def recipient_info(self, cert, session_key): public_key = cert.get_pubkey().to_cryptography_key() encrypted_key = public_key.encrypt(session_key, padding.PKCS1v15()) cert = signer.cert2asn(cert.to_cryptography()) tbs_cert = cert['tbs_certificate'] # TODO: use subject_key_identifier when available return cms.RecipientInfo(name=u'ktri', value={ 'version': u'v0', 'rid': cms.RecipientIdentifier( name=u'issuer_and_serial_number', value={ 'issuer': tbs_cert['issuer'], 'serial_number': tbs_cert['serial_number'] }), 'key_encryption_algorithm': { 'algorithm': u'rsa', }, 'encrypted_key': core.OctetString(encrypted_key) })
def recipient_info(self, cert, session_key, oaep): public_key = cert.public_key() cert = signer.cert2asn(cert) tbs_cert = cert['tbs_certificate'] # TODO: use subject_key_identifier when available if oaep: encrypted_key = public_key.encrypt( session_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA512()), algorithm=hashes.SHA512(), label=None)) kea = cms.KeyEncryptionAlgorithm({ 'algorithm': cms.KeyEncryptionAlgorithmId('rsaes_oaep'), 'parameters': algos.RSAESOAEPParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'p_source_algorithm': algos.PSourceAlgorithm({ 'algorithm': algos.PSourceAlgorithmId('p_specified'), 'parameters': b'', }) }) }) else: kea = {'algorithm': 'rsa'} encrypted_key = public_key.encrypt(session_key, padding.PKCS1v15()) result = cms.RecipientInfo(name='ktri', value={ 'version': 'v0', 'rid': cms.RecipientIdentifier( name='issuer_and_serial_number', value={ 'issuer': tbs_cert['issuer'], 'serial_number': tbs_cert['serial_number'] }), 'key_encryption_algorithm': kea, 'encrypted_key': core.OctetString(encrypted_key) }) return result
def compare_primitive_info(): return ( (core.ObjectIdentifier('1.2.3'), core.ObjectIdentifier('1.2.3'), True), (core.Integer(1), Enum(1), False), (core.Integer(1), core.Integer(1, implicit=5), True), (core.Integer(1), core.Integer(1, explicit=5), True), (core.Integer(1), core.Integer(2), False), (core.OctetString(b''), core.OctetString(b''), True), (core.OctetString(b''), core.OctetString(b'1'), False), (core.OctetString(b''), core.OctetBitString(b''), False), (core.ParsableOctetString(b'12'), core.OctetString(b'12'), True), (core.ParsableOctetBitString(b'12'), core.OctetBitString(b'12'), True), (core.UTF8String('12'), core.UTF8String('12'), True), (core.UTF8String('12'), core.UTF8String('1'), False), (core.UTF8String('12'), core.IA5String('12'), False), )
def return_ocsp_request_object(cert, issuer, algo, nonce=True): cert_details = ocsp.CertId({ 'issuer_name_hash': getattr(cert.issuer, algo), 'issuer_key_hash': getattr(issuer.public_key, algo), 'hash_algorithm': algos.DigestAlgorithm({'algorithm': algo}), 'serial_number': cert.serial_number, }) request_obj = ocsp.Request({ 'req_cert': cert_details, }) tbs_request_obj = ocsp.TBSRequest( {'request_list': ocsp.Requests([request_obj])}) if nonce: nonce_extension = ocsp.TBSRequestExtension({ 'extn_id': 'nonce', 'critical': True, 'extn_value': core.OctetString(os.urandom(16)), }) tbs_request_obj['request_extensions']: ocsp.TBSRequestExtensions( [nonce_extension]) ocsp_request_obj = ocsp.OCSPRequest({ 'tbs_request': tbs_request_obj, }) return ocsp_request_obj
assert status.intact assert 'CONTENT_TIMESTAMP_TOKEN<INVALID>' in status.summary() assert 'TIMESTAMP_TOKEN<INTACT:UNTRUSTED>' in status.summary() @freeze_time('2020-11-01') @pytest.mark.parametrize('content,detach', [ (b'This is not a TST!', True), (b'This is not a TST!', False), (cms.ContentInfo({ 'content_type': 'data', 'content': b'This is not a TST!' }), False), (cms.EncapsulatedContentInfo({ 'content_type': '2.999', 'content': core.ParsableOctetString( core.OctetString(b'This is not a TST!').dump() ) }), False), (cms.ContentInfo({'content_type': '2.999',}), True), ]) async def test_detached_with_malformed_content_tst(content, detach): class CustomProvider(CMSAttributeProvider): attribute_type = 'content_time_stamp' async def build_attr_value(self, dry_run=False): attr_value = await FROM_CA.async_sign_general_data( content, 'sha256', detached=detach, ) return attr_value
def sign_message(data_to_sign, digest_alg, sign_key, use_signed_attributes=True): """Function signs the data and returns the generated ASN.1 :param data_to_sign: A byte string of the data to be signed. :param digest_alg: The digest algorithm to be used for generating the signature. :param sign_key: The key to be used for generating the signature. :param use_signed_attributes: Optional attribute to indicate weather the CMS signature attributes should be included in the signature or not. :return: A CMS ASN.1 byte string of the signed data. """ if use_signed_attributes: digest_func = hashlib.new(digest_alg) digest_func.update(data_to_sign) message_digest = digest_func.digest() class SmimeCapability(core.Sequence): _fields = [('0', core.Any, { 'optional': True }), ('1', core.Any, { 'optional': True }), ('2', core.Any, { 'optional': True }), ('3', core.Any, { 'optional': True }), ('4', core.Any, { 'optional': True })] class SmimeCapabilities(core.Sequence): _fields = [ ('0', SmimeCapability), ('1', SmimeCapability, { 'optional': True }), ('2', SmimeCapability, { 'optional': True }), ('3', SmimeCapability, { 'optional': True }), ('4', SmimeCapability, { 'optional': True }), ('5', SmimeCapability, { 'optional': True }), ] smime_cap = OrderedDict([ ('0', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.7')) ])), ('1', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.2')), ('1', core.Integer(128))])), ('2', OrderedDict([('0', core.ObjectIdentifier('1.2.840.113549.3.4')), ('1', core.Integer(128))])), ]) signed_attributes = cms.CMSAttributes([ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': cms.SetOfContentType([cms.ContentType('data')]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': cms.SetOfTime( [cms.Time({'utc_time': core.UTCTime(datetime.now())})]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': cms.SetOfOctetString([core.OctetString(message_digest)]) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.15'), 'values': cms.SetOfAny([core.Any(SmimeCapabilities(smime_cap))]) }), ]) signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], signed_attributes.dump(), digest_alg) else: signed_attributes = None signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], data_to_sign, digest_alg) return cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData({ 'version': cms.CMSVersion('v1'), 'digest_algorithms': cms.DigestAlgorithms([ algos.DigestAlgorithm( {'algorithm': algos.DigestAlgorithmId(digest_alg)}) ]), 'encap_content_info': cms.ContentInfo({'content_type': cms.ContentType('data')}), 'certificates': cms.CertificateSet( [cms.CertificateChoices({'certificate': sign_key[1].asn1})]), 'signer_infos': cms.SignerInfos([ cms.SignerInfo({ 'version': cms.CMSVersion('v1'), 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': sign_key[1].asn1['tbs_certificate']['issuer'], 'serial_number': sign_key[1].asn1['tbs_certificate'] ['serial_number'] }) }), 'digest_algorithm': algos.DigestAlgorithm( {'algorithm': algos.DigestAlgorithmId(digest_alg)}), 'signed_attrs': signed_attributes, 'signature_algorithm': algos.SignedDigestAlgorithm({ 'algorithm': algos.SignedDigestAlgorithmId('rsassa_pkcs1v15') }), 'signature': core.OctetString(signature) }) ]) }) }).dump()
def sign_message( data_to_sign, digest_alg, sign_key, sign_alg="rsassa_pkcs1v15", use_signed_attributes=True, ): """Function signs the data and returns the generated ASN.1 :param data_to_sign: A byte string of the data to be signed. :param digest_alg: The digest algorithm to be used for generating the signature. :param sign_key: The key to be used for generating the signature. :param sign_alg: The algorithm to be used for signing the message. :param use_signed_attributes: Optional attribute to indicate weather the CMS signature attributes should be included in the signature or not. :return: A CMS ASN.1 byte string of the signed data. """ if use_signed_attributes: digest_func = hashlib.new(digest_alg) digest_func.update(data_to_sign) message_digest = digest_func.digest() class SmimeCapability(core.Sequence): _fields = [ ("0", core.Any, { "optional": True }), ("1", core.Any, { "optional": True }), ("2", core.Any, { "optional": True }), ("3", core.Any, { "optional": True }), ("4", core.Any, { "optional": True }), ] class SmimeCapabilities(core.Sequence): _fields = [ ("0", SmimeCapability), ("1", SmimeCapability, { "optional": True }), ("2", SmimeCapability, { "optional": True }), ("3", SmimeCapability, { "optional": True }), ("4", SmimeCapability, { "optional": True }), ("5", SmimeCapability, { "optional": True }), ] smime_cap = OrderedDict([ ( "0", OrderedDict([ ("0", core.ObjectIdentifier("2.16.840.1.101.3.4.1.42")) ]), ), ( "1", OrderedDict([ ("0", core.ObjectIdentifier("2.16.840.1.101.3.4.1.2")) ]), ), ( "2", OrderedDict([("0", core.ObjectIdentifier("1.2.840.113549.3.7")) ]), ), ( "3", OrderedDict([ ("0", core.ObjectIdentifier("1.2.840.113549.3.2")), ("1", core.Integer(128)), ]), ), ( "4", OrderedDict([ ("0", core.ObjectIdentifier("1.2.840.113549.3.4")), ("1", core.Integer(128)), ]), ), ]) signed_attributes = cms.CMSAttributes([ cms.CMSAttribute({ "type": cms.CMSAttributeType("content_type"), "values": cms.SetOfContentType([cms.ContentType("data")]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("signing_time"), "values": cms.SetOfTime([ cms.Time({ "utc_time": core.UTCTime( datetime.utcnow().replace(tzinfo=timezone.utc)) }) ]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("message_digest"), "values": cms.SetOfOctetString([core.OctetString(message_digest)]), }), cms.CMSAttribute({ "type": cms.CMSAttributeType("1.2.840.113549.1.9.15"), "values": cms.SetOfAny([core.Any(SmimeCapabilities(smime_cap))]), }), ]) else: signed_attributes = None # Generate the signature data_to_sign = signed_attributes.dump( ) if signed_attributes else data_to_sign if sign_alg == "rsassa_pkcs1v15": signature = asymmetric.rsa_pkcs1v15_sign(sign_key[0], data_to_sign, digest_alg) elif sign_alg == "rsassa_pss": signature = asymmetric.rsa_pss_sign(sign_key[0], data_to_sign, digest_alg) else: raise AS2Exception("Unsupported Signature Algorithm") return cms.ContentInfo({ "content_type": cms.ContentType("signed_data"), "content": cms.SignedData({ "version": cms.CMSVersion("v1"), "digest_algorithms": cms.DigestAlgorithms([ algos.DigestAlgorithm( {"algorithm": algos.DigestAlgorithmId(digest_alg)}) ]), "encap_content_info": cms.ContentInfo({"content_type": cms.ContentType("data")}), "certificates": cms.CertificateSet( [cms.CertificateChoices({"certificate": sign_key[1].asn1})]), "signer_infos": cms.SignerInfos([ cms.SignerInfo({ "version": cms.CMSVersion("v1"), "sid": cms.SignerIdentifier({ "issuer_and_serial_number": cms.IssuerAndSerialNumber({ "issuer": sign_key[1].asn1["tbs_certificate"]["issuer"], "serial_number": sign_key[1].asn1["tbs_certificate"] ["serial_number"], }) }), "digest_algorithm": algos.DigestAlgorithm( {"algorithm": algos.DigestAlgorithmId(digest_alg)}), "signed_attrs": signed_attributes, "signature_algorithm": algos.SignedDigestAlgorithm( {"algorithm": algos.SignedDigestAlgorithmId(sign_alg)}), "signature": core.OctetString(signature), }) ]), }), }).dump()
def fetch(cert, issuer, hash_algo='sha1', nonce=True, user_agent=None, timeout=10): """ Fetches an OCSP response for a certificate :param cert: An asn1cyrpto.x509.Certificate object to get an OCSP reponse for :param issuer: An asn1crypto.x509.Certificate object that is the issuer of cert :param hash_algo: A unicode string of "sha1" or "sha256" :param nonce: A boolean - if the nonce extension should be used to prevent replay attacks :param user_agent: The HTTP user agent to use when requesting the OCSP response. If None, a default is used in the format "certvalidation 1.0.0". :param timeout: The number of seconds after which an HTTP request should timeout :raises: urllib.error.URLError/urllib2.URLError - when a URL/HTTP error occurs socket.error - when a socket error occurs :return: An asn1crypto.ocsp.OCSPResponse object """ if not isinstance(cert, x509.Certificate): raise TypeError( 'cert must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(cert)) if not isinstance(issuer, x509.Certificate): raise TypeError( 'issuer must be an instance of asn1crypto.x509.Certificate, not %s' % type_name(issuer)) if hash_algo not in set(['sha1', 'sha256']): raise ValueError('hash_algo must be one of "sha1", "sha256", not %s' % repr(hash_algo)) if not isinstance(nonce, bool): raise TypeError('nonce must be a bool, not %s' % type_name(nonce)) if user_agent is None: user_agent = 'certvalidator %s' % __version__ elif not isinstance(user_agent, str_cls): raise TypeError('user_agent must be a unicode string, not %s' % type_name(user_agent)) cert_id = ocsp.CertId({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': hash_algo}), 'issuer_name_hash': getattr(cert.issuer, hash_algo), 'issuer_key_hash': getattr(issuer.public_key, hash_algo), 'serial_number': cert.serial_number, }) request = ocsp.Request({ 'req_cert': cert_id, }) tbs_request = ocsp.TBSRequest({ 'request_list': ocsp.Requests([request]), }) if nonce: nonce_extension = ocsp.TBSRequestExtension({ 'extn_id': 'nonce', 'critical': False, 'extn_value': core.OctetString(core.OctetString(os.urandom(16)).dump()) }) tbs_request['request_extensions'] = ocsp.TBSRequestExtensions( [nonce_extension]) ocsp_request = ocsp.OCSPRequest({ 'tbs_request': tbs_request, }) last_e = None for ocsp_url in cert.ocsp_urls: try: request = Request(ocsp_url) request.add_header('Accept', 'application/ocsp-response') request.add_header('Content-Type', 'application/ocsp-request') request.add_header('User-Agent', user_agent) response = urlopen(request, ocsp_request.dump(), timeout) ocsp_response = ocsp.OCSPResponse.load(response.read()) request_nonce = ocsp_request.nonce_value if ocsp_response['response_status'].native == 'unauthorized': raise errors.OCSPNoMatchesError( 'Unable to verify OCSP response since the responder returned unauthorized' ) response_nonce = ocsp_response.nonce_value if request_nonce and response_nonce and request_nonce.native != response_nonce.native: raise errors.OCSPValidationError( 'Unable to verify OCSP response since the request and response nonces do not match' ) return ocsp_response except (URLError) as e: last_e = e raise last_e