예제 #1
0
파일: secret.py 프로젝트: mstarecek/spsdk
    def from_certificate(cls, cert: Certificate) -> "SrkItemRSA":
        """Create SRKItemRSA from certificate."""
        assert isinstance(cert, Certificate)

        flag = 0
        try:
            key_usage = cert.extensions.get_extension_for_class(
                KeyUsage)  # type:ignore
            assert isinstance(key_usage.value, KeyUsage)
            if key_usage.value.key_cert_sign:
                flag = 0x80
        except ExtensionNotFound:
            pass

        if isinstance(cert.public_key(), rsa.RSAPublicKey):
            public_key = cert.public_key()
            assert isinstance(public_key, rsa.RSAPublicKey)
            pub_key_numbers = public_key.public_numbers()
            assert isinstance(pub_key_numbers, rsa.RSAPublicNumbers)
            # get modulus and exponent of public key since we are RSA
            modulus_len = math.ceil(pub_key_numbers.n.bit_length() / 8)
            exponent_len = math.ceil(pub_key_numbers.e.bit_length() / 8)
            modulus = pub_key_numbers.n.to_bytes(modulus_len, "big")
            exponent = pub_key_numbers.e.to_bytes(exponent_len, "big")

            return cls(modulus, exponent, flag)
        raise NotImplementedSRKCertificate()
예제 #2
0
def verify(issuer: x509.Certificate, cert: x509.Certificate):
    """
    Verify certificate with its issuer
    """
    h = cert.signature_hash_algorithm
    issuer.public_key().verify(cert.signature, cert.tbs_certificate_bytes,
                               padding.PKCS1v15(), h)
예제 #3
0
    def _get_basic_certificate_text(cls,
                                    certificate: Certificate) -> List[str]:
        text_output = [
            cls._format_field(
                "SHA1 Fingerprint:",
                binascii.hexlify(certificate.fingerprint(
                    hashes.SHA1())).decode("ascii")),
            cls._format_field("Common Name:",
                              _get_name_as_short_text(certificate.subject)),
            cls._format_field("Issuer:",
                              _get_name_as_short_text(certificate.issuer)),
            cls._format_field("Serial Number:",
                              str(certificate.serial_number)),
            cls._format_field("Not Before:",
                              certificate.not_valid_before.date().isoformat()),
            cls._format_field("Not After:",
                              certificate.not_valid_after.date().isoformat()),
            cls._format_field("Public Key Algorithm:",
                              certificate.public_key().__class__.__name__),
        ]

        if certificate.signature_hash_algorithm:
            # The signature_hash_algorithm can be None if signature did not use separate hash (ED25519, ED448)
            # https://cryptography.io/en/latest/x509/reference/#cryptography.x509.Certificate.signature_hash_algorithm
            text_output.append(
                cls._format_field("Signature Algorithm:",
                                  certificate.signature_hash_algorithm.name))

        public_key = certificate.public_key()
        if isinstance(public_key, EllipticCurvePublicKey):
            text_output.append(
                cls._format_field("Key Size:", str(public_key.curve.key_size)))
            text_output.append(
                cls._format_field("Curve:", str(public_key.curve.name)))
        elif isinstance(public_key, RSAPublicKey):
            text_output.append(
                cls._format_field("Key Size:", str(public_key.key_size)))
            text_output.append(
                cls._format_field(
                    "Exponent:",
                    str(public_key.public_numbers().e)))  # type: ignore
        else:
            # DSA Key? https://github.com/nabla-c0d3/sslyze/issues/314
            pass

        try:
            # Print the SAN extension if there's one
            text_output.append(
                cls._format_field(
                    "DNS Subject Alternative Names:",
                    str(extract_dns_subject_alternative_names(certificate))))
        except KeyError:
            pass

        return text_output
