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(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()
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 _sign(self, datau, key, signing_cert, trustchain, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None, identity=None, s=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.datetime.now(tz=util.timezone.utc) esscert = signing_cert.public_bytes(serialization.Encoding.DER) esscert = getattr(hashlib, hashalgo)(esscert).digest() if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) trustchain = [] else: signing_cert = cert2asn(signing_cert) certificates = [] for c in trustchain: certificates.append(cert2asn(c)) certificates.append(signing_cert) signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': signing_cert.issuer, 'serial_number': signing_cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature': signed_value, } signer['signature_algorithm'] = algos.SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'}) 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_certificate_v2'), 'values': (tsp.SigningCertificateV2({ 'certs': [ tsp.ESSCertIDv2({'cert_hash': esscert}), ] }), ) }) #cms.CMSAttribute({ #'type': cms.CMSAttributeType('signing_time'), #'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}),) #}), ] else: signer['signed_attrs'] = attrs # TODO: Keep it all in one loop ocsp_revocation = [] ocsp_revocation.append( cms.RevocationInfoChoice({ 'other': cms.OtherRevocationInfoFormat({ 'other_rev_info_format': cms.OtherRevInfoFormatId('ocsp_response'), 'other_rev_info': self._ocsp_response }) })) # TODO: Don't need this because I have a DSS now #for rev in self._revocation_info: #rev = base64.b64decode(rev) #rev = ocsp.OCSPResponse.load(rev) #ocsp_revocation.append( #cms.RevocationInfoChoice({ #'other': cms.OtherRevocationInfoFormat({ #'other_rev_info_format': cms.OtherRevInfoFormatId('ocsp_response'), #'other_rev_info': rev #}) #}) #) config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms( (algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, 'crls': ocsp_revocation, '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 tosign = getattr(hashlib, hashalgo)(tosign).digest() # Fetch the actual signature r = s.get( self._signature_url.format(id=identity, digest=tosign.hex().upper())) if r.status_code != 200: raise APIError('Cannot retrieve the signature: {}\n{}'.format( r.status_code, r.json())) signed_value_signature = r.json()['signature'] signed_value_signature = bytes.fromhex(signed_value_signature) signed_value = getattr(hashlib, hashalgo)(signed_value_signature).digest() datas['content']['signer_infos'][0][ 'signature'] = signed_value_signature # Use globalsigns timestamp # TODO: uncomment next 17 lines to have timestamped signature r = s.get( self._timestamp_url.format(digest=signed_value.hex().upper())) if r.status_code != 200: raise APIError('Cannot retrieve the timestamp: {}\n{}'.format( r.status_code, r.json())) timestamp_token = r.json()['token'] timestamp_token = timestamp_token.encode('ascii') timestamp_token = base64.b64decode(timestamp_token) tsp_dict = cms.ContentInfo.load(timestamp_token) tsp_attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tsp_dict['content'], }) ]) }) ] datas['content']['signer_infos'][0]['unsigned_attrs'] = tsp_attrs # TODO: OCSP stuff - probably not necessary since we have a DSS #ocsp_seq = pdf.SequenceOfOCSPResponse((self._ocsp_response,)) #ocsp_arc = pdf.RevocationInfoArchival({'ocsp': ocsp_seq}) #revocation_info = pdf.SetOfRevocationInfoArchival() #revocation_info.append(ocsp_arc) #self._ocsp_response #ocsp_attribute = cms.CMSAttribute({ # basic_ocsp_response #'type': cms.CMSAttributeType('adobe_revocation_info_archival'), #'values': pdf.SetOfRevocationInfoArchival([ #pdf.RevocationInfoArchival({ #'ocsp': pdf.SequenceOfOCSPResponse(self._ocsp_response) #})#cert2asn(ocsp_resp.public_bytes(serialization.Encoding.DER), False) #]) #}), #datas['content']['signer_infos'][0]['unsigned_attrs'].append(ocsp_attribute) return datas.dump()