From c7b29b86cd20fe62fa199eb8fb2c87f88133a5ab Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 1 Sep 2016 09:17:21 +0800 Subject: add support for signature_algorithm_oid to cert, CSR, and CRL (#3124) * add support for signature_algorithm_oid to cert, CSR, and CRL * refactor _SIG_OIDS_TO_HASH to use ObjectIdentifiers and use that --- CHANGELOG.rst | 9 +++++ docs/x509/reference.rst | 46 +++++++++++++++++++++ src/cryptography/hazmat/backends/openssl/x509.py | 51 +++++++++++++++--------- src/cryptography/x509/base.py | 18 +++++++++ src/cryptography/x509/oid.py | 28 ++++++------- tests/test_x509.py | 14 ++++++- 6 files changed, 133 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fabc9139..4ec7d72e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,15 @@ Changelog * Added support for :class:`~cryptography.hazmat.primitives.hashes.BLAKE2b` and :class:`~cryptography.hazmat.primitives.hashes.BLAKE2s` when using OpenSSL 1.1.0. +* Added + :attr:`~cryptography.x509.Certificate.signature_algorithm_oid` support to + :class:`~cryptography.x509.Certificate`. +* Added + :attr:`~cryptography.x509.CertificateSigningRequest.signature_algorithm_oid` + support to :class:`~cryptography.x509.CertificateSigningRequest`. +* Added + :attr:`~cryptography.x509.CertificateRevocationList.signature_algorithm_oid` + support to :class:`~cryptography.x509.CertificateRevocationList`. 1.5 - 2016-08-26 ~~~~~~~~~~~~~~~~ diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index ea32c3b7..bd88b023 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -354,6 +354,22 @@ X.509 Certificate Object >>> isinstance(cert.signature_hash_algorithm, hashes.SHA256) True + .. attribute:: signature_algorithm_oid + + .. versionadded:: 1.6 + + :type: :class:`ObjectIdentifier` + + Returns the :class:`ObjectIdentifier` of the signature algorithm used + to sign the certificate. This will be one of the OIDs from + :class:`~cryptography.x509.oid.SignatureAlgorithmOID`. + + + .. doctest:: + + >>> cert.signature_algorithm_oid + + .. attribute:: extensions :type: :class:`Extensions` @@ -464,6 +480,21 @@ X.509 CRL (Certificate Revocation List) Object >>> isinstance(crl.signature_hash_algorithm, hashes.SHA256) True + .. attribute:: signature_algorithm_oid + + .. versionadded:: 1.6 + + :type: :class:`ObjectIdentifier` + + Returns the :class:`ObjectIdentifier` of the signature algorithm used + to sign the CRL. This will be one of the OIDs from + :class:`~cryptography.x509.oid.SignatureAlgorithmOID`. + + .. doctest:: + + >>> crl.signature_algorithm_oid + + .. attribute:: issuer :type: :class:`Name` @@ -711,6 +742,21 @@ X.509 CSR (Certificate Signing Request) Object >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) True + .. attribute:: signature_algorithm_oid + + .. versionadded:: 1.6 + + :type: :class:`ObjectIdentifier` + + Returns the :class:`ObjectIdentifier` of the signature algorithm used + to sign the request. This will be one of the OIDs from + :class:`~cryptography.x509.oid.SignatureAlgorithmOID`. + + .. doctest:: + + >>> csr.signature_algorithm_oid + + .. attribute:: extensions :type: :class:`Extensions` diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 6f7270c8..1f63d85f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -107,12 +107,7 @@ class _Certificate(object): @property def signature_hash_algorithm(self): - alg = self._backend._ffi.new("X509_ALGOR **") - self._backend._lib.X509_get0_signature( - self._backend._ffi.NULL, alg, self._x509 - ) - self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) - oid = _obj2txt(self._backend, alg[0].algorithm) + oid = self.signature_algorithm_oid try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -120,6 +115,16 @@ class _Certificate(object): "Signature algorithm OID:{0} not recognized".format(oid) ) + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_get0_signature( + self._backend._ffi.NULL, alg, self._x509 + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + @property def extensions(self): return _CERTIFICATE_EXTENSION_PARSER.parse(self._backend, self._x509) @@ -223,12 +228,7 @@ class _CertificateRevocationList(object): @property def signature_hash_algorithm(self): - alg = self._backend._ffi.new("X509_ALGOR **") - self._backend._lib.X509_CRL_get0_signature( - self._x509_crl, self._backend._ffi.NULL, alg - ) - self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) - oid = _obj2txt(self._backend, alg[0].algorithm) + oid = self.signature_algorithm_oid try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -236,6 +236,16 @@ class _CertificateRevocationList(object): "Signature algorithm OID:{0} not recognized".format(oid) ) + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_CRL_get0_signature( + self._x509_crl, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + @property def issuer(self): issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl) @@ -355,12 +365,7 @@ class _CertificateSigningRequest(object): @property def signature_hash_algorithm(self): - alg = self._backend._ffi.new("X509_ALGOR **") - self._backend._lib.X509_REQ_get0_signature( - self._x509_req, self._backend._ffi.NULL, alg - ) - self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) - oid = _obj2txt(self._backend, alg[0].algorithm) + oid = self.signature_algorithm_oid try: return x509._SIG_OIDS_TO_HASH[oid] except KeyError: @@ -368,6 +373,16 @@ class _CertificateSigningRequest(object): "Signature algorithm OID:{0} not recognized".format(oid) ) + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_REQ_get0_signature( + self._x509_req, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + @property def extensions(self): x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 156bc493..498ccbb9 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -125,6 +125,12 @@ class Certificate(object): in the certificate. """ + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + @abc.abstractproperty def extensions(self): """ @@ -189,6 +195,12 @@ class CertificateRevocationList(object): in the certificate. """ + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + @abc.abstractproperty def issuer(self): """ @@ -277,6 +289,12 @@ class CertificateSigningRequest(object): in the certificate. """ + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + @abc.abstractproperty def extensions(self): """ diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index 48e9d696..17fa42e3 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -135,20 +135,20 @@ class SignatureAlgorithmOID(object): DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") _SIG_OIDS_TO_HASH = { - SignatureAlgorithmOID.RSA_WITH_MD5.dotted_string: hashes.MD5(), - SignatureAlgorithmOID.RSA_WITH_SHA1.dotted_string: hashes.SHA1(), - SignatureAlgorithmOID.RSA_WITH_SHA224.dotted_string: hashes.SHA224(), - SignatureAlgorithmOID.RSA_WITH_SHA256.dotted_string: hashes.SHA256(), - SignatureAlgorithmOID.RSA_WITH_SHA384.dotted_string: hashes.SHA384(), - SignatureAlgorithmOID.RSA_WITH_SHA512.dotted_string: hashes.SHA512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA1.dotted_string: hashes.SHA1(), - SignatureAlgorithmOID.ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(), - SignatureAlgorithmOID.DSA_WITH_SHA1.dotted_string: hashes.SHA1(), - SignatureAlgorithmOID.DSA_WITH_SHA224.dotted_string: hashes.SHA224(), - SignatureAlgorithmOID.DSA_WITH_SHA256.dotted_string: hashes.SHA256() + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256() } diff --git a/tests/test_x509.py b/tests/test_x509.py index e281579b..dcfbe4fd 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -31,7 +31,8 @@ from cryptography.hazmat.primitives.asymmetric.utils import ( decode_dss_signature ) from cryptography.x509.oid import ( - AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, NameOID + AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, + NameOID, SignatureAlgorithmOID ) from .hazmat.primitives.fixtures_dsa import DSA_KEY_2048 @@ -75,6 +76,10 @@ class TestCertificateRevocationList(object): fingerprint = binascii.hexlify(crl.fingerprint(hashes.SHA1())) assert fingerprint == b"3234b0cb4c0cedf6423724b736729dcfc9e441ef" assert isinstance(crl.signature_hash_algorithm, hashes.SHA256) + assert ( + crl.signature_algorithm_oid == + SignatureAlgorithmOID.RSA_WITH_SHA256 + ) def test_load_der_crl(self, backend): crl = _load_cert( @@ -493,6 +498,9 @@ class TestRSACertificate(object): fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1())) assert fingerprint == b"2b619ed04bfc9c3b08eb677d272192286a0947a8" assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) + assert ( + cert.signature_algorithm_oid == SignatureAlgorithmOID.RSA_WITH_SHA1 + ) def test_cert_serial_number(self, backend): cert = _load_cert( @@ -1053,6 +1061,10 @@ class TestRSACertificateRequest(object): def test_load_rsa_certificate_request(self, path, loader_func, backend): request = _load_cert(path, loader_func, backend) assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert ( + request.signature_algorithm_oid == + SignatureAlgorithmOID.RSA_WITH_SHA1 + ) public_key = request.public_key() assert isinstance(public_key, rsa.RSAPublicKey) subject = request.subject -- cgit v1.2.3