예제 #4
0
def certificate_to_context(
        certificate: x509.Certificate) -> Common.Certificate:
    """
    certificate_to_context function
    Translates an X509 certificate into a Common.Certificate object

    :type certificate: ``x509.Certificate``
    :param oid: Certificate Extension OID

    :return: Certificate represented as a Common.Certificate object
    :rtype: ``Common.Certificate``
    """
    spkisha256 = hashes.Hash(hashes.SHA256(), backends.default_backend())
    spkisha256.update(certificate.public_key().public_bytes(
        encoding=serialization.Encoding.DER,
        format=serialization.PublicFormat.SubjectPublicKeyInfo))

    extensions_contexts: List[Common.CertificateExtension] = []
    for extension in certificate.extensions:
        extension_oid = cast(oid.ObjectIdentifier, extension.oid)
        extensions_contexts.append(
            extension_context(oid=extension_oid.dotted_string,
                              extension_name=extension_oid._name,
                              critical=extension.critical,
                              extension_value=extension.value))

    indicator = certificate.fingerprint(hashes.SHA256()).hex()
    cert = Common.Certificate(
        subject_dn=certificate.subject.rfc4514_string(),
        issuer_dn=certificate.issuer.rfc4514_string(),
        serial_number=str(certificate.serial_number),
        validity_not_before=certificate.not_valid_before.strftime(
            "%Y-%m-%dT%H:%M:%S.000Z"),
        validity_not_after=certificate.not_valid_after.strftime(
            "%Y-%m-%dT%H:%M:%S.000Z"),
        sha256=certificate.fingerprint(hashes.SHA256()).hex(),
        sha1=certificate.fingerprint(hashes.SHA1()).hex(),
        md5=certificate.fingerprint(hashes.MD5()).hex(),
        spki_sha256=spkisha256.finalize().hex(),
        extensions=extensions_contexts,
        signature_algorithm=certificate.signature_hash_algorithm.
        name,  # type: ignore[union-attr]
        signature=certificate.signature.hex(),
        publickey=public_key_context(certificate.public_key()),  # type: ignore
        dbot_score=Common.DBotScore(indicator=indicator,
                                    indicator_type=DBotScoreType.CERTIFICATE,
                                    integration_name="X509Certificate",
                                    score=Common.DBotScore.NONE),
        pem=certificate.public_bytes(
            serialization.Encoding.PEM).decode('ascii'))

    return cert
def key_type_and_size(cert: x509.Certificate) -> List[Tuple[bool, str]]:
    checks = []

    # get the public key
    pk = cert.public_key()

    # check the keypair type
    exp_pk_type = 'RSA'
    pk_type = 'RSA' if isinstance(pk, rsa.RSAPublicKey) else 'NOT ALLOWED'
    msg = 'The keypair must be %s' % exp_pk_type
    res = FAILURE if pk_type != exp_pk_type else SUCCESS
    checks.append((res, msg))

    # check the key size
    min_size = 2048
    size = pk.key_size

    msg = ('The key size must be greater than or equal to %d (now: %d)'
           % (min_size, size))
    res = FAILURE if size < min_size else SUCCESS
    checks.append((res, msg))

    msg = ('The key size must be one of %s (now: %d)'
           % (ALLOWED_SIZES, size))
    res = FAILURE if size not in ALLOWED_SIZES else SUCCESS
    checks.append((res, msg))

    return checks
예제 #6
0
    def _validate(crl: x509.CertificateRevocationList,
                  issuer: x509.Certificate):
        """Validates a crl against a issuer certificate"""

        if crl.next_update is None:
            # rfc5280: Conforming CRL issuers MUST
            # include the nextUpdate field in all CRLs.
            raise CouldNotGetValidCRLError("CRL is missing next update field")

        if not (crl.next_update > datetime.utcnow()
                and crl.last_update < datetime.utcnow()):
            raise CouldNotGetValidCRLError(
                f"CRL failed date validation. "
                f"Last update: '{crl.last_update}' Next Update: '{crl.next_update}'"
            )

        if not crl.issuer == issuer.subject:
            raise CouldNotGetValidCRLError(
                f"CRL failed issuer validation. "
                f"Expected: {issuer.subject.rfc4514_string()} "
                f"Actual: {crl.issuer.rfc4514_string()}.")

        # cast because mypy. The type of key is checked
        # when it is loaded in CertRetriever.
        if not crl.is_signature_valid(cast(RSAPublicKey, issuer.public_key())):
            raise CouldNotGetValidCRLError("CRL failed signature validation")
