def update_sig_algo_if_no_hash_algo(sig_algo: SignedDigestAlgorithm, hash_algo: str): n_sig_algo = sig_algo['algorithm'].native if n_sig_algo == 'rsassa_pkcs1v15' or n_sig_algo == 'ecdsa' or n_sig_algo == 'dsa': if n_sig_algo == 'rsassa_pkcs1v15': n_sig_algo = 'rsa' if hash_algo == 'md5': sig_algo = SignedDigestAlgorithm({'algorithm': 'md5_' + n_sig_algo}) elif hash_algo == 'sha1': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha1_' + n_sig_algo}) elif hash_algo == 'sha224': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha224_' + n_sig_algo}) elif hash_algo == 'sha256': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha256_' + n_sig_algo}) elif hash_algo == 'sha384': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha384_' + n_sig_algo}) elif hash_algo == 'sha512': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha512_' + n_sig_algo}) elif hash_algo == 'sha3_224': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha3_224_' + n_sig_algo}) elif hash_algo == 'sha3_256': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha3_256_' + n_sig_algo}) elif hash_algo == 'sha3_384': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha3_384_' + n_sig_algo}) elif hash_algo == 'sha3_512': sig_algo = SignedDigestAlgorithm({'algorithm': 'sha3_512_' + n_sig_algo}) return sig_algo
def _tamper_with_sig_obj(tamper_fun): input_buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(input_buf) md_algorithm = 'sha256' cms_writer = cms_embedder.PdfCMSEmbedder().write_cms( field_name='Signature', writer=w ) next(cms_writer) sig_obj = signers.SignatureObject(bytes_reserved=8192) cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj)) tamper_fun(w, sig_obj) prep_document_hash, output = cms_writer.send( cms_embedder.SigIOSetup(md_algorithm=md_algorithm, in_place=True) ) signer: signers.SimpleSigner = signers.SimpleSigner( signing_cert=FROM_CA.signing_cert, signing_key=FROM_CA.signing_key, cert_registry=FROM_CA.cert_registry, signature_mechanism=SignedDigestAlgorithm({ 'algorithm': 'rsassa_pkcs1v15' }) ) with pytest.deprecated_call(): # noinspection PyDeprecation cms_obj = signer.sign( data_digest=prep_document_hash.document_digest, digest_algorithm=md_algorithm, ) cms_writer.send(cms_obj) return output
def __init__(self, pkcs11_session: Session, cert_label: str, ca_chain=None, key_label=None): """ Initialise a PKCS11 signer. :param pkcs11_session: The PKCS11 session object to use. :param cert_label: The label of the certificate that will be used for signing. :param ca_chain: Set of other relevant certificates (as :class:`.asn1crypto.x509.Certificate` objects). :param key_label: The label of the key that will be used for signing. Defaults to the value of ``cert_label`` if left unspecified. """ self.cert_label = cert_label self.key_label = key_label or cert_label self.pkcs11_session = pkcs11_session if ca_chain is not None: cs = SimpleCertificateStore() cs.register_multiple(ca_chain) self._cert_registry: CertificateStore = cs else: self._cert_registry = None self._signing_cert = self._key_handle = None self._loaded = False self.signature_mechanism = SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'}) super().__init__()
def test_sign_pss_md_discrepancy(): # Acrobat refuses to validate PSS signatures where the internal # hash functions disagree, but mathematically speaking, that shouldn't # be an issue. signer = signers.SimpleSigner.load( CRYPTO_DATA_DIR + '/selfsigned.key.pem', CRYPTO_DATA_DIR + '/selfsigned.cert.pem', ca_chain_files=(CRYPTO_DATA_DIR + '/selfsigned.cert.pem',), key_passphrase=b'secret', signature_mechanism=SignedDigestAlgorithm({ 'algorithm': 'rsassa_pss', 'parameters': RSASSAPSSParams({ 'mask_gen_algorithm': MaskGenAlgorithm({ 'algorithm': 'mgf1', 'parameters': DigestAlgorithm({'algorithm': 'sha512'}) }), 'hash_algorithm': DigestAlgorithm({'algorithm': 'sha256'}), 'salt_length': 478 }) }) ) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) meta = signers.PdfSignatureMetadata(field_name='Sig1') out = signers.sign_pdf(w, meta, signer=signer) r = PdfFileReader(out) emb = r.embedded_signatures[0] assert emb.field_name == 'Sig1' sda: SignedDigestAlgorithm = emb.signer_info['signature_algorithm'] assert sda.signature_algo == 'rsassa_pss' val_untrusted(emb)
def test_overspecify_cms_digest_algo(): # TODO this behaviour is not ideal, but at least this test documents it signer = signers.SimpleSigner.load( CRYPTO_DATA_DIR + '/selfsigned.key.pem', CRYPTO_DATA_DIR + '/selfsigned.cert.pem', ca_chain_files=(CRYPTO_DATA_DIR + '/selfsigned.cert.pem',), key_passphrase=b'secret', # specify an algorithm object that also mandates a specific # message digest signature_mechanism=SignedDigestAlgorithm( {'algorithm': 'sha256_rsa'} ) ) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) # digest methods agree, so that should be OK out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig1', md_algorithm='sha256'), signer=signer ) r = PdfFileReader(out) s = r.embedded_signatures[0] val_untrusted(s) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) with pytest.raises(SigningError): signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', md_algorithm='sha512' ), signer=signer )
def __init__(self, certificate, private_key, digest_algorithm, signed_attributes=None): self.certificate = certificate self.private_key = private_key # self.digest_algorithm_id = DigestAlgorithmId('sha512') self.digest_algorithm_id = { 'sha1': DigestAlgorithmId(u'sha1'), 'sha256': DigestAlgorithmId(u'sha256'), 'sha512': DigestAlgorithmId(u'sha512'), }[digest_algorithm] self.digest_algorithm = DigestAlgorithm( {'algorithm': self.digest_algorithm_id}) self.signed_digest_algorithm_id = SignedDigestAlgorithmId( u'rsassa_pkcs1v15') # was: sha256_rsa self.signed_digest_algorithm = SignedDigestAlgorithm( {'algorithm': self.signed_digest_algorithm_id}) if signed_attributes is not None: self.signed_attributes = signed_attributes else: self.signed_attributes = []
async def test_async_sign_raw_many_concurrent_no_preload_objs(bulk_fetch, pss): concurrent_count = 10 # don't instantiate through PKCS11SigningContext # also, just sign raw strings, we want to exercise the correctness of # the awaiting logic in sign_raw for object loading with _simple_sess() as sess: signer = pkcs11.PKCS11Signer(sess, 'signer', other_certs_to_pull=default_other_certs, bulk_fetch=bulk_fetch) async def _job(_i): payload = f"PKCS#11 concurrency test #{_i}!".encode('utf8') sig_result = await signer.async_sign_raw(payload, 'sha256') await asyncio.sleep(2) return _i, sig_result jobs = asyncio.as_completed(map(_job, range(1, concurrent_count + 1))) for finished_job in jobs: i, sig = await finished_job general._validate_raw( signature=sig, signed_data=f"PKCS#11 concurrency test #{i}!".encode('utf8'), cert=signer.signing_cert, md_algorithm='sha256', signature_algorithm=SignedDigestAlgorithm( {'algorithm': 'sha256_rsa'}))
def __init__(self, certificate: x509.Certificate, private_key: rsa.RSAPrivateKeyWithSerialization, digest_algorithm: str, signed_attributes: List[CMSAttribute] = None): self.certificate = certificate self.private_key = private_key self.digest_algorithm_id = DigestAlgorithmId('sha512') # self.digest_algorithm_id = { # 'sha1': DigestAlgorithmId('sha1'), # 'sha256': DigestAlgorithmId('sha256'), # 'sha512': DigestAlgorithmId('sha512'), # }[digest_algorithm] self.digest_algorithm = DigestAlgorithm( {'algorithm': self.digest_algorithm_id}) self.signed_digest_algorithm_id = SignedDigestAlgorithmId( 'rsassa_pkcs1v15') # was: sha256_rsa self.signed_digest_algorithm = SignedDigestAlgorithm( {'algorithm': self.signed_digest_algorithm_id}) if signed_attributes is not None: self.signed_attributes = signed_attributes else: self.signed_attributes = []
async def test_sign_weak_sig_digest(): # We have to jump through some hoops to put together a signature # where the signing method's digest is not the same as the "external" # digest. This is intentional, since it's bad practice. input_buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(input_buf) cms_writer = cms_embedder.PdfCMSEmbedder().write_cms( field_name='Signature', writer=w ) next(cms_writer) timestamp = datetime.now(tz=tzlocal.get_localzone()) sig_obj = signers.SignatureObject(timestamp=timestamp, bytes_reserved=8192) external_md_algorithm = 'sha256' cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj)) prep_digest, output = cms_writer.send( cms_embedder.SigIOSetup(md_algorithm=external_md_algorithm, in_place=True) ) signer = signers.SimpleSigner( signing_cert=TESTING_CA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA.key_set.get_private_key(KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs([ROOT_CERT, INTERM_CERT]) ) cms_obj = await signer.async_sign( data_digest=prep_digest.document_digest, digest_algorithm=external_md_algorithm, signed_attr_settings=PdfCMSSignedAttributes(signing_time=timestamp) ) si_obj: cms.SignerInfo = cms_obj['content']['signer_infos'][0] bad_algo = SignedDigestAlgorithm({'algorithm': 'md5_rsa'}) si_obj['signature_algorithm'] = signer.signature_mechanism = bad_algo attrs = si_obj['signed_attrs'] cms_prot = find_cms_attribute(attrs, 'cms_algorithm_protection')[0] cms_prot['signature_algorithm'] = bad_algo # recompute the signature si_obj['signature'] = signer.sign_raw(attrs.untag().dump(), 'md5') sig_contents = cms_writer.send(cms_obj) # we requested in-place output assert output is input_buf r = PdfFileReader(input_buf) emb = r.embedded_signatures[0] with pytest.raises(WeakHashAlgorithmError): await async_val_trusted(emb) lenient_vc = ValidationContext( trust_roots=[ROOT_CERT], weak_hash_algos=set() ) await async_val_trusted(emb, vc=lenient_vc)
def _tamper_with_signed_attrs(attr_name, *, duplicate=False, delete=False, replace_with=None, resign=False): input_buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(input_buf) md_algorithm = 'sha256' cms_writer = cms_embedder.PdfCMSEmbedder().write_cms( field_name='Signature', writer=w ) next(cms_writer) sig_obj = signers.SignatureObject(bytes_reserved=8192) cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj)) prep_digest, output = cms_writer.send( cms_embedder.SigIOSetup(md_algorithm=md_algorithm, in_place=True) ) signer: signers.SimpleSigner = signers.SimpleSigner( signing_cert=FROM_CA.signing_cert, signing_key=FROM_CA.signing_key, cert_registry=FROM_CA.cert_registry, signature_mechanism=SignedDigestAlgorithm({ 'algorithm': 'rsassa_pkcs1v15' }) ) with pytest.deprecated_call(): # noinspection PyDeprecation cms_obj = signer.sign( data_digest=prep_digest.document_digest, digest_algorithm=md_algorithm, ) sd = cms_obj['content'] si, = sd['signer_infos'] signed_attrs = si['signed_attrs'] ix = next( ix for ix, attr in enumerate(signed_attrs) if attr['type'].native == attr_name ) # mess with the attribute in the requested way if delete: del signed_attrs[ix] elif duplicate: vals = signed_attrs[ix]['values'] vals.append(vals[0]) else: vals = signed_attrs[ix]['values'] vals[0] = replace_with # ... and replace the signature if requested if resign: si['signature'] = \ signer.sign_raw(si['signed_attrs'].untag().dump(), md_algorithm) cms_writer.send(cms_obj) return output
async def test_no_certificates(delete): input_buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(input_buf) md_algorithm = 'sha256' cms_writer = cms_embedder.PdfCMSEmbedder().write_cms( field_name='Signature', writer=w ) next(cms_writer) sig_obj = signers.SignatureObject(bytes_reserved=8192) cms_writer.send(cms_embedder.SigObjSetup(sig_placeholder=sig_obj)) prep_digest, output = cms_writer.send( cms_embedder.SigIOSetup(md_algorithm=md_algorithm, in_place=True) ) signer: signers.SimpleSigner = signers.SimpleSigner( signing_cert=FROM_CA.signing_cert, signing_key=FROM_CA.signing_key, cert_registry=FROM_CA.cert_registry, signature_mechanism=SignedDigestAlgorithm({ 'algorithm': 'rsassa_pkcs1v15' }) ) cms_obj = await signer.async_sign( data_digest=prep_digest.document_digest, digest_algorithm=md_algorithm, ) sd = cms_obj['content'] if delete: del sd['certificates'] else: sd['certificates'] = cms.CertificateSet([]) cms_writer.send(cms_obj) r = PdfFileReader(output) with pytest.raises(CMSExtractionError, match='signer cert.*includ'): emb = r.embedded_signatures[0] await collect_validation_info( embedded_sig=emb, validation_context=ValidationContext() ) with pytest.raises(SignatureValidationError, match='signer cert.*includ'): r.embedded_signatures[0].signer_cert.dump()
def test_sign_with_explicit_dsa_implied_hash(): signer = signers.SimpleSigner( signing_cert=TESTING_CA_DSA.get_cert(CertLabel('signer1')), signing_key=TESTING_CA_DSA.key_set.get_private_key( KeyLabel('signer1')), cert_registry=SimpleCertificateStore.from_certs( [DSA_ROOT_CERT, DSA_INTERM_CERT]), # this is not allowed, but the validator should accept it anyway signature_mechanism=SignedDigestAlgorithm({'algorithm': 'dsa'})) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=signer) r = PdfFileReader(out) s = r.embedded_signatures[0] si = s.signer_info assert si['signature_algorithm']['algorithm'].native == 'dsa' assert s.field_name == 'Sig1' val_trusted(s, vc=SIMPLE_DSA_V_CONTEXT())
def sign(self): h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self._content_mime.as_bytes()) message_digest = h.finalize() cs = CertificateSet() cs.append(load(self._certificate.public_bytes(Encoding.DER))) for ca_cert in self._ca: cs.append(load(ca_cert.public_bytes(Encoding.DER))) ec = EncapsulatedContentInfo({ 'content_type': ContentType('data'), 'content': ParsableOctetString(self._content_mime.as_bytes()) }) sident = SignerIdentifier({ 'issuer_and_serial_number': IssuerAndSerialNumber({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }) }) certv2 = ESSCertIDv2({ 'hash_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'cert_hash': OctetString(self._certificate.fingerprint(hashes.SHA256())), 'issuer_serial': IssuerSerial({ 'issuer': load( self._issuer_name.public_bytes(default_backend()) ), #[GeneralName({'directory_name': self._issuer_name.public_bytes(default_backend())})], 'serial_number': self._cert_serial, }), }) now = datetime.now().replace(microsecond=0, tzinfo=pytz.utc) sattrs = CMSAttributes({ CMSAttribute({ 'type': CMSAttributeType('content_type'), 'values': ["data"] }), CMSAttribute({ 'type': CMSAttributeType('message_digest'), 'values': [message_digest] }), CMSAttribute({ 'type': CMSAttributeType('signing_time'), 'values': (Time({'utc_time': UTCTime(now)}), ) }), # isti k v CMSAttribute({ 'type': CMSAttributeType('signing_certificate_v2'), 'values': [SigningCertificateV2({'certs': (certv2, )})] }) }) signature = self._private_key.sign(sattrs.dump(), padding.PKCS1v15(), hashes.SHA256()) si = SignerInfo({ 'version': 'v1', 'sid': sident, 'digest_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'signed_attrs': sattrs, 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': SignedDigestAlgorithmId('rsassa_pkcs1v15')}), 'signature': signature, }) da = DigestAlgorithms( (DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), )) signed_data = SignedData({ 'version': 'v3', 'encap_content_info': ec, 'certificates': cs, 'digest_algorithms': da, 'signer_infos': SignerInfos((si, )) }) ci = ContentInfo({ 'content_type': ContentType('signed_data'), 'content': signed_data }) self.set_payload(ci.dump()) encode_base64(self)
vals = signed_attrs[ix]['values'] vals[0] = replace_with # ... and replace the signature if requested if resign: si['signature'] = \ signer.sign_raw(si['signed_attrs'].untag().dump(), md_algorithm) cms_writer.send(cms_obj) return output @pytest.mark.parametrize('replacement_value', [ cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha1'}), 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': 'rsassa_pkcs1v15'} ) }), cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha256'}), 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': 'sha512_rsa'} ) }), cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha256'}), }), None ]) def test_cms_algorithm_protection(replacement_value): output = _tamper_with_signed_attrs(
class Signer(object): """The signer object represents a single signer on a SignedData structure. It provides a convenient way of generating a signature and a SignerInfo. Attributes: certificate (x509.Certificate): Signers certificate private_key (rsa.RSAPrivateKey): Signers private key """ signed_digest_algorithm_id = SignedDigestAlgorithmId('rsassa_pkcs1v15') # was: sha256_rsa signed_digest_algorithm = SignedDigestAlgorithm({'algorithm': signed_digest_algorithm_id, 'parameters': None}) def __init__(self, certificate: x509.Certificate, private_key: rsa.RSAPrivateKeyWithSerialization, digest_algorithm: str, signed_attributes: List[CMSAttribute] = None): self.certificate = certificate self.private_key = private_key self.digest_algorithm_id = { 'sha1': DigestAlgorithmId('sha1'), 'sha256': DigestAlgorithmId('sha256'), 'sha512': DigestAlgorithmId('sha512'), }[digest_algorithm] self.digest_algorithm = DigestAlgorithm({'algorithm': self.digest_algorithm_id}) if signed_attributes is not None: self.signed_attributes = signed_attributes else: self.signed_attributes = [] @property def sid(self) -> SignerIdentifier: """Get a SignerIdentifier for IssuerAndSerialNumber""" derp = self.certificate.public_bytes(serialization.Encoding.DER) asn1cert = parse_certificate(derp) # Signer Identifier ias = IssuerAndSerialNumber({'issuer': asn1cert.issuer, 'serial_number': asn1cert.serial_number}) sid = SignerIdentifier('issuer_and_serial_number', ias) return sid def sign(self, data: bytes, content_type: ContentType, content_digest: bytes, cms_attributes: List[CMSAttribute]) -> SignerInfo: """Generate a signature encrypted with the signer's private key and return the SignerInfo.""" # The CMS standard requires that the content-type authenticatedAttribute and the message-digest # attribute must be present if any authenticatedAttribute exists at all. self.signed_attributes = cms_attributes self.signed_attributes.insert(0, CMSAttribute({ 'type': 'signing_time', 'values': [GeneralizedTime(datetime.datetime.utcnow())] })) self.signed_attributes.insert(0, CMSAttribute({ 'type': 'message_digest', 'values': [OctetString(content_digest)], })) # This refers to whatever the content of EncapsulatedContentInfo is self.signed_attributes.insert(0, CMSAttribute({ 'type': 'content_type', 'values': [content_type], })) cms_attributes = CMSAttributes(self.signed_attributes) # NOTE: no need to calculate this digest as .signer() does the hashing # RFC5652 # The message digest is # computed on either the content being signed or the content # together with the signed attributes using the process described in # Section 5.4. # digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) # the initial input is the encapContentInfo eContent OCTET STRING # RFC5652 Section 5.4 - When the field (signed_attrs) is present, however, the result is the message # digest of the complete DER encoding of the SignedAttrs value # contained in the signedAttrs field. # NOTE: it is not clear whether data is included #digest.update(data) # digest.update(cms_attributes.dump()) # d = digest.finalize() # Make DigestInfo from result # NOTE: It is not clear whether this applies: RFC5652 - Section 5.5. # digest_info = DigestInfo({ # 'digest_algorithm': self.digest_algorithm, # 'digest': d, # }) # Get the RSA key to sign the digestinfo digest_function = { 'sha1': hashes.SHA1, # macOS 'sha256': hashes.SHA256, 'sha512': hashes.SHA512 }[self.digest_algorithm_id.native] signer = self.private_key.signer( asympad.PKCS1v15(), digest_function(), ) # NOTE: this is not the digest `d` above because crypto.io already hashes stuff for us!! signer.update(cms_attributes.dump()) signature = signer.finalize() signer_info = SignerInfo({ # Version must be 1 if signer uses IssuerAndSerialNumber as sid 'version': CMSVersion(1), 'sid': self.sid, 'digest_algorithm': self.digest_algorithm, 'signed_attrs': cms_attributes, # Referred to as ``digestEncryptionAlgorithm`` in the RFC 'signature_algorithm': self.signed_digest_algorithm, # Referred to as ``encryptedDigest`` in the RFC 'signature': OctetString(signature), }) return signer_info
def sign(self): h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self._content_mime.as_bytes()) message_digest = h.finalize() cs = CertificateSet() cs.append(load(self._certificate.public_bytes(Encoding.DER))) for ca_cert in self._ca: cs.append(load(ca_cert.public_bytes(Encoding.DER))) ec = ContentInfo({ 'content_type': ContentType('data'), }) sident = SignerIdentifier({ 'issuer_and_serial_number': IssuerAndSerialNumber({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }) }) certv2 = ESSCertIDv2({ 'hash_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'cert_hash': OctetString(self._certificate.fingerprint(hashes.SHA256())), 'issuer_serial': IssuerSerial({ 'issuer': load(self._issuer_name.public_bytes(default_backend())), 'serial_number': self._cert_serial, }), }) now = datetime.now().replace(microsecond=0, tzinfo=pytz.utc) # .isoformat() sattrs = CMSAttributes({ CMSAttribute({ 'type': CMSAttributeType('content_type'), 'values': ["data"] }), CMSAttribute({ 'type': CMSAttributeType('message_digest'), 'values': [message_digest] }), CMSAttribute({ 'type': CMSAttributeType('signing_time'), 'values': (Time({'utc_time': UTCTime(now)}), ) }), CMSAttribute({ 'type': CMSAttributeType('signing_certificate_v2'), 'values': [SigningCertificateV2({'certs': (certv2, )})] }) }) signature = self._private_key.sign(sattrs.dump(), padding.PKCS1v15(), hashes.SHA256()) # si = SignerInfo({ 'version': 'v1', 'sid': sident, 'digest_algorithm': DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), 'signed_attrs': sattrs, 'signature_algorithm': SignedDigestAlgorithm( {'algorithm': SignedDigestAlgorithmId('rsassa_pkcs1v15')}), 'signature': signature, }) da = DigestAlgorithms( (DigestAlgorithm({'algorithm': DigestAlgorithmId('sha256')}), )) signed_data = SignedData({ 'version': 'v1', 'encap_content_info': ec, 'certificates': cs, 'digest_algorithms': da, 'signer_infos': SignerInfos((si, )) }) ci = ContentInfo({ 'content_type': ContentType('signed_data'), 'content': signed_data }) self._signature_mime = MIMEApplication(ci.dump(), _subtype="pkcs7-signature", name="smime.p7s", policy=email.policy.SMTPUTF8) self._signature_mime.add_header('Content-Disposition', 'attachment; filename=smime.p7s') super(CADESMIMESignature, self).attach(self._content_mime) super(CADESMIMESignature, self).attach(self._signature_mime)
vals[0] = replace_with # ... and replace the signature if requested if resign: si['signature'] = \ signer.sign_raw(si['signed_attrs'].untag().dump(), md_algorithm) cms_writer.send(cms_obj) return output @pytest.mark.parametrize('replacement_value', [ cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha1'}), 'signature_algorithm': SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}) }), cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha256'}), 'signature_algorithm': SignedDigestAlgorithm({'algorithm': 'sha512_rsa'}) }), cms.CMSAlgorithmProtection({ 'digest_algorithm': DigestAlgorithm({'algorithm': 'sha256'}), }), None ]) def test_cms_algorithm_protection(replacement_value): output = _tamper_with_signed_attrs('cms_algorithm_protection', duplicate=replacement_value is None,