Exemplo n.º 1
0
def build_as_req_negoEx(user_cert, cert_pass, remoteComputer,
                        diffieHellmanExchange):
    pfx = open(user_cert, 'rb').read()
    privkeyinfo, certificate, extra_certs = parse_pkcs12(
        pfx, password=cert_pass.encode())
    privkey = load_private_key(privkeyinfo)
    issuer = certificate.issuer.native['common_name']
    cname = "AzureAD\\" + issuer + "\\" + [
        i for i in certificate.subject.native['common_name']
        if i.startswith('S-1')
    ][0]

    now = datetime.datetime.now(datetime.timezone.utc)

    req_body = build_req_body_NegoEx(remoteComputer, cname, now)

    padata = BuildPkinit_pa(req_body, now, diffieHellmanExchange, privkey,
                            certificate)

    payload = PA_PK_AS_REQ()
    payload['signedAuthPack'] = padata

    pa_data = {
        'padata-type': PaDataType.PK_AS_REQ.value,
        'padata-value': payload.dump()
    }

    asreq = {
        'pvno': 5,
        'msg-type': 10,
        'padata': [pa_data],
        'req-body': req_body
    }

    req = {
        'kerberos-v5': algos.DigestAlgorithmId('1.3.6.1.5.2.7'),
        'null': core.Null(),
        'Kerberos': AS_REQ(asreq)
    }
    req = SPNEGO_PKINIT_REP(req)

    return issuer, req.dump().hex()