예제 #7
0
파일: Crypto.py 프로젝트: LeGroupeDeFer/IAM
    def _save(
            cls, key: PrivateKey, cert: x509.Certificate, directory: str,
            name: str, key_format: Encoding
    ) -> ((str, bytes), (str, bytes), (str, bytes)):

        private_file = f'{name}.{key_format.name.lower()}'
        private_path = join(directory, private_file)
        private_bytes = key.private_bytes(key_format, PrivateFormat.PKCS8,
                                          NoEncryption())

        public_file = f'{name}.pub.{key_format.name.lower()}'
        public_path = join(directory, public_file)
        public_bytes = cert.public_key().public_bytes(key_format,
                                                      PublicFormat.PKCS1)

        cert_file = f'{name}.cert.{key_format.name.lower()}'
        cert_path = join(directory, cert_file)
        cert_bytes = cert.public_bytes(key_format)

        serialized = ((private_path, private_bytes),
                      (public_path, public_bytes), (cert_path, cert_bytes))

        for file_path, file_bytes in serialized:
            with open(file_path, 'wb') as out:
                out.write(file_bytes)

        return serialized
예제 #8
0
 def assertBasic(  # pylint: disable=invalid-name
     self, cert: x509.Certificate, algo: typing.Type[hashes.HashAlgorithm] = hashes.SHA256
 ) -> None:
     """Assert some basic key properties."""
     self.assertEqual(cert.version, x509.Version.v3)
     self.assertIsInstance(cert.public_key(), rsa.RSAPublicKey)
     self.assertIsInstance(cert.signature_hash_algorithm, algo)
예제 #9
0
파일: secret.py 프로젝트: mstarecek/spsdk
 def from_certificate(cls, cert: Certificate) -> "SrkItem":
     """Pick up the right implementation of an SRK item."""
     assert isinstance(cert, Certificate)
     public_key = cert.public_key()
     if isinstance(public_key, rsa.RSAPublicKey):
         return SrkItemRSA.from_certificate(cert)
     raise NotImplementedSRKCertificate()
예제 #10
0
def x509_certificate_to_json(certificate: x509.Certificate) -> Dict[str, Any]:
    public_key = certificate.public_key()

    try:
        public_key_size = public_key.key_size  # type: ignore
    except AttributeError:
        public_key_size = None

    public_key_json = _PublicKeyAsJson(
        algorithm=public_key.__class__.__name__,
        key_size=public_key_size,
        # EC-only fields
        ec_curve_name=public_key.curve.name if isinstance(public_key, EllipticCurvePublicKey) else None,
        ec_x=public_key.public_numbers().x if isinstance(public_key, EllipticCurvePublicKey) else None,
        ec_y=public_key.public_numbers().y if isinstance(public_key, EllipticCurvePublicKey) else None,
        # RSA-only fields
        rsa_e=public_key.public_numbers().e if isinstance(public_key, RSAPublicKey) else None,
        rsa_n=public_key.public_numbers().n if isinstance(public_key, RSAPublicKey) else None,
    )

    signature_hash_algorithm: Optional[_HashAlgorithmAsJson]
    if certificate.signature_hash_algorithm:
        signature_hash_algorithm = _HashAlgorithmAsJson(
            name=certificate.signature_hash_algorithm.name,
            digest_size=certificate.signature_hash_algorithm.digest_size,
        )
    else:
        signature_hash_algorithm = None

    # We may get garbage/invalid certificates so we need to handle ValueErrors.
    # See https://github.com/nabla-c0d3/sslyze/issues/403 for more information
    subject_field: Optional[x509.name.Name]
    try:
        subject_field = certificate.subject
    except ValueError:
        subject_field = None

    issuer_field: Optional[x509.name.Name]
    try:
        issuer_field = certificate.issuer
    except ValueError:
        issuer_field = None

    cert_as_json = _X509CertificateAsJson(
        as_pem=certificate.public_bytes(Encoding.PEM).decode("ascii"),
        hpkp_pin=b64encode(get_public_key_sha256(certificate)).decode("ascii"),
        fingerprint_sha1=b64encode(certificate.fingerprint(hashes.SHA1())).decode("ascii"),
        fingerprint_sha256=b64encode(certificate.fingerprint(hashes.SHA256())).decode("ascii"),
        serial_number=certificate.serial_number,
        not_valid_before=certificate.not_valid_before,
        not_valid_after=certificate.not_valid_after,
        subject_alternative_name=_SubjAltNameAsJson(dns=extract_dns_subject_alternative_names(certificate)),
        signature_hash_algorithm=signature_hash_algorithm,
        signature_algorithm_oid=certificate.signature_algorithm_oid,
        subject=subject_field,
        issuer=issuer_field,
        public_key=public_key_json,
    )
    return asdict(cert_as_json)
