Example #1
0
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
        })
Example #3
0
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
    })
Example #4
0
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()
Example #5
0
    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
Example #6
0
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)
Example #7
0
 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)
Example #9
0
 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
     })
Example #10
0
    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
Example #11
0
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
     })
Example #13
0
 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),})
Example #14
0
    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
Example #15
0
 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
Example #16
0
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
Example #17
0
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()
Example #18
0
    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()
Example #19
0
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
Example #20
0
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()
Example #21
0
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")
Example #22
0
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()
Example #23
0
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()
Example #24
0
    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})
Example #25
0
    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})
Example #26
0
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()
Example #27
0
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()
Example #28
0
 def test_digest_parameters(self):
     sha1 = algos.DigestAlgorithm({'algorithm': 'sha1'})
     self.assertEqual(core.Null, sha1['parameters'].__class__)
Example #29
0
    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
Example #30
0
    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()