aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/x509/reference.rst39
-rw-r--r--src/cryptography/x509.py49
-rw-r--r--tests/test_x509_ext.py19
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):