예제 #11
0
파일: utils.py 프로젝트: HENNGE/minisignxml
def verify(signature: bytes, data: bytes, certificate: Certificate,
           hasher: HashAlgorithm) -> None:
    key = certificate.public_key()
    if not isinstance(key, RSAPublicKey):
        raise TypeError(
            f"Only certificates with RSA Keys are supported. Got {key!r} instead."
        )
    key.verify(signature, data, padding.PKCS1v15(), hasher)
예제 #12
0
def _check_ocsp_response_signature(response_ocsp: 'ocsp.OCSPResponse',
                                   issuer_cert: x509.Certificate, cert_path: str) -> None:
    """Verify an OCSP response signature against certificate issuer or responder"""
    def _key_hash(cert: x509.Certificate) -> bytes:
        return x509.SubjectKeyIdentifier.from_public_key(cert.public_key()).digest

    if (response_ocsp.responder_name == issuer_cert.subject
            or response_ocsp.responder_key_hash == _key_hash(issuer_cert)):
        # Case where the OCSP responder is also the certificate issuer
        logger.debug('OCSP response for certificate %s is signed by the certificate\'s issuer.',
                     cert_path)
        responder_cert = issuer_cert
    else:
        # Case where the OCSP responder is not the certificate issuer
        logger.debug('OCSP response for certificate %s is delegated to an external responder.',
                     cert_path)

        responder_certs = [cert for cert in response_ocsp.certificates
                           if response_ocsp.responder_name == cert.subject or \
                              response_ocsp.responder_key_hash == _key_hash(cert)]
        if not responder_certs:
            raise AssertionError('no matching responder certificate could be found')

        # We suppose here that the ACME server support only one certificate in the OCSP status
        # request. This is currently the case for LetsEncrypt servers.
        # See https://github.com/letsencrypt/boulder/issues/2331
        responder_cert = responder_certs[0]

        if responder_cert.issuer != issuer_cert.subject:
            raise AssertionError('responder certificate is not signed '
                                 'by the certificate\'s issuer')

        try:
            extension = responder_cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
            delegate_authorized = x509.oid.ExtendedKeyUsageOID.OCSP_SIGNING in extension.value
        except (x509.ExtensionNotFound, IndexError):
            delegate_authorized = False
        if not delegate_authorized:
            raise AssertionError('responder is not authorized by issuer to sign OCSP responses')

        # Following line may raise UnsupportedAlgorithm
        chosen_cert_hash = responder_cert.signature_hash_algorithm
        # For a delegate OCSP responder, we need first check that its certificate is effectively
        # signed by the certificate issuer.
        crypto_util.verify_signed_payload(issuer_cert.public_key(), responder_cert.signature,
                                          responder_cert.tbs_certificate_bytes, chosen_cert_hash)

    # Following line may raise UnsupportedAlgorithm
    chosen_response_hash = response_ocsp.signature_hash_algorithm
    # We check that the OSCP response is effectively signed by the responder
    # (an authorized delegate one or the certificate issuer itself).
    if not chosen_response_hash:
        raise AssertionError("no signature hash algorithm defined")
    crypto_util.verify_signed_payload(responder_cert.public_key(), response_ocsp.signature,
                                      response_ocsp.tbs_response_bytes, chosen_response_hash)
