From 9a10d59aaaf805a2aecef40df5338d2fc0602be9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 10 May 2015 14:55:51 -0500 Subject: support CRLDistributionPoints in the OpenSSL backend --- src/cryptography/hazmat/backends/openssl/x509.py | 112 ++++++++++++++++++++--- 1 file changed, 101 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 9d70d72f..7f487d35 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -28,6 +28,18 @@ from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.primitives import hashes +_REASONFLAGS_ENUM_MAPPING = { + 1: x509.ReasonFlags.key_compromise, + 2: x509.ReasonFlags.ca_compromise, + 3: x509.ReasonFlags.affiliation_changed, + 4: x509.ReasonFlags.superseded, + 5: x509.ReasonFlags.cessation_of_operation, + 6: x509.ReasonFlags.certificate_hold, + 7: x509.ReasonFlags.privilege_withdrawn, + 8: x509.ReasonFlags.aa_compromise +} + + def _obj2txt(backend, obj): # Set to 80 on the recommendation of # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values @@ -56,22 +68,23 @@ def _asn1_string_to_utf8(backend, asn1_string): return backend._ffi.buffer(buf[0], res)[:].decode('utf8') +def _build_x509_name_entry(backend, x509_name_entry): + obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry) + assert obj != backend._ffi.NULL + data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry) + assert data != backend._ffi.NULL + value = _asn1_string_to_utf8(backend, data) + oid = _obj2txt(backend, obj) + + return x509.NameAttribute(x509.ObjectIdentifier(oid), value) + + def _build_x509_name(backend, x509_name): count = backend._lib.X509_NAME_entry_count(x509_name) attributes = [] for x in range(count): entry = backend._lib.X509_NAME_get_entry(x509_name, x) - obj = backend._lib.X509_NAME_ENTRY_get_object(entry) - assert obj != backend._ffi.NULL - data = backend._lib.X509_NAME_ENTRY_get_data(entry) - assert data != backend._ffi.NULL - value = _asn1_string_to_utf8(backend, data) - oid = _obj2txt(backend, obj) - attributes.append( - x509.NameAttribute( - x509.ObjectIdentifier(oid), value - ) - ) + attributes.append(_build_x509_name_entry(backend, entry)) return x509.Name(attributes) @@ -292,6 +305,8 @@ class _Certificate(object): value = self._build_authority_information_access(ext) elif oid == x509.OID_CERTIFICATE_POLICIES: value = self._build_certificate_policies(ext) + elif oid == x509.OID_CRL_DISTRIBUTION_POINTS: + value = self._build_crl_distribution_points(ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -518,6 +533,81 @@ class _Certificate(object): return x509.ExtendedKeyUsage(ekus) + def _build_crl_distribution_points(self, ext): + cdps = self._backend._ffi.cast( + "Cryptography_STACK_OF_DIST_POINT *", + self._backend._lib.X509V3_EXT_d2i(ext) + ) + assert cdps != self._backend._ffi.NULL + cdps = self._backend._ffi.gc( + cdps, self._backend._lib.sk_DIST_POINT_free) + num = self._backend._lib.sk_DIST_POINT_num(cdps) + + dist_points = [] + for i in range(num): + full_name = None + relative_name = None + crl_issuer = None + reasons = None + cdp = self._backend._lib.sk_DIST_POINT_value(cdps, i) + if cdp.reasons != self._backend._ffi.NULL: + reasons = [] + # We will check each bit from RFC 5280 + # ReasonFlags ::= BIT STRING { + # unused (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # privilegeWithdrawn (7), + # aACompromise (8) } + for bit in range(1, 9): + if self._backend._lib.ASN1_BIT_STRING_get_bit( + cdp.reasons, bit + ): + reasons.append(_REASONFLAGS_ENUM_MAPPING[bit]) + + reasons = frozenset(reasons) + + if cdp.CRLissuer != self._backend._ffi.NULL: + crl_issuer = _build_general_names(self._backend, cdp.CRLissuer) + + # Certificates may have a crl_issuer/reasons and no distribution + # point so make sure it's not null. + if cdp.distpoint != self._backend._ffi.NULL: + # Type 0 is fullName, there is no #define for it in the code. + if cdp.distpoint.type == 0: + full_name = _build_general_names( + self._backend, cdp.distpoint.name.fullname + ) + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. + else: + rns = cdp.distpoint.name.relativename + rnum = self._backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = [] + for i in range(rnum): + rn = self._backend._lib.sk_X509_NAME_ENTRY_value( + rns, i + ) + assert rn != self._backend._ffi.NULL + attributes.append( + _build_x509_name_entry(self._backend, rn) + ) + + relative_name = x509.Name(attributes) + + dist_points.append( + x509.DistributionPoint( + full_name, relative_name, reasons, crl_issuer + ) + ) + + return x509.CRLDistributionPoints(dist_points) + @utils.register_interface(x509.CertificateSigningRequest) class _CertificateSigningRequest(object): -- cgit v1.2.3 From 594a2edf1ead6b7ce3f4e217bada30f2f323dc36 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 12 May 2015 23:27:32 -0500 Subject: change approach for parsing CDP reason flags --- src/cryptography/hazmat/backends/openssl/x509.py | 43 ++++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 7f487d35..07e54baa 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -28,18 +28,6 @@ from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.primitives import hashes -_REASONFLAGS_ENUM_MAPPING = { - 1: x509.ReasonFlags.key_compromise, - 2: x509.ReasonFlags.ca_compromise, - 3: x509.ReasonFlags.affiliation_changed, - 4: x509.ReasonFlags.superseded, - 5: x509.ReasonFlags.cessation_of_operation, - 6: x509.ReasonFlags.certificate_hold, - 7: x509.ReasonFlags.privilege_withdrawn, - 8: x509.ReasonFlags.aa_compromise -} - - def _obj2txt(backend, obj): # Set to 80 on the recommendation of # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values @@ -551,7 +539,6 @@ class _Certificate(object): reasons = None cdp = self._backend._lib.sk_DIST_POINT_value(cdps, i) if cdp.reasons != self._backend._ffi.NULL: - reasons = [] # We will check each bit from RFC 5280 # ReasonFlags ::= BIT STRING { # unused (0), @@ -563,11 +550,31 @@ class _Certificate(object): # certificateHold (6), # privilegeWithdrawn (7), # aACompromise (8) } - for bit in range(1, 9): - if self._backend._lib.ASN1_BIT_STRING_get_bit( - cdp.reasons, bit - ): - reasons.append(_REASONFLAGS_ENUM_MAPPING[bit]) + reasons = [] + get_bit = self._backend._lib.ASN1_BIT_STRING_get_bit + if get_bit(cdp.reasons, 1): + reasons.append(x509.ReasonFlags.key_compromise) + + if get_bit(cdp.reasons, 2): + reasons.append(x509.ReasonFlags.ca_compromise) + + if get_bit(cdp.reasons, 3): + reasons.append(x509.ReasonFlags.affiliation_changed) + + if get_bit(cdp.reasons, 4): + reasons.append(x509.ReasonFlags.superseded) + + if get_bit(cdp.reasons, 5): + reasons.append(x509.ReasonFlags.cessation_of_operation) + + if get_bit(cdp.reasons, 6): + reasons.append(x509.ReasonFlags.certificate_hold) + + if get_bit(cdp.reasons, 7): + reasons.append(x509.ReasonFlags.privilege_withdrawn) + + if get_bit(cdp.reasons, 8): + reasons.append(x509.ReasonFlags.aa_compromise) reasons = frozenset(reasons) -- cgit v1.2.3