def optimal_pss_params(cert: x509.Certificate, digest_algorithm: str): digest_algorithm = digest_algorithm.lower() try: from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey except ImportError: # pragma: nocover raise SigningError("pyca/cryptography is required for generic PSS") key: RSAPublicKey = serialization.load_der_public_key( cert.public_key.dump()) md = getattr(hashes, digest_algorithm.upper()) # the PSS salt calculation function is not in the .pyi file, apparently. # noinspection PyUnresolvedReferences optimal_salt_len = padding.calculate_max_pss_salt_length(key, md()) return algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': digest_algorithm}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': algos.DigestAlgorithm({'algorithm': digest_algorithm}), }), 'salt_length': optimal_salt_len })
def optimal_pss_params(self, key: keys.PublicKeyInfo, digest_algo: str) -> algos.RSASSAPSSParams: from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import serialization, hashes digest_algo = digest_algo.lower() if key.algorithm == 'rsassa_pss': # again, pretend that we're working with a normal RSA key key = key.copy() key['algorithm'] = {'algorithm': 'rsa'} loaded_key: rsa.RSAPublicKey \ = serialization.load_der_public_key(key.dump()) md = getattr(hashes, digest_algo.upper()) # the PSS salt calculation function is not in the .pyi file, apparently. # noinspection PyUnresolvedReferences optimal_salt_len = padding.calculate_max_pss_salt_length( loaded_key, md()) return algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': digest_algo}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': algos.DigestAlgorithm({'algorithm': digest_algo}), }), 'salt_length': optimal_salt_len })
def optimal_pss_params(cert: x509.Certificate, digest_algorithm: str) \ -> algos.RSASSAPSSParams: """ Figure out the optimal RSASSA-PSS parameters for a given certificate. The subject's public key must be an RSA key. :param cert: An RSA X.509 certificate. :param digest_algorithm: The digest algorithm to use. :return: RSASSA-PSS parameters. """ digest_algorithm = digest_algorithm.lower() key: RSAPublicKey = serialization.load_der_public_key( cert.public_key.dump()) md = get_pyca_cryptography_hash(digest_algorithm) # the PSS salt calculation function is not in the .pyi file, apparently. # noinspection PyUnresolvedReferences optimal_salt_len = padding.calculate_max_pss_salt_length(key, md) return algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': digest_algorithm}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': algos.DigestAlgorithm({'algorithm': digest_algorithm}), }), 'salt_length': optimal_salt_len })
def sign_authpack_native(data, privkey, certificate, wrap_signed=False): """ Creating PKCS7 blob which contains the following things: 1. 'data' blob which is an ASN1 encoded "AuthPack" structure 2. the certificate used to sign the data blob 3. the singed 'signed_attrs' structure (ASN1) which points to the "data" structure (in point 1) """ da = {'algorithm': algos.DigestAlgorithmId('1.3.14.3.2.26')} si = {} si['version'] = 'v1' si['sid'] = cms.IssuerAndSerialNumber({ 'issuer': certificate.issuer, 'serial_number': certificate.serial_number, }) si['digest_algorithm'] = algos.DigestAlgorithm(da) si['signed_attrs'] = [ cms.CMSAttribute({ 'type': 'content_type', 'values': ['1.3.6.1.5.2.3.1'] }), # indicates that the encap_content_info's authdata struct (marked with OID '1.3.6.1.5.2.3.1' is signed ) cms.CMSAttribute({ 'type': 'message_digest', 'values': [hashlib.sha1(data).digest()] }), ### hash of the data, the data itself will not be signed, but this block of data will be. ] si['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': '1.2.840.113549.1.1.1'}) si['signature'] = rsa_pkcs1v15_sign( privkey, cms.CMSAttributes(si['signed_attrs']).dump(), "sha1") ec = {} ec['content_type'] = '1.3.6.1.5.2.3.1' ec['content'] = data sd = {} sd['version'] = 'v3' sd['digest_algorithms'] = [algos.DigestAlgorithm(da)] # must have only one sd['encap_content_info'] = cms.EncapsulatedContentInfo(ec) sd['certificates'] = [certificate] sd['signer_infos'] = cms.SignerInfos([cms.SignerInfo(si)]) if wrap_signed is True: ci = {} ci['content_type'] = '1.2.840.113549.1.7.2' # signed data OID ci['content'] = cms.SignedData(sd) return cms.ContentInfo(ci).dump() return cms.SignedData(sd).dump()
def request_cms(self, message_digest, md_algorithm): """ Format the body of an :rfc:`3161` request as a CMS object. Subclasses with more specific needs may want to override this. :param message_digest: Message digest to which the timestamp will apply. :param md_algorithm: Message digest algorithm to use. .. note:: As per :rfc:`8933`, ``md_algorithm`` should also be the algorithm used to compute ``message_digest``. :return: An :class:`.asn1crypto.tsp.TimeStampReq` object. """ nonce = get_nonce() req = tsp.TimeStampReq({ 'version': 1, 'message_imprint': tsp.MessageImprint({ 'hash_algorithm': algos.DigestAlgorithm({ 'algorithm': md_algorithm }), 'hashed_message': message_digest }), 'nonce': cms.Integer(nonce), # we want the server to send along its certs 'cert_req': True }) return nonce, req
def main(): p12 = load_pkcs12(open('demo2_user1.p12', 'rb').read(), '1234') datau = open('smime-unsigned.txt', 'rb').read() datau1 = datau.replace(b'\n', b'\r\n') hashalgo = 'sha256' signed_value = getattr(hashlib, hashalgo)(datau1).digest() attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.16.2.47'), 'values': (algos.DigestAlgorithm({'algorithm': hashalgo}), ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), ] datas = email.sign(datau, p12.get_privatekey().to_cryptography_key(), p12.get_certificate().to_cryptography(), [], 'sha256', attrs=attrs) open('smime-signed-attr-custom.txt', 'wb').write(datas)
def _generate_signed_attrs(self, eta_invoice, signing_time): cert = x509.Certificate.load(base64.b64decode(self.certificate)) data = hashlib.sha256(self._serialize_for_signing(eta_invoice).encode()).digest() return cms.CMSAttributes([ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('digested_data',), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (data,), }), cms.CMSAttribute({ 'type': tsp.CMSAttributeType('signing_certificate_v2'), 'values': ({ 'certs': (tsp.ESSCertIDv2({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha256'}), 'cert_hash': hashlib.sha256(cert.dump()).digest() }),) },), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': ( cms.Time({'utc_time': core.UTCTime(signing_time.replace(tzinfo=pytz.UTC))}),) }), ])
def test_timestamp(requests_mock, setup): setup.illusionist.register(requests_mock) hashed_bytes = hashlib.sha256(b'test').digest() req = tsp.TimeStampReq({ 'version': 'v2', 'message_imprint': tsp.MessageImprint({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha256'}), 'hashed_message': hashed_bytes }), 'nonce': core.Integer(0x1337), 'cert_req': True }) response = requests.post("http://test.test/testing-ca/tsa/tsa", data=req.dump()) resp: tsp.TimeStampResp = tsp.TimeStampResp.load(response.content) sd = resp['time_stamp_token']['content'] tst_info: tsp.TSTInfo = sd['encap_content_info']['content'].parsed assert tst_info['nonce'].native == 0x1337 assert tst_info['gen_time'].native \ == datetime.now().replace(tzinfo=pytz.utc)
async def build_attr_value(self, dry_run=False) \ -> cms.CMSAlgorithmProtection: return cms.CMSAlgorithmProtection({ 'digest_algorithm': algos.DigestAlgorithm({'algorithm': self.digest_algo}), 'signature_algorithm': self.signature_algo })
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 optimal_pss_params(cert: x509.Certificate, digest_algorithm: str): digest_algorithm = digest_algorithm.lower() key: RSAPublicKey = serialization.load_der_public_key( cert.public_key.dump()) md = get_pyca_cryptography_hash(digest_algorithm) # the PSS salt calculation function is not in the .pyi file, apparently. # noinspection PyUnresolvedReferences optimal_salt_len = padding.calculate_max_pss_salt_length(key, md) return algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': digest_algorithm}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': algos.DigestAlgorithm({'algorithm': digest_algorithm}), }), 'salt_length': optimal_salt_len })
def optimal_pss_params(self, key: PublicKeyInfo, digest_algo: str): key_algo = key.algorithm if key_algo == 'rsassa_pss': logger.warning( "You seem to be using an RSA key that has been marked as " "RSASSA-PSS exclusive. If it has non-null parameters, these " "WILL be disregarded by the signer, since oscrypto doesn't " "currently support RSASSA-PSS with arbitrary parameters.") # replicate default oscrypto PSS settings salt_len = len(getattr(hashlib, digest_algo)().digest()) return algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': digest_algo}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': algos.DigestAlgorithm({'algorithm': digest_algo}) }), 'salt_length': salt_len })
def _generate_cades_bes_signature(self, eta_invoice, signing_time, signature): cert = x509.Certificate.load(base64.b64decode(self.certificate)) signed_data = { 'version': 'v3', 'digest_algorithms': cms.DigestAlgorithms(( algos.DigestAlgorithm({'algorithm': 'sha256'}), )), 'encap_content_info': { 'content_type': 'digested_data', }, 'certificates': [cert], 'signer_infos': [ self._generate_signer_info(eta_invoice, signing_time, signature), ], } return cms.ContentInfo({'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(signed_data),})
def test_email_signed_attr_custom(self): p12 = crypto.load_pkcs12( open(fixture('demo2_user1.p12'), 'rb').read(), '1234') datau = open(fixture('smime-unsigned.txt'), 'rb').read() datau1 = datau.replace(b'\n', b'\r\n') hashalgo = 'sha256' signed_value = getattr(hashlib, hashalgo)(datau1).digest() attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.16.2.47'), 'values': (algos.DigestAlgorithm({'algorithm': hashalgo}), ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), ] datas = email.sign(datau, p12.get_privatekey().to_cryptography_key(), p12.get_certificate().to_cryptography(), [], 'sha256', attrs=attrs) fname = fixture('smime-signed-attr-custom.txt') open(fname, 'wb').write(datas) cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('demo2_ca.crt.pem'), '-in', fname, '-inform', 'SMIME', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau.replace(b'\n', b'\r\n') == stdout
def _generate_signer_info(self, eta_invoice, signing_time, signature=False): cert = x509.Certificate.load(base64.b64decode(self.certificate)) signer_info = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': 'sha256'}), 'signature_algorithm': algos.SignedDigestAlgorithm({ 'algorithm': 'sha256_rsa' }), 'signed_attrs': self._generate_signed_attrs(eta_invoice, signing_time) } if signature: signer_info['signature'] = signature return signer_info
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
def sign(datau, session, cert, cert_value, hashalgo, attrs=True, signed_value=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now() x509 = Certificate.load(cert_value) certificates = [] certificates.append(x509) cert_value_digest = bytes( session.digest(cert_value, Mechanism(LowLevel.CKM_SHA256))) MyLogger().my_logger().info('building signed attributes...') signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': x509.issuer, 'serial_number': x509.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}), 'signature': signed_value, } if attrs: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data', ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}), ) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.16.2.47'), 'values': (tsp.SigningCertificateV2({ 'certs': (tsp.ESSCertIDv2({ 'hash_algorithm': algos.DigestAlgorithm({ 'algorithm': hashalgo, 'parameters': None }), 'cert_hash': cert_value_digest, }), ), }), ) }), ] config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms((algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau MyLogger().my_logger().info('signed attributes ready') # fetching private key from smart card priv_key = SignatureUtils.fetch_private_key(session, cert) mechanism = Mechanism(LowLevel.CKM_SHA256_RSA_PKCS, None) MyLogger().my_logger().info('signing...') # signing bytes to be signed signature = session.sign(priv_key, tosign, mechanism) datas['content']['signer_infos'][0]['signature'] = bytes(signature) return datas.dump()
def on_get(self, req, resp): operation = req.get_param("operation", required=True) if operation.lower() == "getcacert": resp.body = keys.parse_certificate( self.authority.certificate_buf).dump() resp.append_header("Content-Type", "application/x-x509-ca-cert") return # If we bump into exceptions later encrypted_container = b"" attr_list = [ cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["2"] # rejected }) ] try: info = cms.ContentInfo.load( b64decode(req.get_param("message", required=True))) ############################################### ### Verify signature of the outer container ### ############################################### signed_envelope = info['content'] encap_content_info = signed_envelope['encap_content_info'] encap_content = encap_content_info['content'] # TODO: try except current_certificate, = signed_envelope["certificates"] signer, = signed_envelope["signer_infos"] # TODO: compare cert to current one if we are renewing assert signer["digest_algorithm"]["algorithm"].native == "md5" assert signer["signature_algorithm"][ "algorithm"].native == "rsassa_pkcs1v15" message_digest = None transaction_id = None sender_nonce = None for attr in signer["signed_attrs"]: if attr["type"].native == "sender_nonce": sender_nonce, = attr["values"] elif attr["type"].native == "trans_id": transaction_id, = attr["values"] elif attr["type"].native == "message_digest": message_digest, = attr["values"] if hashlib.md5(encap_content.native).digest( ) != message_digest.native: raise SCEPBadMessageCheck() assert message_digest msg = signer["signed_attrs"].dump(force=True) assert msg[0] == 160 # Verify signature try: asymmetric.rsa_pkcs1v15_verify( asymmetric.load_certificate(current_certificate.dump()), signer["signature"].native, b"\x31" + msg[1:], # wtf?! "md5") except SignatureError: raise SCEPBadMessageCheck() ############################### ### Decrypt inner container ### ############################### info = cms.ContentInfo.load(encap_content.native) encrypted_envelope = info['content'] encrypted_content_info = encrypted_envelope[ 'encrypted_content_info'] iv = encrypted_content_info['content_encryption_algorithm'][ 'parameters'].native if encrypted_content_info['content_encryption_algorithm'][ "algorithm"].native != "des": raise SCEPBadAlgo() encrypted_content = encrypted_content_info[ 'encrypted_content'].native recipient, = encrypted_envelope['recipient_infos'] if recipient.native["rid"][ "serial_number"] != self.authority.certificate.serial_number: raise SCEPBadCertId() # Since CA private key is not directly readable here, we'll redirect it to signer socket key = asymmetric.rsa_pkcs1v15_decrypt( self.authority.private_key, recipient.native["encrypted_key"]) if len(key) == 8: key = key * 3 # Convert DES to 3DES buf = symmetric.tripledes_cbc_pkcs5_decrypt( key, encrypted_content, iv) _, _, common_name = self.authority.store_request(buf, overwrite=True) cert, buf = self.authority.sign(common_name, overwrite=True) signed_certificate = asymmetric.load_certificate(buf) content = signed_certificate.asn1.dump() except SCEPError as e: attr_list.append( cms.CMSAttribute({ 'type': "fail_info", 'values': ["%d" % e.code] })) else: ################################## ### Degenerate inner container ### ################################## degenerate = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [signed_certificate.asn1], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': "md5"})], 'encap_content_info': { 'content_type': "data", 'content': cms.ContentInfo({ 'content_type': "signed_data", 'content': None }).dump() }, 'signer_infos': [] }) }) ################################ ### Encrypt middle container ### ################################ key = os.urandom(8) iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt( key, degenerate.dump(), os.urandom(8)) assert degenerate.dump() == symmetric.tripledes_cbc_pkcs5_decrypt( key * 3, encrypted_content, iv) ri = cms.RecipientInfo({ 'ktri': cms.KeyTransRecipientInfo({ 'version': "v0", 'rid': cms.RecipientIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': current_certificate.chosen["tbs_certificate"] ["issuer"], 'serial_number': current_certificate.chosen["tbs_certificate"] ["serial_number"], }), }), 'key_encryption_algorithm': { 'algorithm': "rsa" }, 'encrypted_key': asymmetric.rsa_pkcs1v15_encrypt( asymmetric.load_certificate( current_certificate.chosen.dump()), key) }) }) encrypted_container = cms.ContentInfo({ 'content_type': "enveloped_data", 'content': cms.EnvelopedData({ 'version': "v1", 'recipient_infos': [ri], 'encrypted_content_info': { 'content_type': "data", 'content_encryption_algorithm': { 'algorithm': "des", 'parameters': iv }, 'encrypted_content': encrypted_content } }) }).dump() attr_list = [ cms.CMSAttribute({ 'type': "message_digest", 'values': [hashlib.sha1(encrypted_container).digest()] }), cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["0"] # ok }) ] finally: ############################## ### Signed outer container ### ############################## attrs = cms.CMSAttributes(attr_list + [ cms.CMSAttribute({ 'type': "recipient_nonce", 'values': [sender_nonce] }), cms.CMSAttribute({ 'type': "trans_id", 'values': [transaction_id] }) ]) signer = cms.SignerInfo({ "signed_attrs": attrs, 'version': "v1", 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': self.authority.certificate.issuer, 'serial_number': self.authority.certificate.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': "sha1"}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}), 'signature': asymmetric.rsa_pkcs1v15_sign(self.authority.private_key, b"\x31" + attrs.dump()[1:], "sha1") }) resp.append_header("Content-Type", "application/x-pki-message") resp.body = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [self.authority.certificate], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': "sha1"})], 'encap_content_info': { 'content_type': "data", 'content': encrypted_container }, 'signer_infos': [signer] }) }).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
def sign(datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None, timestampcredentials=None, timestamp_req_options=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=util.timezone.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) else: cert = cert2asn(cert) certificates = [] certificates.append(cert) for i in range(len(othercerts)): certificates.append(cert2asn(othercerts[i])) hashalgo = unicode(hashalgo) if sys.version[0] < '3' else hashalgo signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature': signed_value, } if not pss: signer['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'}) else: if isinstance(key, keys.PrivateKeyInfo): salt_length = key.byte_size - hashes.SHA512.digest_size - 2 salt_length = hashes.SHA512.digest_size else: salt_length = padding.calculate_max_pss_salt_length( key, hashes.SHA512) signer['signature_algorithm'] = algos.SignedDigestAlgorithm({ 'algorithm': 'rsassa_pss', 'parameters': algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'salt_length': algos.Integer(salt_length), 'trailer_field': algos.TrailerField(1) }) }) if attrs: if attrs is True: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data', ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}), ) }), ] else: signer['signed_attrs'] = attrs config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms((algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) elif isinstance(key, keys.PrivateKeyInfo): key = asymmetric.load_private_key(key) if pss: signed_value_signature = asymmetric.rsa_pss_sign( key, tosign, 'sha512') else: signed_value_signature = asymmetric.rsa_pkcs1v15_sign( key, tosign, hashalgo.lower()) else: if pss: hasher = hashes.Hash(hashes.SHA512(), backend=backends.default_backend()) hasher.update(tosign) digest = hasher.finalize() signed_value_signature = key.sign( digest, padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=salt_length), utils.Prehashed(hashes.SHA512())) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())()) if timestampurl is not None: datas['content']['signer_infos'][0]['unsigned_attrs'] = timestamp( signed_value_signature, hashalgo, timestampurl, timestampcredentials, timestamp_req_options, ) # signed_value_signature = core.OctetString(signed_value_signature) datas['content']['signer_infos'][0]['signature'] = signed_value_signature #open('signed-content-info', 'wb').write(datas.dump()) return datas.dump()
def timestamp(unhashed, hashalgo, url, credentials, req_options, prehashed=None): if prehashed: hashed_value = prehashed else: hashed_value = getattr(hashlib, hashalgo)(unhashed).digest() tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({'algorithm': hashalgo}), "hashed_message": hashed_value, }), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time() * 1000), "cert_req": True, #'extensions': tsp.Extensions() }) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} if credentials is not None: username = credentials.get("username", None) password = credentials.get("password", None) if username and password: auth_header_value = b64encode( bytes(username + ':' + password, "utf-8")).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" if req_options is None: req_options = {} tspresp = requests.post(url, data=tspreq, headers=tspheaders, **req_options) if tspresp.headers.get('Content-Type', None) == 'application/timestamp-reply': tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp['status']['status'].native == 'granted': attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tspresp["time_stamp_token"]["content"], }) ]) }) ] return attrs else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type")
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(datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None, timestampcredentials=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=util.timezone.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) else: cert = cert2asn(cert) certificates = [] certificates.append(cert) for i in range(len(othercerts)): certificates.append(cert2asn(othercerts[i])) hashalgo = unicode(hashalgo) if sys.version[0] < '3' else hashalgo signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature': signed_value, } if not pss: signer['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'}) else: if isinstance(key, keys.PrivateKeyInfo): salt_length = key.byte_size - hashes.SHA512.digest_size - 2 salt_length = hashes.SHA512.digest_size else: salt_length = padding.calculate_max_pss_salt_length( key, hashes.SHA512) signer['signature_algorithm'] = algos.SignedDigestAlgorithm({ 'algorithm': 'rsassa_pss', 'parameters': algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'salt_length': algos.Integer(salt_length), 'trailer_field': algos.TrailerField(1) }) }) if attrs: if attrs is True: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data', ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}), ) }), ] else: signer['signed_attrs'] = attrs config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms((algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) elif isinstance(key, keys.PrivateKeyInfo): key = asymmetric.load_private_key(key) if pss: signed_value_signature = asymmetric.rsa_pss_sign( key, tosign, 'sha512') else: signed_value_signature = asymmetric.rsa_pkcs1v15_sign( key, tosign, hashalgo.lower()) else: if pss: hasher = hashes.Hash(hashes.SHA512(), backend=backends.default_backend()) hasher.update(tosign) digest = hasher.finalize() signed_value_signature = key.sign( digest, padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=salt_length), utils.Prehashed(hashes.SHA512())) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())()) if timestampurl is not None: signed_value = getattr(hashlib, hashalgo)(signed_value_signature).digest() tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({'algorithm': hashalgo}), "hashed_message": signed_value, }), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time() * 1000), "cert_req": True, #'extensions': tsp.Extensions() }) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} if timestampcredentials is not None: username = timestampcredentials.get("username", None) password = timestampcredentials.get("password", None) if username and password: auth_header_value = b64encode( bytes(username + ':' + password, "utf-8")).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" tspresp = requests.post(timestampurl, data=tspreq, headers=tspheaders) if tspresp.headers.get('Content-Type', None) == 'application/timestamp-reply': tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp['status']['status'].native == 'granted': attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tspresp["time_stamp_token"]["content"], }) ]) }) ] datas['content']['signer_infos'][0]['unsigned_attrs'] = attrs else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type") # signed_value_signature = core.OctetString(signed_value_signature) datas['content']['signer_infos'][0]['signature'] = signed_value_signature #open('signed-content-info', 'wb').write(datas.dump()) return datas.dump()
def request_tsa_response(self, req: tsp.TimeStampReq) -> tsp.TimeStampResp: # We pretend that certReq is always true in the request status = tsp.PKIStatusInfo({'status': tsp.PKIStatus('granted')}) message_imprint: tsp.MessageImprint = req['message_imprint'] md_algorithm = self.md_algorithm digest_algorithm_obj = algos.DigestAlgorithm({ 'algorithm': md_algorithm }) dt = self.fixed_dt or datetime.now(tz=tzlocal.get_localzone()) tst_info = { 'version': 'v1', 'policy': self.policy, 'message_imprint': message_imprint, 'serial_number': get_nonce(), 'gen_time': dt, 'tsa': x509.GeneralName( name='directory_name', value=self.tsa_cert.subject ) } try: tst_info['nonce'] = req['nonce'] except KeyError: pass tst_info = tsp.TSTInfo(tst_info) tst_info_data = tst_info.dump() message_digest = getattr(hashlib, md_algorithm)(tst_info_data).digest() signing_cert_id = tsp.ESSCertID({ 'cert_hash': hashlib.sha1(self.tsa_cert.dump()).digest() }) signed_attrs = cms.CMSAttributes([ simple_cms_attribute('content_type', 'tst_info'), simple_cms_attribute( 'signing_time', cms.Time({'utc_time': core.UTCTime(dt)}) ), simple_cms_attribute( 'signing_certificate', tsp.SigningCertificate({'certs': [signing_cert_id]}) ), simple_cms_attribute('message_digest', message_digest), ]) signature = generic_sign( self.tsa_key, signed_attrs.dump(), self.signature_algo ) sig_info = cms.SignerInfo({ 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': self.tsa_cert.issuer, 'serial_number': self.tsa_cert.serial_number, }) }), 'digest_algorithm': digest_algorithm_obj, 'signature_algorithm': self.signature_algo, 'signed_attrs': signed_attrs, 'signature': signature }) certs = set(self.certs_to_embed) certs.add(self.tsa_cert) signed_data = { # must use v3 to get access to the EncapsulatedContentInfo construct 'version': 'v3', 'digest_algorithms': cms.DigestAlgorithms((digest_algorithm_obj,)), 'encap_content_info': cms.EncapsulatedContentInfo({ 'content_type': cms.ContentType('tst_info'), 'content': cms.ParsableOctetString(tst_info_data) }), 'certificates': certs, 'signer_infos': [sig_info] } tst = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(signed_data) }) return tsp.TimeStampResp({'status': status, 'time_stamp_token': tst})
def request_tsa_response(self, req: tsp.TimeStampReq) -> tsp.TimeStampResp: # We pretend that certReq is always true in the request # TODO generalise my detached signature logic to include cases like this # (see § 5.4 in RFC 5652) # TODO does the RFC status = tsp.PKIStatusInfo({'status': tsp.PKIStatus('granted')}) message_imprint: tsp.MessageImprint = req['message_imprint'] md_algorithm = message_imprint['hash_algorithm']['algorithm'].native digest_algorithm_obj = algos.DigestAlgorithm({ 'algorithm': md_algorithm }) dt = self.fixed_dt or datetime.now(tz=tzlocal.get_localzone()) tst_info = { 'version': 'v1', # See http://oidref.com/1.3.6.1.4.1.4146.2.2 # I don't really care too much, this is a testing device anyway 'policy': tsp.ObjectIdentifier('1.3.6.1.4.1.4146.2.2'), 'message_imprint': message_imprint, # should be sufficiently random (again, this is a testing class) 'serial_number': get_nonce(), 'gen_time': dt, 'tsa': x509.GeneralName( name='directory_name', value=self.tsa_cert.subject ) } try: tst_info['nonce'] = req['nonce'] except KeyError: pass tst_info = tsp.TSTInfo(tst_info) tst_info_data = tst_info.dump() message_digest = getattr(hashlib, md_algorithm)(tst_info_data).digest() signed_attrs = cms.CMSAttributes([ simple_cms_attribute('content_type', 'tst_info'), simple_cms_attribute( 'signing_time', cms.Time({'utc_time': core.UTCTime(dt)}) ), simple_cms_attribute( 'signing_certificate', general.as_signing_certificate(self.tsa_cert) ), simple_cms_attribute('message_digest', message_digest), ]) signature = asymmetric.rsa_pkcs1v15_sign( asymmetric.load_private_key(self.tsa_key), signed_attrs.dump(), md_algorithm ) sig_info = cms.SignerInfo({ 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': self.tsa_cert.issuer, 'serial_number': self.tsa_cert.serial_number, }) }), 'digest_algorithm': digest_algorithm_obj, 'signature_algorithm': algos.SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'} ), 'signed_attrs': signed_attrs, 'signature': signature }) certs = set(self.certs_to_embed) certs.add(self.tsa_cert) signed_data = { # must use v3 to get access to the EncapsulatedContentInfo construct 'version': 'v3', 'digest_algorithms': cms.DigestAlgorithms((digest_algorithm_obj,)), 'encap_content_info': cms.EncapsulatedContentInfo({ 'content_type': cms.ContentType('tst_info'), 'content': cms.ParsableOctetString(tst_info_data) }), 'certificates': certs, 'signer_infos': [sig_info] } tst = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(signed_data) }) return tsp.TimeStampResp({'status': status, 'time_stamp_token': tst})
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 sign(datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=pytz.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) othercerts = [] else: cert = cert2asn(cert) certificates = [] certificates.append(cert) for i in range(len(othercerts)): certificates.append(cert2asn(othercerts[i])) hashalgo = unicode(hashalgo) if sys.version[0] < '3' else hashalgo signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}), 'signature': signed_value, } if attrs: if attrs is True: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data',), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value,), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}),) }), ] else: signer['signed_attrs'] = attrs config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms(( algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())() ) # signed_value_signature = core.OctetString(signed_value_signature) datas['content']['signer_infos'][0]['signature'] = signed_value_signature return datas.dump()
def test_digest_parameters(self): sha1 = algos.DigestAlgorithm({'algorithm': 'sha1'}) self.assertEqual(core.Null, sha1['parameters'].__class__)
def unsignedpropertied(self, signed_value, tspurl, tspcred, hashalgo="sha256"): if tspurl is None: unsignedproperties = UnsignedProperties( Id="UnsignedProperties_" + self.guid + self.mapa["_5d"]) else: tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({"algorithm": hashalgo}), "hashed_message": signed_value.encode(), }), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time() * 1000), "cert_req": True, #'extensions': tsp.Extensions() }) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} if tspcred is not None: username = tspcred.get("username", None) password = tspcred.get("password", None) if username and password: auth_header_value = base64.b64encode( bytes(username + ":" + password, "utf-8")).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" tspresp = requests.post(tspurl, data=tspreq, headers=tspheaders) if (tspresp.headers.get("Content-Type", None) == "application/timestamp-reply"): tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp["status"]["status"].native == "granted": attr = self.base64(tspresp["time_stamp_token"].dump()) else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type") unsignedproperties = UnsignedProperties( UnsignedSignatureProperties( SignatureTimeStamp( CanonicalizationMethod( Algorithm= "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"), EncapsulatedTimeStamp( attr, Encoding="http://uri.etsi.org/01903/v1.2.2#DER"), Id="SignatureTimeStamp_" + self.guid, )), Id="UnsignedProperties_" + self.guid + self.mapa["_5d"], ) return unsignedproperties
def _sign(self, datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=util.timezone.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) othercerts = [] else: cert = cert2asn(cert) certificates = [] certificates.append(cert) for i in range(len(othercerts)): certificates.append(cert2asn(othercerts[i])) signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature': signed_value, } if not pss: signer['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'}) else: salt_length = padding.calculate_max_pss_salt_length( key, hashes.SHA512) signer['signature_algorithm'] = algos.SignedDigestAlgorithm({ 'algorithm': 'rsassa_pss', 'parameters': algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'salt_length': algos.Integer(salt_length), 'trailer_field': algos.TrailerField(1) }) }) if attrs: if attrs is True: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data', ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}), ) }), ] else: signer['signed_attrs'] = attrs config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms( (algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) else: if pss: hasher = hashes.Hash(hashes.SHA512(), backend=backends.default_backend()) hasher.update(tosign) digest = hasher.finalize() signed_value_signature = key.sign( digest, padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=salt_length), utils.Prehashed(hashes.SHA512())) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())()) if timestampurl is not None: signed_value = getattr(hashlib, hashalgo)(signed_value_signature).digest() tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({'algorithm': hashalgo}), "hashed_message": signed_value, }), "nonce": int(time.time() * 1000), "cert_req": True, }) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} tspresp = requests.post(timestampurl, data=tspreq, headers=tspheaders) if tspresp.headers.get('Content-Type', None) == 'application/timestamp-reply': tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp['status']['status'].native == 'granted': attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tspresp["time_stamp_token"]["content"], }) ]) }) ] datas['content']['signer_infos'][0][ 'unsigned_attrs'] = attrs # signed_value_signature = core.OctetString(signed_value_signature) datas['content']['signer_infos'][0][ 'signature'] = signed_value_signature return datas.dump()