예제 #13
0
def dummy_cert(
    privkey: rsa.RSAPrivateKey,
    cacert: x509.Certificate,
    commonname: Optional[str],
    sans: List[str],
    organization: Optional[str] = None,
) -> Cert:
    """
        Generates a dummy certificate.

        privkey: CA private key
        cacert: CA certificate
        commonname: Common name for the generated certificate.
        sans: A list of Subject Alternate Names.
        organization: Organization name for the generated certificate.

        Returns cert if operation succeeded, None if not.
    """
    builder = x509.CertificateBuilder()
    builder = builder.issuer_name(cacert.subject)
    builder = builder.add_extension(x509.ExtendedKeyUsage(
        [ExtendedKeyUsageOID.SERVER_AUTH]),
                                    critical=False)
    builder = builder.public_key(cacert.public_key())

    now = datetime.datetime.now()
    builder = builder.not_valid_before(now - datetime.timedelta(days=2))
    builder = builder.not_valid_after(now + CERT_EXPIRY)

    subject = []
    is_valid_commonname = (commonname is not None and len(commonname) < 64)
    if is_valid_commonname:
        assert commonname is not None
        subject.append(x509.NameAttribute(NameOID.COMMON_NAME, commonname))
    if organization is not None:
        assert organization is not None
        subject.append(
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization))
    builder = builder.subject_name(x509.Name(subject))
    builder = builder.serial_number(x509.random_serial_number())

    ss: List[x509.GeneralName] = []
    for x in sans:
        try:
            ip = ipaddress.ip_address(x)
        except ValueError:
            ss.append(x509.DNSName(x))
        else:
            ss.append(x509.IPAddress(ip))
    # RFC 5280 §4.2.1.6: subjectAltName is critical if subject is empty.
    builder = builder.add_extension(x509.SubjectAlternativeName(ss),
                                    critical=not is_valid_commonname)
    cert = builder.sign(private_key=privkey,
                        algorithm=hashes.SHA256())  # type: ignore
    return Cert(cert)
