From 1eb82a604175923acd6c0512e86a746df7acbb59 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 31 Mar 2015 20:00:33 -0500 Subject: add subjectkeyidentifier support --- docs/x509.rst | 20 +++++++ src/cryptography/hazmat/backends/openssl/x509.py | 12 ++++ src/cryptography/x509.py | 26 +++++++++ tests/test_x509_ext.py | 72 ++++++++++++++++++++++++ 4 files changed, 130 insertions(+) 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) + , critical=False, value=)> , critical=True, value=)> 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 `. +.. 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 "".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) == ( + ", critical=False, value=)>" + ) + + 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 + ) -- cgit v1.2.3 From ee997266b9c88202e10772a687334d568c2de1f9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Apr 2015 12:20:28 -0500 Subject: python 3.2 you are terrible --- tests/test_x509_ext.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 4f0ad13b..5728a896 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -136,14 +136,14 @@ class TestKeyUsage(object): class TestSubjectKeyIdentifier(object): def test_properties(self): hexdigest = "092384932230498bc980aa8098456f6ff7ff3ac9" - value = binascii.unhexlify(hexdigest) + value = binascii.unhexlify(hexdigest.encode('ascii')) ski = x509.SubjectKeyIdentifier(value) assert ski.digest == value assert ski.hexdigest == hexdigest def test_repr(self): ski = x509.SubjectKeyIdentifier( - binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9") + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) ext = x509.Extension(x509.OID_SUBJECT_KEY_IDENTIFIER, False, ski) assert repr(ext) == ( @@ -154,19 +154,19 @@ class TestSubjectKeyIdentifier(object): def test_eq(self): ski = x509.SubjectKeyIdentifier( - binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9") + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) ski2 = x509.SubjectKeyIdentifier( - binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9") + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) assert ski == ski2 def test_ne(self): ski = x509.SubjectKeyIdentifier( - binascii.unhexlify("092384932230498bc980aa8098456f6ff7ff3ac9") + binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) ski2 = x509.SubjectKeyIdentifier( - binascii.unhexlify("aa8098456f6ff7ff3ac9092384932230498bc980") + binascii.unhexlify(b"aa8098456f6ff7ff3ac9092384932230498bc980") ) assert ski != ski2 assert ski != object() @@ -404,7 +404,7 @@ class TestSubjectKeyIdentifierExtension(object): assert ext.critical is False assert ski.hexdigest == "580184241bbc2b52944a3da510721451f5af3ac9" assert ski.digest == binascii.unhexlify( - "580184241bbc2b52944a3da510721451f5af3ac9" + b"580184241bbc2b52944a3da510721451f5af3ac9" ) def test_no_subject_key_identifier(self, backend): -- cgit v1.2.3 From 0f5a66b1d60063b7e7afc5ad2f001fa00cc8ac1e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 9 Apr 2015 14:23:03 -0400 Subject: free the ASN1_OCTET_STRING instance --- src/cryptography/hazmat/backends/openssl/x509.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 8b77a11b..5d47c5ea 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -225,6 +225,9 @@ class _Certificate(object): asn1_string = self._backend._ffi.cast( "ASN1_OCTET_STRING *", asn1_string ) + asn1_string = self._backend._ffi.gc( + asn1_string, self._backend._lib.ASN1_OCTET_STRING_free + ) return x509.SubjectKeyIdentifier( self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] ) -- cgit v1.2.3 From cbfb1015d9750a276456411a2b638585b6e4d7de Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 10 Apr 2015 20:57:20 -0400 Subject: alter approach to just use digest, no hexdigest --- docs/x509.rst | 8 +------- src/cryptography/x509.py | 6 +----- tests/test_x509_ext.py | 26 +++++++++++++++++--------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index 8a855617..d09651fb 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -275,7 +275,7 @@ X.509 Certificate Object >>> for ext in cert.extensions: ... print(ext) - , critical=False, value=)> + , critical=False, value=)> , critical=True, value=)> X.509 CSR (Certificate Signing Request) Object @@ -590,12 +590,6 @@ X.509 Extensions The binary value of the identifier. - .. attribute:: hexdigest - - :type: :term:`text` - - The hexadecimal value of the identifier. - Object Identifiers ~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index df37934a..d635d4af 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -353,12 +353,8 @@ class SubjectKeyIdentifier(object): digest = utils.read_only_property("_digest") - @property - def hexdigest(self): - return binascii.hexlify(self.digest).decode("ascii") - def __repr__(self): - return "".format(self.hexdigest) + return "".format(self.digest) def __eq__(self, other): if not isinstance(other, SubjectKeyIdentifier): diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 5728a896..194b18c8 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -9,6 +9,8 @@ import os import pytest +import six + from cryptography import x509 from cryptography.hazmat.backends.interfaces import RSABackend, X509Backend @@ -135,22 +137,29 @@ class TestKeyUsage(object): class TestSubjectKeyIdentifier(object): def test_properties(self): - hexdigest = "092384932230498bc980aa8098456f6ff7ff3ac9" - value = binascii.unhexlify(hexdigest.encode('ascii')) + value = binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ski = x509.SubjectKeyIdentifier(value) assert ski.digest == value - assert ski.hexdigest == hexdigest def test_repr(self): ski = x509.SubjectKeyIdentifier( binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) ext = x509.Extension(x509.OID_SUBJECT_KEY_IDENTIFIER, False, ski) - assert repr(ext) == ( - ", critical=False, value=)>" - ) + if six.PY3: + assert repr(ext) == ( + ", critical=False, value=)>" + ) + else: + assert repr(ext) == ( + ", critical=False, value=)>" + ) def test_eq(self): ski = x509.SubjectKeyIdentifier( @@ -402,7 +411,6 @@ class TestSubjectKeyIdentifierExtension(object): ski = ext.value assert ext is not None assert ext.critical is False - assert ski.hexdigest == "580184241bbc2b52944a3da510721451f5af3ac9" assert ski.digest == binascii.unhexlify( b"580184241bbc2b52944a3da510721451f5af3ac9" ) -- cgit v1.2.3 From 6c7dd24f350435f6362021822dcd7e51902088ec Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 11 Apr 2015 08:16:52 -0400 Subject: unused import I left in as a test. Yeah, that's why... --- src/cryptography/x509.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index d635d4af..28d16853 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function import abc -import binascii from enum import Enum import six -- cgit v1.2.3