Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
    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__()
Esempio n. 4
0
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)
Esempio n. 5
0
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
        )
Esempio n. 6
0
    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 = []
Esempio n. 7
0
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'}))
Esempio n. 8
0
    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 = []
Esempio n. 9
0
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)
Esempio n. 10
0
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
Esempio n. 11
0
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()
Esempio n. 12
0
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())
Esempio n. 13
0
    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)
Esempio n. 14
0
        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(
Esempio n. 15
0
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
Esempio n. 16
0
    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)
Esempio n. 17
0
        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,