aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-03-31 20:00:33 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-04-10 22:22:05 -0400
commit1eb82a604175923acd6c0512e86a746df7acbb59 (patch)
treee5f6baffa81eae8ccfbe293a5f6254f6c3eafa1c
parent890081828d99159145e12c8654501c2d867c4327 (diff)
downloadcryptography-1eb82a604175923acd6c0512e86a746df7acbb59.tar.gz
cryptography-1eb82a604175923acd6c0512e86a746df7acbb59.tar.bz2
cryptography-1eb82a604175923acd6c0512e86a746df7acbb59.zip
add subjectkeyidentifier support
-rw-r--r--docs/x509.rst20
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py12
-rw-r--r--src/cryptography/x509.py26
-rw-r--r--tests/test_x509_ext.py72
4 files changed, 130 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst
index afc9620a..8a855617 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -275,6 +275,7 @@ X.509 Certificate Object
>>> for ext in cert.extensions:
... print(ext)
+ <Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectKeyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(value=580184241bbc2b52944a3da510721451f5af3ac9)>)>
<Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)>
X.509 CSR (Certificate Signing Request) Object
@@ -576,6 +577,25 @@ 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:: SubjectKeyIdentifier
+
+ .. versionadded:: 0.9
+
+ The subject key identifier extension provides a means of identifying
+ certificates that contain a particular public key.
+
+ .. attribute:: digest
+
+ :type: bytes
+
+ The binary value of the identifier.
+
+ .. attribute:: hexdigest
+
+ :type: :term:`text`
+
+ The hexadecimal value of the identifier.
+
Object Identifiers
~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 6a7032ba..8b77a11b 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -170,6 +170,8 @@ class _Certificate(object):
)
elif oid == x509.OID_BASIC_CONSTRAINTS:
value = self._build_basic_constraints(ext)
+ elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER:
+ value = self._build_subject_key_identifier(ext)
elif oid == x509.OID_KEY_USAGE and critical:
# TODO: remove this obviously.
warnings.warn(
@@ -217,6 +219,16 @@ class _Certificate(object):
return x509.BasicConstraints(ca, path_length)
+ def _build_subject_key_identifier(self, ext):
+ asn1_string = self._backend._lib.X509V3_EXT_d2i(ext)
+ assert asn1_string != self._backend._ffi.NULL
+ asn1_string = self._backend._ffi.cast(
+ "ASN1_OCTET_STRING *", asn1_string
+ )
+ return x509.SubjectKeyIdentifier(
+ self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
+ )
+
@utils.register_interface(x509.CertificateSigningRequest)
class _CertificateSigningRequest(object):
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 697d7d6e..df37934a 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -5,6 +5,7 @@
from __future__ import absolute_import, division, print_function
import abc
+import binascii
from enum import Enum
import six
@@ -346,6 +347,31 @@ class KeyUsage(object):
return self._decipher_only
+class SubjectKeyIdentifier(object):
+ def __init__(self, digest):
+ self._digest = digest
+
+ digest = utils.read_only_property("_digest")
+
+ @property
+ def hexdigest(self):
+ return binascii.hexlify(self.digest).decode("ascii")
+
+ def __repr__(self):
+ return "<SubjectKeyIdentifier(value={0})>".format(self.hexdigest)
+
+ def __eq__(self, other):
+ if not isinstance(other, SubjectKeyIdentifier):
+ return NotImplemented
+
+ return (
+ self.digest == other.digest
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+
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 c1512d5f..4f0ad13b 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -4,6 +4,7 @@
from __future__ import absolute_import, division, print_function
+import binascii
import os
import pytest
@@ -132,6 +133,45 @@ class TestKeyUsage(object):
ku.decipher_only
+class TestSubjectKeyIdentifier(object):
+ def test_properties(self):
+ hexdigest = "092384932230498bc980aa8098456f6ff7ff3ac9"
+ value = binascii.unhexlify(hexdigest)
+ ski = x509.SubjectKeyIdentifier(value)
+ assert ski.digest == value
+ assert ski.hexdigest == hexdigest
+
+ def test_repr(self):
+ ski = x509.SubjectKeyIdentifier(
+ binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9")
+ )
+ ext = x509.Extension(x509.OID_SUBJECT_KEY_IDENTIFIER, False, ski)
+ assert repr(ext) == (
+ "<Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectKey"
+ "Identifier)>, critical=False, value=<SubjectKeyIdentifier("
+ "value=092384932230498bc980aa8098456f6ff7ff3ac9)>)>"
+ )
+
+ def test_eq(self):
+ ski = x509.SubjectKeyIdentifier(
+ binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9")
+ )
+ ski2 = x509.SubjectKeyIdentifier(
+ binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9")
+ )
+ assert ski == ski2
+
+ def test_ne(self):
+ ski = x509.SubjectKeyIdentifier(
+ binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9")
+ )
+ ski2 = x509.SubjectKeyIdentifier(
+ binascii.unhexlify("aa8098456f6ff7ff3ac9092384932230498bc980")
+ )
+ assert ski != ski2
+ assert ski != object()
+
+
class TestBasicConstraints(object):
def test_ca_not_boolean(self):
with pytest.raises(TypeError):
@@ -345,3 +385,35 @@ class TestBasicConstraintsExtension(object):
assert ext is not None
assert ext.critical is False
assert ext.value.ca is False
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestSubjectKeyIdentifierExtension(object):
+ def test_subject_key_identifier(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
+ x509.load_der_x509_certificate,
+ backend
+ )
+ ext = cert.extensions.get_extension_for_oid(
+ x509.OID_SUBJECT_KEY_IDENTIFIER
+ )
+ ski = ext.value
+ assert ext is not None
+ assert ext.critical is False
+ assert ski.hexdigest == "580184241bbc2b52944a3da510721451f5af3ac9"
+ assert ski.digest == binascii.unhexlify(
+ "580184241bbc2b52944a3da510721451f5af3ac9"
+ )
+
+ def test_no_subject_key_identifier(self, backend):
+ cert = _load_cert(
+ os.path.join("x509", "custom", "bc_path_length_zero.pem"),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ with pytest.raises(x509.ExtensionNotFound):
+ cert.extensions.get_extension_for_oid(
+ x509.OID_SUBJECT_KEY_IDENTIFIER
+ )