Exemplo n.º 2
0
def dump_private_key(private_key, passphrase, encoding='pem', target_ms=200):
    """
    Serializes a private key object into a byte string of the PKCS#8 format

    :param private_key:
        An oscrypto.asymmetric.PrivateKey or asn1crypto.keys.PrivateKeyInfo
        object

    :param passphrase:
        A unicode string of the passphrase to encrypt the private key with.
        A passphrase of None will result in no encryption. A blank string will
        result in a ValueError to help ensure that the lack of passphrase is
        intentional.

    :param encoding:
        A unicode string of "pem" or "der"

    :param target_ms:
        Use PBKDF2 with the number of iterations that takes about this many
        milliseconds on the current machine.

    :raises:
        ValueError - when a blank string is provided for the passphrase

    :return:
        A byte string of the encoded and encrypted public key
    """

    if encoding not in set(['pem', 'der']):
        raise ValueError(
            pretty_message(
                '''
            encoding must be one of "pem", "der", not %s
            ''', repr(encoding)))

    if passphrase is not None:
        if not isinstance(passphrase, str_cls):
            raise TypeError(
                pretty_message(
                    '''
                passphrase must be a unicode string, not %s
                ''', type_name(passphrase)))
        if passphrase == '':
            raise ValueError(
                pretty_message('''
                passphrase may not be a blank string - pass None to disable
                encryption
                '''))

    is_oscrypto = isinstance(private_key, PrivateKey)
    if not isinstance(private_key, keys.PrivateKeyInfo) and not is_oscrypto:
        raise TypeError(
            pretty_message(
                '''
            private_key must be an instance of oscrypto.asymmetric.PrivateKey
            or asn1crypto.keys.PrivateKeyInfo, not %s
            ''', type_name(private_key)))

    if is_oscrypto:
        private_key = private_key.asn1

    output = private_key.dump()

    if passphrase is not None:
        cipher = 'aes256_cbc'
        key_length = 32
        kdf_hmac = 'sha256'
        kdf_salt = rand_bytes(key_length)
        iterations = pbkdf2_iteration_calculator(kdf_hmac,
                                                 key_length,
                                                 target_ms=target_ms,
                                                 quiet=True)
        # Need a bare minimum of 10,000 iterations for PBKDF2 as of 2015
        if iterations < 10000:
            iterations = 10000

        passphrase_bytes = passphrase.encode('utf-8')
        key = pbkdf2(kdf_hmac, passphrase_bytes, kdf_salt, iterations,
                     key_length)
        iv, ciphertext = aes_cbc_pkcs7_encrypt(key, output, None)

        output = keys.EncryptedPrivateKeyInfo({
            'encryption_algorithm': {
                'algorithm': 'pbes2',
                'parameters': {
                    'key_derivation_func': {
                        'algorithm': 'pbkdf2',
                        'parameters': {
                            'salt':
                            algos.Pbkdf2Salt(name='specified', value=kdf_salt),
                            'iteration_count':
                            iterations,
                            'prf': {
                                'algorithm': kdf_hmac,
                                'parameters': core.Null()
                            }
                        }
                    },
                    'encryption_scheme': {
                        'algorithm': cipher,
                        'parameters': iv
                    }
                }
            },
            'encrypted_data': ciphertext
        }).dump()

    if encoding == 'pem':
        if passphrase is None:
            object_type = 'PRIVATE KEY'
        else:
            object_type = 'ENCRYPTED PRIVATE KEY'
        output = pem.armor(object_type, output)

    return output
    def build(self, responder_private_key=None, responder_certificate=None):
        """
        Validates the request information, constructs the ASN.1 structure and
        signs it.
        The responder_private_key and responder_certificate parameters are onlystr
        required if the response_status is "successful".
        :param responder_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the response with
        :param responder_certificate:
            An asn1crypto.x509.Certificate or oscrypto.asymmetric.Certificate
            object of the certificate associated with the private key
        :return:
            An asn1crypto.ocsp.OCSPResponse object of the response
        """
        if self._response_status != 'successful':
            return ocsp.OCSPResponse({
                'response_status': self._response_status
            })

        is_oscrypto = isinstance(responder_private_key, asymmetric.PrivateKey)
        if not isinstance(responder_private_key, keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(_pretty_message(
                '''
                responder_private_key must be an instance ofthe c
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''',
                _type_name(responder_private_key)
            ))

        cert_is_oscrypto = isinstance(responder_certificate, asymmetric.Certificate)
        if not isinstance(responder_certificate, x509.Certificate) and not cert_is_oscrypto:
            raise TypeError(_pretty_message(
                '''
                responder_certificate must be an instance of
                asn1crypto.x509.Certificate or
                oscrypto.asymmetric.Certificate, not %s
                ''',
                _type_name(responder_certificate)
            ))

        if cert_is_oscrypto:
            responder_certificate = responder_certificate.asn1

        if self._certificate_status_list is None:
            raise ValueError(_pretty_message(
                '''
                certificate_status_list must be set if the response_status is
                "successful"
                '''
            ))

        def _make_extension(name, value):
            return {
                'extn_id': name,
                'critical': False,
                'extn_value': value
            }

        responses = []
        for serial, status in self._certificate_status_list:
            response_data_extensions = []
            single_response_extensions = []
            for name, value in self._response_data_extensions.items():
                response_data_extensions.append(_make_extension(name, value))
            if self._nonce:
                response_data_extensions.append(
                    _make_extension('nonce', self._nonce)
                )

            if not response_data_extensions:
                response_data_extensions = None

            for name, value in self._single_response_extensions.items():
                single_response_extensions.append(_make_extension(name, value))

            if self._certificate_issuer:
                single_response_extensions.append(
                    _make_extension(
                        'certificate_issuer',
                        [
                            x509.GeneralName(
                                name='directory_name',
                                value=self._certificate_issuer.subject
                            )
                        ]
                    )
                )

            if not single_response_extensions:
                single_response_extensions = None

            responder_key_hash = getattr(responder_certificate.public_key, self._key_hash_algo)

            if status == 'good':
                cert_status = ocsp.CertStatus(
                    name='good',
                    value=core.Null()
                )
            elif status == 'unknown':
                cert_status = ocsp.CertStatus(
                    name='unknown',
                    value=core.Null()
                )
            else:
                reason = status if status != 'revoked' else 'unspecified'
                cert_status = ocsp.CertStatus(
                    name='revoked',
                    value={
                        'revocation_time': self._revocation_date,
                        'revocation_reason': reason,
                    }
                )

            issuer = self._certificate_issuer if self._certificate_issuer else responder_certificate

            produced_at = datetime.now(timezone.utc).replace(microsecond=0)

            if self._this_update is None:
                self._this_update = produced_at

            if self._next_update is None:
                self._next_update = (self._this_update + timedelta(days=7)).replace(microsecond=0)

            response = {
                    'cert_id': {
                        'hash_algorithm': {
                            'algorithm': self._key_hash_algo
                        },
                        'issuer_name_hash': getattr(issuer.subject, self._key_hash_algo),
                        'issuer_key_hash': getattr(issuer.public_key, self._key_hash_algo),
                        'serial_number': serial,
                    },
                    'cert_status': cert_status,
                    'this_update': self._this_update,
                    'next_update': self._next_update,
                    'single_extensions': single_response_extensions
                }
            responses.append(response)

        response_data = ocsp.ResponseData({
            'responder_id': ocsp.ResponderId(name='by_key', value=responder_key_hash),
            'produced_at': produced_at,
            'responses': responses,
            'response_extensions': response_data_extensions
        })

        signature_algo = responder_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        if responder_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif responder_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif responder_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            responder_private_key = asymmetric.load_private_key(responder_private_key)
        signature_bytes = sign_func(responder_private_key, response_data.dump(), self._hash_algo)

        certs = None
        if self._certificate_issuer and getattr(self._certificate_issuer.public_key, self._key_hash_algo) != responder_key_hash:
            certs = [responder_certificate]

        return ocsp.OCSPResponse({
            'response_status': self._response_status,
            'response_bytes': {
                'response_type': 'basic_ocsp_response',
                'response': {
                    'tbs_response_data': response_data,
                    'signature_algorithm': {'algorithm': signature_algorithm_id},
                    'signature': signature_bytes,
                    'certs': certs,
                }
            }
        })
Exemplo n.º 4
0
    def build(self, signing_private_key):
        """
        Validates the certificate information, constructs the ASN.1 structure
        and then signs it

        :param signing_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the certificate with. If the key
            is self-signed, this should be the private key that matches the
            public key, otherwise it needs to be the issuer's private key.

        :return:
            An asn1crypto.x509.Certificate object of the newly signed
            certificate
        """

        is_oscrypto = isinstance(signing_private_key, asymmetric.PrivateKey)
        if not isinstance(
                signing_private_key, keys.PrivateKeyInfo
        ) and not is_oscrypto and signing_private_key is not None:
            raise TypeError(
                _pretty_message(
                    '''
                signing_private_key must be an instance of
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''', _type_name(signing_private_key)))

        if self._self_signed is not True and self._issuer is None:
            raise ValueError(
                _pretty_message('''
                Certificate must be self-signed, or an issuer must be specified
                '''))

        if self._self_signed:
            self._issuer = self._subject

        if self._serial_number is None:
            time_part = int_to_bytes(int(time.time()))
            random_part = util.rand_bytes(4)
            self._serial_number = int_from_bytes(time_part + random_part)

        if self._begin_date is None:
            self._begin_date = datetime.now(timezone.utc)

        if self._end_date is None:
            self._end_date = self._begin_date + timedelta(365)

        if not self.ca:
            for ca_only_extension in set([
                    'policy_mappings', 'policy_constraints',
                    'inhibit_any_policy'
            ]):
                if ca_only_extension in self._other_extensions:
                    raise ValueError(
                        _pretty_message(
                            '''
                        Extension %s is only valid for CA certificates
                        ''', ca_only_extension))

        if signing_private_key is not None:
            signature_algo = signing_private_key.algorithm
            if signature_algo == 'ec':
                signature_algo = 'ecdsa'

            signature_algorithm_id = '%s_%s' % (self._hash_algo,
                                                signature_algo)
        else:
            signature_algorithm_id = '%s_%s' % (
                self._hash_algo, "rsa")  #making rsa assumption for ease

        # RFC 3280 4.1.2.5
        def _make_validity_time(dt):
            if dt < datetime(2050, 1, 1, tzinfo=timezone.utc):
                value = x509.Time(name='utc_time', value=dt)
            else:
                value = x509.Time(name='general_time', value=dt)

            return value

        def _make_extension(name, value):
            return {
                'extn_id': name,
                'critical': self._determine_critical(name),
                'extn_value': value
            }

        extensions = []
        for name in sorted(self._special_extensions):
            value = getattr(self, '_%s' % name)
            if name == 'ocsp_no_check':
                value = core.Null() if value else None
            if value is not None:
                extensions.append(_make_extension(name, value))

        for name in sorted(self._other_extensions.keys()):
            extensions.append(
                _make_extension(name, self._other_extensions[name]))

        tbs_cert = x509.TbsCertificate({
            'version': 'v3',
            'serial_number': self._serial_number,
            'signature': {
                'algorithm': signature_algorithm_id
            },
            'issuer': self._issuer,
            'validity': {
                'not_before': _make_validity_time(self._begin_date),
                'not_after': _make_validity_time(self._end_date),
            },
            'subject': self._subject,
            'subject_public_key_info': self._subject_public_key,
            'extensions': extensions
        })

        if signing_private_key is None:
            return tbs_cert
        elif signing_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif signing_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif signing_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            signing_private_key = asymmetric.load_private_key(
                signing_private_key)
        signature = sign_func(signing_private_key, tbs_cert.dump(),
                              self._hash_algo)

        return x509.Certificate({
            'tbs_certificate': tbs_cert,
            'signature_algorithm': {
                'algorithm': signature_algorithm_id
            },
            'signature_value': signature
        })
Exemplo n.º 5
0
    def build(self, responder_private_key=None, responder_certificate=None):
        """
        Validates the request information, constructs the ASN.1 structure and
        signs it.

        The responder_private_key and responder_certificate parameters are only
        required if the response_status is "successful".

        :param responder_private_key:
            An asn1crypto.keys.PrivateKeyInfo or oscrypto.asymmetric.PrivateKey
            object for the private key to sign the response with

        :param responder_certificate:
            An asn1crypto.x509.Certificate or oscrypto.asymmetric.Certificate
            object of the certificate associated with the private key

        :return:
            An asn1crypto.ocsp.OCSPResponse object of the response
        """

        if self._response_status != 'successful':
            return ocsp.OCSPResponse(
                {'response_status': self._response_status})

        is_oscrypto = isinstance(responder_private_key, asymmetric.PrivateKey)
        if not isinstance(responder_private_key,
                          keys.PrivateKeyInfo) and not is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_private_key must be an instance of
                asn1crypto.keys.PrivateKeyInfo or
                oscrypto.asymmetric.PrivateKey, not %s
                ''', _type_name(responder_private_key)))

        cert_is_oscrypto = isinstance(responder_certificate,
                                      asymmetric.Certificate)
        if not isinstance(responder_certificate,
                          x509.Certificate) and not cert_is_oscrypto:
            raise TypeError(
                _pretty_message(
                    '''
                responder_certificate must be an instance of
                asn1crypto.x509.Certificate or
                oscrypto.asymmetric.Certificate, not %s
                ''', _type_name(responder_certificate)))

        if cert_is_oscrypto:
            responder_certificate = responder_certificate.asn1

        for cert in self._certificates:
            if not cert:
                raise ValueError(
                    _pretty_message('''
                    certificates must be set if the response_status is
                    "successful"
                    '''))
        for cert_status in self._certificates_status:
            if not cert_status:
                raise ValueError(
                    _pretty_message('''
                    certificates_status for all certificates must be set if the response_status is
                    "successful"
                    '''))

        def _make_extension(name, value):
            return {'extn_id': name, 'critical': False, 'extn_value': value}

        issuer = self._certificate_issuer if self._certificate_issuer else responder_certificate
        for x in range(len(self._certificates)):
            if issuer.subject != self._certificates[x].issuer:
                raise ValueError(
                    _pretty_message('''
                    responder_certificate does not appear to be the issuer for
                    the certificate. Perhaps set the .certificate_issuer attribute?
                    '''))
        total_issuers = len(self._certificates)
        response_data_extensions = []
        single_response_extensions = [[]] * total_issuers
        for x in range(len(self._certificates)):
            for name, value in self._response_data_extensions[x].items():
                response_data_extensions.append(_make_extension(name, value))
            for name, value in self._single_response_extensions[x].items():
                single_response_extensions[x].append(
                    _make_extension(name, value))
            # This means single_response_extensions can never be empty
            single_response_extensions[x].append(
                _make_extension('certificate_issuer', [
                    x509.GeneralName(name='directory_name',
                                     value=issuer.subject)
                ]))

        if self._nonce:
            response_data_extensions.append(
                _make_extension('nonce', self._nonce))

        if len(response_data_extensions) == 0:
            response_data_extensions = None

        responder_key_hash = getattr(responder_certificate.public_key,
                                     self._key_hash_algo)

        certs_status = []
        for x in range(len(self._certificates_status)):
            c_stat = self._certificates_status[x]
            if c_stat == 'good':
                cert_status = ocsp.CertStatus(name='good', value=core.Null())
            elif c_stat == 'unknown':
                cert_status = ocsp.CertStatus(name='unknown',
                                              value=core.Null())
            else:
                status = c_stat
                reason = status if status != 'revoked' else 'unspecified'
                cert_status = ocsp.CertStatus(name='revoked',
                                              value={
                                                  'revocation_time':
                                                  self._revocation_dates[x],
                                                  'revocation_reason':
                                                  reason,
                                              })
            certs_status.append(cert_status)

        produced_at = datetime.now(timezone.utc)
        # Construct the multiple certs response
        responses = []
        for x in range(len(self._certificates)):
            if self._this_updates[x] is None:
                self._this_updates[x] = produced_at
            if self._next_updates[x] is None:
                self._next_updates[x] = self._this_updates[x] + timedelta(
                    days=7)
            item = {
                'cert_id': {
                    'hash_algorithm': {
                        'algorithm': self._key_hash_algo
                    },
                    'issuer_name_hash':
                    getattr(self._certificates[x].issuer, self._key_hash_algo),
                    'issuer_key_hash':
                    getattr(issuer.public_key, self._key_hash_algo),
                    'serial_number':
                    self._certificates[x].serial_number
                },
                'cert_status': certs_status[x],
                'this_update': self._this_updates[x],
                'next_update': self._next_updates[x],
                'single_extensions': single_response_extensions[x]
            }
            responses.append(item)

        signature_algo = responder_private_key.algorithm
        if signature_algo == 'ec':
            signature_algo = 'ecdsa'

        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        if responder_private_key.algorithm == 'rsa':
            sign_func = asymmetric.rsa_pkcs1v15_sign
        elif responder_private_key.algorithm == 'dsa':
            sign_func = asymmetric.dsa_sign
        elif responder_private_key.algorithm == 'ec':
            sign_func = asymmetric.ecdsa_sign

        if not is_oscrypto:
            responder_private_key = asymmetric.load_private_key(
                responder_private_key)
        # Set response_data for use in ocsp-service
        response_data = ocsp.ResponseData({
            'responder_id':
            ocsp.ResponderId(name='by_key', value=responder_key_hash),
            'produced_at':
            produced_at,
            'responses':
            responses,
            'response_extensions':
            response_data_extensions
        })
        signature_bytes = sign_func(responder_private_key,
                                    response_data.dump(), self._hash_algo)
        certs = None
        if self._certificate_issuer:
            certs = [responder_certificate]
        return ocsp.OCSPResponse({
            'response_status': self._response_status,
            'response_bytes': {
                'response_type': 'basic_ocsp_response',
                'response': {
                    'tbs_response_data': response_data,
                    'signature_algorithm': {
                        'algorithm': signature_algorithm_id
                    },
                    'signature': signature_bytes,
                    'certs': certs
                }
            }
        })
Exemplo n.º 6
0
    def build_mpc(self, signing_private_key, orq_ip, orq_port):
        """
        Validates the certificate information, constructs the ASN.1 structure
        and then signs it with a mpc engine

        :param signing_private_key:
            An integer identifier for the private key to sign the certificate with.
            This identifier permits the mpc engine to find the private key associated
            with the public key exported in the key generation process

        :return:
            An asn1crypto.x509.Certificate object of the newly signed
            certificate
        """
        def rsa_mpc_sign(signing_private_key, tbs_cert_dump, hash_algo, orq_ip,
                         orq_port):

            # Calculate hash corresponding to tbs_cert_dump	[Only SHA256]
            digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
            digest.update(tbs_cert_dump)
            digest = hexlify(digest.finalize())
            print("[Client] Hash: " + digest)

            # Send HTTP GET request to the orquestrator for signing
            target = "http://" + orq_ip + ":" + orq_port + "/signMessage/" + str(
                signing_private_key) + "?message=" + str(digest)
            r = requests.get(target)

            response = dict(json.loads(r.text))

            # Sign format must be bytearray
            print("Firma: " + str(response["sign"]))
            firma = unhexlify(response["sign"])
            return firma

        if self._self_signed is not True and self._issuer is None:
            raise ValueError(
                _pretty_message('''
                Certificate must be self-signed, or an issuer must be specified
                '''))

        if self._self_signed:
            self._issuer = self._subject

        if self._serial_number is None:
            time_part = int_to_bytes(int(time.time()))
            random_part = util.rand_bytes(4)
            self._serial_number = int_from_bytes(time_part + random_part)

        if self._begin_date is None:
            self._begin_date = datetime.now(timezone.utc)

        if self._end_date is None:
            self._end_date = self._begin_date + timedelta(365)

        if not self.ca:
            for ca_only_extension in set([
                    'policy_mappings', 'policy_constraints',
                    'inhibit_any_policy'
            ]):
                if ca_only_extension in self._other_extensions:
                    raise ValueError(
                        _pretty_message(
                            '''
                        Extension %s is only valid for CA certificates
                        ''', ca_only_extension))

        # The algorith is forced to be 'rsa'
        signature_algo = 'rsa'

        # Hash's algorithm limited to SHA256 (internally)
        signature_algorithm_id = '%s_%s' % (self._hash_algo, signature_algo)

        def _make_extension(name, value):
            return {
                'extn_id': name,
                'critical': self._determine_critical(name),
                'extn_value': value
            }

        extensions = []
        for name in sorted(self._special_extensions):
            value = getattr(self, '_%s' % name)
            if name == 'ocsp_no_check':
                value = core.Null() if value else None
            if value is not None:
                extensions.append(_make_extension(name, value))

        for name in sorted(self._other_extensions.keys()):
            extensions.append(
                _make_extension(name, self._other_extensions[name]))

        tbs_cert = x509.TbsCertificate({
            'version': 'v3',
            'serial_number': self._serial_number,
            'signature': {
                'algorithm': signature_algorithm_id
            },
            'issuer': self._issuer,
            'validity': {
                'not_before': x509.Time(name='utc_time',
                                        value=self._begin_date),
                'not_after': x509.Time(name='utc_time', value=self._end_date),
            },
            'subject': self._subject,
            'subject_public_key_info': self._subject_public_key,
            'extensions': extensions
        })

        # Function binding
        sign_func = rsa_mpc_sign
        print(orq_ip)
        print(orq_port)
        signature = sign_func(signing_private_key, tbs_cert.dump(),
                              self._hash_algo, orq_ip, orq_port)

        return x509.Certificate({
            'tbs_certificate': tbs_cert,
            'signature_algorithm': {
                'algorithm': signature_algorithm_id
            },
            'signature_value': signature
        })