aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2015-04-19 11:06:54 -0400
committerAlex Gaynor <alex.gaynor@gmail.com>2015-04-19 11:06:54 -0400
commit941afb370677019323c6d335c2f529a3994a600a (patch)
tree1824f127523a0c4dcd1c5b20e737404b67447fea
parent7476b13b4953fd750d0484b0227e5de7b6cfeea8 (diff)
parentc7c9a43d39c0018b0e32e43f9c523dc768b462e9 (diff)
downloadcryptography-941afb370677019323c6d335c2f529a3994a600a.tar.gz
cryptography-941afb370677019323c6d335c2f529a3994a600a.tar.bz2
cryptography-941afb370677019323c6d335c2f529a3994a600a.zip
Merge pull request #1835 from reaperhulk/x509-aki
AuthorityKeyIdentifier support
-rw-r--r--docs/x509.rst30
-rw-r--r--src/cryptography/x509.py37
-rw-r--r--tests/test_x509_ext.py51
3 files changed, 118 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst
index e0e05b6b..da6bd85c 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -652,6 +652,35 @@ X.509 Extensions
purposes indicated in the key usage extension. The object is
iterable to obtain the list of :ref:`extended key usage OIDs <eku_oids>`.
+.. class:: AuthorityKeyIdentifier
+
+ .. versionadded:: 0.9
+
+ The authority key identifier extension provides a means of identifying the
+ public key corresponding to the private key used to sign a certificate.
+ This extension is typically used to assist in determining the appropriate
+ certificate chain. For more information about generation and use of this
+ extension see `RFC 5280 section 4.2.1.1`_.
+
+ .. attribute:: key_identifier
+
+ :type: bytes
+
+ A value derived from the public key used to verify the certificate's
+ signature.
+
+ .. attribute:: authority_cert_issuer
+
+ :type: :class:`Name` or None
+
+ The :class:`Name` of the issuer's issuer.
+
+ .. attribute:: authority_cert_serial_number
+
+ :type: int or None
+
+ The serial number of the issuer's issuer.
+
.. class:: SubjectKeyIdentifier
.. versionadded:: 0.9
@@ -938,3 +967,4 @@ Exceptions
.. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure
.. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security
+.. _`RFC 5280 section 4.2.1.1`: https://tools.ietf.org/html/rfc5280#section-4.2.1.1
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 55b17460..cdc0e430 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -557,6 +557,43 @@ class SubjectAlternativeName(object):
return "<SubjectAlternativeName({0})>".format(self._general_names)
+class AuthorityKeyIdentifier(object):
+ def __init__(self, key_identifier, authority_cert_issuer,
+ authority_cert_serial_number):
+ if authority_cert_issuer or authority_cert_serial_number:
+ if not authority_cert_issuer or not authority_cert_serial_number:
+ raise ValueError(
+ "authority_cert_issuer and authority_cert_serial_number "
+ "must both be present or both None"
+ )
+
+ if not isinstance(authority_cert_issuer, Name):
+ raise TypeError("authority_cert_issuer must be a Name")
+
+ if not isinstance(authority_cert_serial_number, six.integer_types):
+ raise TypeError(
+ "authority_cert_serial_number must be an integer"
+ )
+
+ self._key_identifier = key_identifier
+ self._authority_cert_issuer = authority_cert_issuer
+ self._authority_cert_serial_number = authority_cert_serial_number
+
+ def __repr__(self):
+ return (
+ "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
+ "authority_cert_issuer={0.authority_cert_issuer}, "
+ "authority_cert_serial_number={0.authority_cert_serial_number}"
+ ")>".format(self)
+ )
+
+ key_identifier = utils.read_only_property("_key_identifier")
+ authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
+ authority_cert_serial_number = utils.read_only_property(
+ "_authority_cert_serial_number"
+ )
+
+
OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 4811541f..8516a339 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -220,6 +220,57 @@ class TestSubjectKeyIdentifier(object):
assert ski != object()
+class TestAuthorityKeyIdentifier(object):
+ def test_authority_cert_issuer_not_name(self):
+ with pytest.raises(TypeError):
+ x509.AuthorityKeyIdentifier(b"identifier", "notname", 3)
+
+ def test_authority_cert_serial_number_not_integer(self):
+ name = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ ])
+ with pytest.raises(TypeError):
+ x509.AuthorityKeyIdentifier(b"identifier", name, "notanint")
+
+ def test_authority_issuer_none_serial_not_none(self):
+ with pytest.raises(ValueError):
+ x509.AuthorityKeyIdentifier(b"identifier", None, 3)
+
+ def test_authority_issuer_not_none_serial_none(self):
+ name = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ ])
+ with pytest.raises(ValueError):
+ x509.AuthorityKeyIdentifier(b"identifier", name, None)
+
+ def test_authority_cert_serial_and_issuer_none(self):
+ aki = x509.AuthorityKeyIdentifier(b"id", None, None)
+ assert aki.key_identifier == b"id"
+ assert aki.authority_cert_issuer is None
+ assert aki.authority_cert_serial_number is None
+
+ def test_repr(self):
+ name = x509.Name([x509.NameAttribute(x509.OID_COMMON_NAME, 'myCN')])
+ aki = x509.AuthorityKeyIdentifier(b"digest", name, 1234)
+
+ if six.PY3:
+ assert repr(aki) == (
+ "<AuthorityKeyIdentifier(key_identifier=b'digest', authority_"
+ "cert_issuer=<Name([<NameAttribute(oid=<ObjectIdentifier(oid="
+ "2.5.4.3, name=commonName)>, value='myCN')>])>, authority_cer"
+ "t_serial_number=1234)>"
+ )
+ else:
+ assert repr(aki) == (
+ "<AuthorityKeyIdentifier(key_identifier='digest', authority_ce"
+ "rt_issuer=<Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5"
+ ".4.3, name=commonName)>, value='myCN')>])>, authority_cert_se"
+ "rial_number=1234)>"
+ )
+
+
class TestBasicConstraints(object):
def test_ca_not_boolean(self):
with pytest.raises(TypeError):