예제 #14
0
def get_spki_hash(certificate: Certificate) -> bytes:
    """
    Get the public key hash, as per RFC 7469: base64 of sha256 of the public
    key encoded in DER + Subject Public Key Info format.

    We use the URL-safe base64 variant, since this is typically found in NURLs.
    """
    public_key_bytes = certificate.public_key().public_bytes(
        Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
    return urlsafe_b64encode(
        sha256(public_key_bytes).digest()).strip().rstrip(b"=")
예제 #15
0
파일: receipt.py 프로젝트: lynshi/CCF
def verify(root: str, signature: str, cert: Certificate):
    """
    Verify signature over root of Merkle Tree
    """
    sig = base64.b64decode(signature)
    pk = cert.public_key()
    assert isinstance(pk, ec.EllipticCurvePublicKey)
    pk.verify(
        sig,
        bytes.fromhex(root),
        ec.ECDSA(utils.Prehashed(hashes.SHA256())),
    )
예제 #16
0
def check_endorsement(endorsee: Certificate, endorser: Certificate):
    """
    Check endorser has endorsed endorsee
    """
    digest_algo = endorsee.signature_hash_algorithm
    assert digest_algo
    digester = hashes.Hash(digest_algo)
    digester.update(endorsee.tbs_certificate_bytes)
    digest = digester.finalize()
    endorser_pk = endorser.public_key()
    assert isinstance(endorser_pk, ec.EllipticCurvePublicKey)
    endorser_pk.verify(endorsee.signature, digest,
                       ec.ECDSA(utils.Prehashed(digest_algo)))
예제 #17
0
def x509_certificate_to_json(certificate: x509.Certificate) -> Dict[str, Any]:
    result: Dict[str, Union[None, str, Dict[str, Any]]] = {
        # Add general info
        "as_pem": certificate.public_bytes(Encoding.PEM).decode("ascii"),
        "hpkp_pin": b64encode(
            get_public_key_sha256(certificate)).decode("utf-8"),  # RFC 7469
        # Add some of the fields of the cert
        "serialNumber": str(certificate.serial_number),
        "notBefore": certificate.not_valid_before.isoformat(),
        "notAfter": certificate.not_valid_after.isoformat(),
        "subjectAlternativeName": {
            "DNS": extract_dns_subject_alternative_names(certificate)
        },
    }

    if certificate.signature_hash_algorithm:
        # The signature_hash_algorithm can be None if signature did not use separate hash (ED25519, ED448)
        # https://cryptography.io/en/latest/x509/reference/#cryptography.x509.Certificate.signature_hash_algorithm
        result[
            "signatureAlgorithm"] = certificate.signature_hash_algorithm.name
    else:
        result["signatureAlgorithm"] = None

    # We may get garbage/invalid certificates so we need to handle ValueErrors.
    # See https://github.com/nabla-c0d3/sslyze/issues/403 for more information
    for name_field in ["subject", "issuer"]:
        try:
            result[name_field] = getattr(certificate, name_field)
        except ValueError as e:
            x509name_as_json = _X509NameAsJson(rfc4514_string=None,
                                               attributes=None,
                                               parsing_error=e.args[0])
            result[name_field] = asdict(x509name_as_json)

    # Add some info about the public key
    public_key = certificate.public_key()
    public_key_dict: Dict[str, Union[str, int]] = {
        "algorithm": public_key.__class__.__name__
    }
    if isinstance(public_key, EllipticCurvePublicKey):
        public_key_dict["size"] = public_key.curve.key_size
        public_key_dict["curve"] = public_key.curve.name
    elif isinstance(public_key, RSAPublicKey):
        public_key_dict["size"] = public_key.key_size
        public_key_dict["exponent"] = public_key.public_numbers().e
    else:
        # DSA Key? https://github.com/nabla-c0d3/sslyze/issues/402
        pass

    result["publicKey"] = public_key_dict
    return result
예제 #18
0
def matches_key_and_cert(priv_key: bytes, cert: Certificate) -> bool:
    """Verify that given private key matches the public certificate.

    :param priv_key: to be tested; decrypted binary data in PEM format
    :param cert: to be used for verification
    :return: True if yes; False otherwise
    """
    signature = crypto_backend().rsa_sign(priv_key, bytes())
    assert isinstance(cert, Certificate)
    cert_pub_key = cert.public_key()  # public key of last certificate
    assert isinstance(cert_pub_key, RSAPublicKey)
    return crypto_backend().rsa_verify(cert_pub_key.public_numbers().n,
                                       cert_pub_key.public_numbers().e,
                                       signature, bytes())
예제 #19
0
    def _validate_cert_against_issuer(cert: x509.Certificate,
                                      issuer: x509.Certificate) -> bool:
        """Validates a certificate against it's (alleged) issuer"""

        if cert.issuer != issuer.subject:
            return False
        try:
            # casts because mypy. The type of key is checked
            # when it is loaded in CertRetriever.
            cast(RSAPublicKey, issuer.public_key()).verify(
                cert.signature,
                cert.tbs_certificate_bytes,
                PKCS1v15(),
                cast(HashAlgorithm, cert.signature_hash_algorithm),
            )
        except InvalidSignature:
            return False
        return True
예제 #20
0
    def from_orm(cls, certificate: x509.Certificate) -> "_CertificateAsJson":
        signature_hash_algorithm: Optional[_HashAlgorithmAsJson]
        if certificate.signature_hash_algorithm:
            signature_hash_algorithm = _HashAlgorithmAsJson.from_orm(
                certificate.signature_hash_algorithm)
        else:
            signature_hash_algorithm = None

        # We may get garbage/invalid certificates so we need to handle ValueErrors.
        # See https://github.com/nabla-c0d3/sslyze/issues/403 for more information
        subject_field: Optional[_X509NameAsJson]
        try:
            subject_field = _X509NameAsJson.from_orm(certificate.subject)
        except ValueError:
            subject_field = None

        issuer_field: Optional[_X509NameAsJson]
        try:
            issuer_field = _X509NameAsJson.from_orm(certificate.issuer)
        except ValueError:
            issuer_field = None

        return cls(
            as_pem=certificate.public_bytes(Encoding.PEM).decode("ascii"),
            hpkp_pin=b64encode(
                get_public_key_sha256(certificate)).decode("ascii"),
            fingerprint_sha1=b64encode(certificate.fingerprint(
                hashes.SHA1())).decode("ascii"),
            fingerprint_sha256=b64encode(
                certificate.fingerprint(hashes.SHA256())).decode("ascii"),
            serial_number=certificate.serial_number,
            not_valid_before=certificate.not_valid_before,
            not_valid_after=certificate.not_valid_after,
            subject_alternative_name=_SubjAltNameAsJson(
                dns=extract_dns_subject_alternative_names(certificate)),
            signature_hash_algorithm=signature_hash_algorithm,
            signature_algorithm_oid=certificate.signature_algorithm_oid,
            subject=subject_field,
            issuer=issuer_field,
            public_key=_PublicKeyAsJson.from_orm(certificate.public_key()),
        )
예제 #21
0
def sign_csr(
    csr: CertificateSigningRequest, ca_cert: Certificate,
    key: EllipticCurvePrivateKey, expiration_date: date,
    custom_extensions: Iterable[Union[KeyUsage, UnrecognizedExtension,
                                      BasicConstraints]]
) -> Certificate:
    """
    Sign a CSR with CA credentials.
    :param csr: the CSR
    :param ca_cert: the CA certificate
    :param key: the CA private key
    :param expiration_date: expiration date
    :param custom_extensions: custom extensions to be added to the certificate
    :return: a certificate object
    """
    issuer = ca_cert.subject
    now = datetime.utcnow()
    cert_builder = CertificateBuilder().issuer_name(issuer).subject_name(
        csr.subject).public_key(csr.public_key()).serial_number(
            x509.random_serial_number()).not_valid_before(now).not_valid_after(
                datetime.combine(expiration_date, time(), None)).add_extension(
                    extension=AuthorityKeyIdentifier.from_issuer_public_key(
                        ca_cert.public_key()),
                    critical=False)
    try:
        cert_builder = cert_builder.add_extension(
            csr.extensions.get_extension_for_class(
                SubjectAlternativeName).value,
            critical=False)
    except ExtensionNotFound:
        pass
    for extension in custom_extensions:
        if isinstance(extension, UnrecognizedExtension):
            critical = False
        else:
            critical = True
        # pyre-fixme[6]: Expected `ExtensionType` for 1st param but got
        #  `Union[BasicConstraints, KeyUsage, UnrecognizedExtension]`.
        cert_builder = cert_builder.add_extension(extension, critical=critical)
    return cert_builder.sign(key, SHA256(), backends.default_backend())
예제 #22
0
    def storePublicKey(self, certName: str, cert: x509.Certificate) -> None:
        path = self.conf.getCertPath(certName=certName,
                                     ext="signed_certificate")
        certConf = self.conf.getCert(certName=certName)
        format = certConf.get("public_key").get("format", None)

        try:
            if type(format) == str and format.lower() == "openssh":
                content = serialization.ssh.serialize_ssh_public_key(
                    cert.public_key())
                with open(path, "wb") as f:
                    f.write(content)
            # DER or PEM encodings
            else:
                encoding, _ = self._getParamsForPublicBytes(certConf=certConf)
                content = cert.public_bytes(encoding)
                with open(path, "wb") as f:
                    f.write(content)

        except OSError:
            logging.error(f"can't save public key in {path}")
            sys.exit()
예제 #23
0
    def _build_recipient_info(self, symmetric_key: bytes,
                              recipient: x509.Certificate) -> RecipientInfo:
        """Build an ASN.1 data structure containing the encrypted symmetric key for the encrypted_content.
        
        NOTE: The recipient is always identified by issuerAndSerialNumber
        NOTE: 

        Args:
            symmetric_key (bytes): Typically the randomly generated 3DES key for the encrypted_content.
            recipient (x509.Certificate): The certificate which will be used to encrypt the symmetric key.

        Returns:
              RecipientInfo: Instance of ASN.1 data structure with required attributes and encrypted key.
        """
        encrypted_symkey = recipient.public_key().encrypt(
            symmetric_key, asympad.PKCS1v15())
        asn1cert = parse_certificate(
            recipient.public_bytes(serialization.Encoding.DER))
        ias = IssuerAndSerialNumber({
            'issuer': asn1cert.issuer,
            'serial_number': asn1cert.serial_number
        })

        ri = RecipientInfo(
            'ktri',
            KeyTransRecipientInfo({
                'version':
                0,
                'rid':
                RecipientIdentifier('issuer_and_serial_number', ias),
                'key_encryption_algorithm':
                KeyEncryptionAlgorithm(
                    {'algorithm': KeyEncryptionAlgorithmId('rsa')}),
                'encrypted_key':
                encrypted_symkey,
            }))

        return ri
예제 #24
0
def is_pareja(cer: x509.Certificate, private_key: rsa.RSAPrivateKey) -> bool:
    encoding = serialization.Encoding.PEM
    fmt = serialization.PublicFormat.PKCS1

    return cer.public_key().public_bytes(encoding, fmt) == private_key.public_key().public_bytes(encoding, fmt)
예제 #25
0
 def _key_hash(cert: x509.Certificate) -> bytes:
     return x509.SubjectKeyIdentifier.from_public_key(
         cert.public_key()).digest
예제 #26
0
def _keyid(cert: Certificate) -> str:
    pub = cert.public_key()
    h = hashlib.sha256()
    h.update(pub.public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo))
    return h.hexdigest()
