From 8802a5bae7138d10c289361e5204fb1ea72fc099 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 13 Feb 2015 12:06:57 -0600 Subject: implement signature_hash_algorithm instead --- CHANGELOG.rst | 2 +- docs/spelling_wordlist.txt | 1 + docs/x509.rst | 15 ++++++++------- src/cryptography/hazmat/backends/openssl/x509.py | 12 +++++++++++- src/cryptography/x509.py | 23 ++++++++++++++++++++--- tests/test_x509.py | 18 ++++++++++++++---- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index df78acd3..f903b7f9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,7 @@ Changelog * :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` can now load elliptic curve public keys. * Added - :attr:`~cryptography.x509.Certificate.signature_algorithm` support to + :attr:`~cryptography.x509.Certificate.signature_hash_algorithm` support to :class:`~cryptography.x509.Certificate`. * Added :func:`~cryptography.hazmat.primitives.asymmetric.rsa.rsa_recover_prime_factors` diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index fefd26b3..ddd37897 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -51,3 +51,4 @@ Ubuntu unencrypted unpadded unpadding +Verisign diff --git a/docs/x509.rst b/docs/x509.rst index 8043b367..193b8452 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -182,18 +182,19 @@ X.509 Certificate Object The :class:`Name` of the subject. - .. attribute:: signature_algorithm + .. attribute:: signature_hash_algorithm - :type: :class:`ObjectIdentifier` + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - An :class:`ObjectIdentifier` instance corresponding to the signature - algorithm used to sign the certificate. This is both the digest - used as well as the asymmetric type. + A :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + corresponding to the hash algorithm used within the certificate + signature. .. doctest:: - >>> cert.signature_algorithm - + >>> from cryptography.hazmat.primitives import hashes + >>> isinstance(cert.signature_hash_algorithm, hashes.SHA256) + True .. class:: Name diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index a3dddc49..989a9dd7 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -16,6 +16,7 @@ from __future__ import absolute_import, division, print_function import datetime from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.primitives import hashes @@ -138,7 +139,16 @@ class _Certificate(object): return x509.Name(attributes) @property - def signature_algorithm(self): + def signature_hash_algorithm(self): + oid = self._signature_algorithm() + try: + return x509._SIG_OIDS_TO_HASH[oid.dotted_string] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm {0} not recognized".format(oid) + ) + + def _signature_algorithm(self): buf_len = 50 buf = self._backend._ffi.new("char[]", buf_len) res = self._backend._lib.OBJ_obj2txt( diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index c4d87bb7..c6ce61d1 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -10,6 +10,7 @@ from enum import Enum import six from cryptography import utils +from cryptography.hazmat.primitives import hashes _OID_NAMES = { @@ -170,6 +171,22 @@ OID_DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") OID_DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") OID_DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") +_SIG_OIDS_TO_HASH = { + "1.2.840.113549.1.1.4": hashes.MD5(), + "1.2.840.113549.1.1.5": hashes.SHA1(), + "1.2.840.113549.1.1.14": hashes.SHA224(), + "1.2.840.113549.1.1.11": hashes.SHA256(), + "1.2.840.113549.1.1.12": hashes.SHA384(), + "1.2.840.113549.1.1.13": hashes.SHA512(), + "1.2.840.10045.4.3.1": hashes.SHA224(), + "1.2.840.10045.4.3.2": hashes.SHA256(), + "1.2.840.10045.4.3.3": hashes.SHA384(), + "1.2.840.10045.4.3.4": hashes.SHA512(), + "1.2.840.10040.4.3": hashes.SHA1(), + "2.16.840.1.101.3.4.3.1": hashes.SHA224(), + "2.16.840.1.101.3.4.3.2": hashes.SHA256() +} + @six.add_metaclass(abc.ABCMeta) class Certificate(object): @@ -222,8 +239,8 @@ class Certificate(object): """ @abc.abstractproperty - def signature_algorithm(self): + def signature_hash_algorithm(self): """ - Returns an ObjectIdentifier corresponding to the signature algorithm of - the certificate. + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. """ diff --git a/tests/test_x509.py b/tests/test_x509.py index 613263d1..8f00eeed 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -13,6 +13,7 @@ import pytest import six from cryptography import x509 +from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.interfaces import ( DSABackend, EllipticCurveBackend, RSABackend, X509Backend ) @@ -45,7 +46,7 @@ class TestRSACertificate(object): assert cert.serial == 11559813051657483483 fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1())) assert fingerprint == b"2b619ed04bfc9c3b08eb677d272192286a0947a8" - assert cert.signature_algorithm == x509.OID_SHA1_WITH_RSA + assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) def test_load_der_cert(self, backend): cert = _load_cert( @@ -57,7 +58,7 @@ class TestRSACertificate(object): assert cert.serial == 2 fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1())) assert fingerprint == b"6f49779533d565e8b7c1062503eab41492c38e4d" - assert cert.signature_algorithm == x509.OID_SHA256_WITH_RSA + assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) def test_issuer(self, backend): cert = _load_cert( @@ -330,6 +331,15 @@ class TestRSACertificate(object): with pytest.raises(ValueError): x509.load_der_x509_certificate(b"notacert", backend) + def test_unsupported_signature_hash_algorithm_cert(self, backend): + cert = _load_cert( + os.path.join("x509", "verisign_md2_root.pem"), + x509.load_pem_x509_certificate, + backend + ) + with pytest.raises(UnsupportedAlgorithm): + cert.signature_hash_algorithm + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -340,7 +350,7 @@ class TestDSACertificate(object): x509.load_pem_x509_certificate, backend ) - assert cert.signature_algorithm == x509.OID_DSA_WITH_SHA1 + assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) public_key = cert.public_key() assert isinstance(public_key, interfaces.DSAPublicKey) if isinstance(public_key, interfaces.DSAPublicKeyWithNumbers): @@ -393,7 +403,7 @@ class TestECDSACertificate(object): x509.load_pem_x509_certificate, backend ) - assert cert.signature_algorithm == x509.OID_ECDSA_WITH_SHA384 + assert isinstance(cert.signature_hash_algorithm, hashes.SHA384) public_key = cert.public_key() assert isinstance(public_key, interfaces.EllipticCurvePublicKey) if isinstance( -- cgit v1.2.3