From 253929a85c45c1313fd68d10ec7a7a45e380d5c0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 5 Aug 2015 17:30:39 +0100 Subject: add AuthorityKeyIdentifier from_issuer_public_key Refactored SKI's creation code into a separate function, added doctest examples --- docs/x509/reference.rst | 30 +++++++++++++++++++++++++++++ src/cryptography/x509.py | 49 ++++++++++++++++++++++++++++++------------------ tests/test_x509_ext.py | 19 +++++++++++++++++++ 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index dfa91fac..a05be164 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1160,6 +1160,28 @@ X.509 Extensions The serial number of the issuer's issuer. + .. classmethod:: from_issuer_public_key(public_key) + + .. versionadded:: 1.0 + + Creates a new AuthorityKeyIdentifier instance using the public key + provided to generate the appropriate digest. This should be the + **issuer public key**. The resulting object will contain a + :attr:`~cryptography.x509.AuthorityKeyIdentifier.key_identifier`. + The generated digest is the SHA1 hash of the ``subjectPublicKey`` A + SN.1 bit string. This is the first recommendation in :rfc:`5280` + section 4.2.1.2. + + :param certificate: The issuing :class:`~cryptography.x509.Certificate`. + + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(cert.public_key()) + + .. class:: SubjectKeyIdentifier .. versionadded:: 0.9 @@ -1198,6 +1220,14 @@ X.509 Extensions , or :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.backends import default_backend + >>> cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> x509.SubjectKeyIdentifier.from_public_key(cert.public_key()) + + .. class:: SubjectAlternativeName .. versionadded:: 0.9 diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 5ed3c094..3f306e3a 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -32,6 +32,27 @@ class _SubjectPublicKeyInfo(univ.Sequence): ) +def _key_identifier_from_public_key(public_key): + # This is a very slow way to do this. + serialized = public_key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo + ) + spki, remaining = decoder.decode( + serialized, asn1Spec=_SubjectPublicKeyInfo() + ) + # the univ.BitString object is a tuple of bits. We need bytes and + # pyasn1 really doesn't want to give them to us. To get it we'll + # build an integer and convert that to bytes. + assert not remaining + bits = 0 + for bit in spki.getComponentByName("subjectPublicKey"): + bits = bits << 1 | bit + + data = utils.int_to_bytes(bits) + return hashlib.sha1(data).digest() + + _OID_NAMES = { "2.5.4.3": "commonName", "2.5.4.6": "countryName", @@ -710,24 +731,7 @@ class SubjectKeyIdentifier(object): @classmethod def from_public_key(cls, public_key): - # This is a very slow way to do this. - serialized = public_key.public_bytes( - serialization.Encoding.DER, - serialization.PublicFormat.SubjectPublicKeyInfo - ) - spki, remaining = decoder.decode( - serialized, asn1Spec=_SubjectPublicKeyInfo() - ) - assert not remaining - # the univ.BitString object is a tuple of bits. We need bytes and - # pyasn1 really doesn't want to give them to us. To get it we'll - # build an integer and convert that to bytes. - bits = 0 - for bit in spki.getComponentByName("subjectPublicKey"): - bits = bits << 1 | bit - - data = utils.int_to_bytes(bits) - return cls(hashlib.sha1(data).digest()) + return cls(_key_identifier_from_public_key(public_key)) digest = utils.read_only_property("_digest") @@ -1318,6 +1322,15 @@ class AuthorityKeyIdentifier(object): self._authority_cert_issuer = authority_cert_issuer self._authority_cert_serial_number = authority_cert_serial_number + @classmethod + def from_issuer_public_key(cls, public_key): + digest = _key_identifier_from_public_key(public_key) + return cls( + key_identifier=digest, + authority_cert_issuer=None, + authority_cert_serial_number=None + ) + def __repr__(self): return ( " Date: Sat, 8 Aug 2015 15:20:52 -0500 Subject: update prose for from_issuer_public_key --- docs/x509/reference.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index a05be164..930c7f9f 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1166,10 +1166,14 @@ X.509 Extensions Creates a new AuthorityKeyIdentifier instance using the public key provided to generate the appropriate digest. This should be the - **issuer public key**. The resulting object will contain a - :attr:`~cryptography.x509.AuthorityKeyIdentifier.key_identifier`. - The generated digest is the SHA1 hash of the ``subjectPublicKey`` A - SN.1 bit string. This is the first recommendation in :rfc:`5280` + **issuer's public key**. The resulting object will contain + :attr:`~cryptography.x509.AuthorityKeyIdentifier.key_identifier`, but + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_issuer` + and + :attr:`~cryptography.x509.AuthorityKeyIdentifier.authority_cert_serial_number` + will be None. + The generated ``key_identifier`` is the SHA1 hash of the ``subjectPublicKey`` + ASN.1 bit string. This is the first recommendation in :rfc:`5280` section 4.2.1.2. :param certificate: The issuing :class:`~cryptography.x509.Certificate`. -- cgit v1.2.3 From cc671824ad133df93bbf903ef2d363b54b5835a9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 8 Aug 2015 15:41:54 -0500 Subject: address review comments --- docs/x509/reference.rst | 17 +++++++++++------ src/cryptography/x509.py | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 930c7f9f..d86ebbe8 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1176,14 +1176,19 @@ X.509 Extensions ASN.1 bit string. This is the first recommendation in :rfc:`5280` section 4.2.1.2. - :param certificate: The issuing :class:`~cryptography.x509.Certificate`. + :param public_key: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` + , + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` + , or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. .. doctest:: >>> from cryptography import x509 >>> from cryptography.hazmat.backends import default_backend - >>> cert = x509.load_pem_x509_certificate(pem_data, default_backend()) - >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(cert.public_key()) + >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) .. class:: SubjectKeyIdentifier @@ -1228,9 +1233,9 @@ X.509 Extensions >>> from cryptography import x509 >>> from cryptography.hazmat.backends import default_backend - >>> cert = x509.load_pem_x509_certificate(pem_data, default_backend()) - >>> x509.SubjectKeyIdentifier.from_public_key(cert.public_key()) - + >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) + >>> x509.SubjectKeyIdentifier.from_public_key(csr.public_key()) + .. class:: SubjectAlternativeName diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 3f306e3a..713e92a2 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -41,10 +41,10 @@ def _key_identifier_from_public_key(public_key): spki, remaining = decoder.decode( serialized, asn1Spec=_SubjectPublicKeyInfo() ) + assert not remaining # the univ.BitString object is a tuple of bits. We need bytes and # pyasn1 really doesn't want to give them to us. To get it we'll # build an integer and convert that to bytes. - assert not remaining bits = 0 for bit in spki.getComponentByName("subjectPublicKey"): bits = bits << 1 | bit -- cgit v1.2.3