예제 #27
0
def get_public_key_sha256(certificate: x509.Certificate) -> bytes:
    pub_bytes = certificate.public_key().public_bytes(encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo)
    digest = sha256(pub_bytes).digest()
    return digest
예제 #28
0
    def _check_certificate_properties(
            self, certificate: Certificate,
            ocsp_stapling: bool) -> Tuple[List[str], List[str], str]:
        errors = []
        warnings = []

        # check certificate lifespan
        lifespan = certificate.not_valid_after - certificate.not_valid_before
        if self.target_profile["maximum_certificate_lifespan"] < lifespan.days:
            errors.append(
                f"Certificate lifespan too long (is {lifespan.days}, "
                f"should be less than {self.target_profile['maximum_certificate_lifespan']})"
            )
        elif (self.target_profile["recommended_certificate_lifespan"]
              and self.target_profile["recommended_certificate_lifespan"] <
              lifespan.days):
            warnings.append(
                f"Certificate lifespan is {lifespan.days} days but the recommended lifespan is {self.target_profile['recommended_certificate_lifespan']} days."
            )

        current_time = datetime.now()
        days_before_expire = certificate.not_valid_after - current_time
        if days_before_expire.days < self.cert_expire_warning:
            warnings.append(
                f"Certificate expires in {days_before_expire.days} days")

        # check certificate public key type
        pub_key_type = self._cert_type_string(certificate.public_key())
        if pub_key_type.lower(
        ) not in self.target_profile["certificate_types"]:
            errors.append(
                f"Wrong certificate type (is {pub_key_type}), "
                f"should be one of {self.target_profile['certificate_types']}")

        # check key property
        pub_key = certificate.public_key()
        if (isinstance(pub_key, rsa.RSAPublicKey)
                and self.target_profile["rsa_key_size"]
                and pub_key.key_size != self.target_profile["rsa_key_size"]):
            errors.append(
                f"RSA certificate has wrong key size (is {pub_key.key_size}, "
                f"should be {self.target_profile['rsa_key_size']})")
        elif (isinstance(pub_key, ec.EllipticCurvePublicKey)
              and self.target_profile["certificate_curves"]
              and pub_key.curve.name
              not in self.target_profile["certificate_curves_preprocessed"]):
            errors.append(
                f"ECDSA certificate uses wrong curve "
                f"(is {pub_key.curve.name}, should be one of {self.target_profile['certificate_curves']})"
            )

        # check certificate signature
        if (certificate.signature_algorithm_oid._name
                not in self.target_profile["certificate_signatures"]):
            errors.append(
                f"Certificate has a wrong signature (is {certificate.signature_algorithm_oid._name}), "
                f"should be one of {self.target_profile['certificate_signatures']}"
            )

        # check if ocsp stabling is supported
        if ocsp_stapling != self.target_profile["ocsp_staple"]:
            if self.target_profile["ocsp_staple"]:
                errors.append(f"OCSP stapling must be supported")
            else:
                errors.append(f"OCSP stapling should not be supported")

        return errors, warnings, pub_key_type