diff options
| author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-08-08 17:53:25 -0400 | 
|---|---|---|
| committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-08-08 17:53:25 -0400 | 
| commit | c5f59dae64bc0218da50696fad2bfd75471d6e09 (patch) | |
| tree | d36710212582288d887fcc86f9750e8027e75459 | |
| parent | 8b4b4166d3214509d6776b040c2409369bfd3363 (diff) | |
| parent | cc671824ad133df93bbf903ef2d363b54b5835a9 (diff) | |
| download | cryptography-c5f59dae64bc0218da50696fad2bfd75471d6e09.tar.gz cryptography-c5f59dae64bc0218da50696fad2bfd75471d6e09.tar.bz2 cryptography-c5f59dae64bc0218da50696fad2bfd75471d6e09.zip | |
Merge pull request #2210 from reaperhulk/aki-classmethod
AuthorityKeyIdentifier classmethod
| -rw-r--r-- | docs/x509/reference.rst | 39 | ||||
| -rw-r--r-- | src/cryptography/x509.py | 49 | ||||
| -rw-r--r-- | tests/test_x509_ext.py | 19 | 
3 files changed, 89 insertions, 18 deletions
| diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index dfa91fac..d86ebbe8 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1160,6 +1160,37 @@ 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'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 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 +            >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) +            >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) +            <AuthorityKeyIdentifier(key_identifier='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9', authority_cert_issuer=None, authority_cert_serial_number=None)> +  .. class:: SubjectKeyIdentifier      .. versionadded:: 0.9 @@ -1198,6 +1229,14 @@ X.509 Extensions              , or              :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. +        .. doctest:: + +            >>> from cryptography import x509 +            >>> from cryptography.hazmat.backends import default_backend +            >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) +            >>> x509.SubjectKeyIdentifier.from_public_key(csr.public_key()) +            <SubjectKeyIdentifier(digest='\xdb\xaa\xf0\x06\x11\xdbD\xfe\xbf\x93\x03\x8av\x88WP7\xa6\x91\xf7')> +  .. class:: SubjectAlternativeName      .. versionadded:: 0.9 diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 38d540ab..da7603c4 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() +    ) +    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 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 (              "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 73cdfc5f..40231b93 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -2112,6 +2112,25 @@ class TestAuthorityKeyIdentifierExtension(object):          ]          assert ext.value.authority_cert_serial_number == 3 +    def test_from_certificate(self, backend): +        issuer_cert = _load_cert( +            os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), +            x509.load_pem_x509_certificate, +            backend +        ) +        cert = _load_cert( +            os.path.join("x509", "cryptography.io.pem"), +            x509.load_pem_x509_certificate, +            backend +        ) +        ext = cert.extensions.get_extension_for_oid( +            x509.OID_AUTHORITY_KEY_IDENTIFIER +        ) +        aki = x509.AuthorityKeyIdentifier.from_issuer_public_key( +            issuer_cert.public_key() +        ) +        assert ext.value == aki +  class TestNameConstraints(object):      def test_ipaddress_wrong_type(self): | 
