aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py119
-rw-r--r--tests/test_x509_ext.py215
2 files changed, 323 insertions, 11 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 9d70d72f..07e54baa 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -56,22 +56,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 +293,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 +521,100 @@ 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:
+ # 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) }
+ 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)
+
+ 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):
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index a833bf37..72f2f9e4 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -2012,3 +2012,218 @@ class TestCRLDistributionPoints(object):
assert cdp != cdp3
assert cdp != cdp4
assert cdp != object()
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=X509Backend)
+class TestCRLDistributionPointsExtension(object):
+ def test_fullname_and_crl_issuer(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "PKITS_data", "certs", "ValidcRLIssuerTest28EE.crt"
+ ),
+ x509.load_der_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=[x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, "US"),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME,
+ "Test Certificates 2011"
+ ),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME,
+ "indirectCRL CA3 cRLIssuer"
+ ),
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ "indirect CRL for indirectCRL CA3"
+ ),
+ ])
+ )],
+ relative_name=None,
+ reasons=None,
+ crl_issuer=[x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, "US"),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME,
+ "Test Certificates 2011"
+ ),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME,
+ "indirectCRL CA3 cRLIssuer"
+ ),
+ ])
+ )],
+ )
+ ])
+
+ def test_relativename_and_crl_issuer(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "PKITS_data", "certs", "ValidcRLIssuerTest29EE.crt"
+ ),
+ x509.load_der_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=None,
+ relative_name=x509.Name([
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ "indirect CRL for indirectCRL CA3"
+ ),
+ ]),
+ reasons=None,
+ crl_issuer=[x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, "US"),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME,
+ "Test Certificates 2011"
+ ),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME,
+ "indirectCRL CA3 cRLIssuer"
+ ),
+ ])
+ )],
+ )
+ ])
+
+ def test_fullname_crl_issuer_reasons(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "cdp_fullname_reasons_crl_issuer.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=[x509.UniformResourceIdentifier(
+ u"http://myhost.com/myca.crl"
+ )],
+ relative_name=None,
+ reasons=frozenset([
+ x509.ReasonFlags.key_compromise,
+ x509.ReasonFlags.ca_compromise
+ ]),
+ crl_issuer=[x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, "US"),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, "PyCA"
+ ),
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME, "cryptography CA"
+ ),
+ ])
+ )],
+ )
+ ])
+
+ def test_all_reasons(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "cdp_all_reasons.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=[x509.UniformResourceIdentifier(
+ u"http://domain.com/some.crl"
+ )],
+ relative_name=None,
+ reasons=frozenset([
+ x509.ReasonFlags.key_compromise,
+ x509.ReasonFlags.ca_compromise,
+ x509.ReasonFlags.affiliation_changed,
+ x509.ReasonFlags.superseded,
+ x509.ReasonFlags.privilege_withdrawn,
+ x509.ReasonFlags.cessation_of_operation,
+ x509.ReasonFlags.aa_compromise,
+ x509.ReasonFlags.certificate_hold,
+ ]),
+ crl_issuer=None
+ )
+ ])
+
+ def test_single_reason(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "cdp_reason_aa_compromise.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=[x509.UniformResourceIdentifier(
+ u"http://domain.com/some.crl"
+ )],
+ relative_name=None,
+ reasons=frozenset([x509.ReasonFlags.aa_compromise]),
+ crl_issuer=None
+ )
+ ])
+
+ def test_crl_issuer_only(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom", "cdp_crl_issuer.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+
+ cdps = cert.extensions.get_extension_for_oid(
+ x509.OID_CRL_DISTRIBUTION_POINTS
+ ).value
+
+ assert cdps == x509.CRLDistributionPoints([
+ x509.DistributionPoint(
+ full_name=None,
+ relative_name=None,
+ reasons=None,
+ crl_issuer=[x509.DirectoryName(
+ x509.Name([
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME, "cryptography CA"
+ ),
+ ])
+ )],
+ )
+ ])