From a147699cabf935b0c770d5c72fb8d2305737d66a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 4 May 2015 17:35:47 -0500 Subject: add support for authority information access in the openssl backend --- src/cryptography/hazmat/backends/openssl/x509.py | 23 +++++ src/cryptography/hazmat/bindings/openssl/x509v3.py | 14 ++++ tests/test_x509_ext.py | 98 ++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index c6b85c9f..42ca138d 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -271,6 +271,8 @@ class _Certificate(object): value = self._build_extended_key_usage(ext) elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER: value = self._build_authority_key_identifier(ext) + elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS: + value = self._build_authority_information_access(ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -362,6 +364,27 @@ class _Certificate(object): key_identifier, authority_cert_issuer, authority_cert_serial_number ) + def _build_authority_information_access(self, ext): + aia = self._backend._lib.X509V3_EXT_d2i(ext) + assert aia != self._backend._ffi.NULL + aia = self._backend._ffi.cast( + "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia + ) + aia = self._backend._ffi.gc( + aia, self._backend._lib.sk_ACCESS_DESCRIPTION_free + ) + num = self._backend._lib.sk_ACCESS_DESCRIPTION_num(aia) + access_descriptions = [] + for i in range(num): + ad = self._backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) + assert ad.method != self._backend._ffi.NULL + oid = x509.ObjectIdentifier(_obj2txt(self._backend, ad.method)) + assert ad.location != self._backend._ffi.NULL + gn = _build_general_name(self._backend, ad.location) + access_descriptions.append(x509.AccessDescription(oid, gn)) + + return x509.AuthorityInformationAccess(access_descriptions) + def _build_key_usage(self, ext): bit_string = self._backend._lib.X509V3_EXT_d2i(ext) assert bit_string != self._backend._ffi.NULL diff --git a/src/cryptography/hazmat/bindings/openssl/x509v3.py b/src/cryptography/hazmat/bindings/openssl/x509v3.py index 311261f0..c2b6860f 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509v3.py +++ b/src/cryptography/hazmat/bindings/openssl/x509v3.py @@ -19,9 +19,12 @@ typedef LHASH_OF(CONF_VALUE) Cryptography_LHASH_OF_CONF_VALUE; #else typedef LHASH Cryptography_LHASH_OF_CONF_VALUE; #endif +typedef STACK_OF(ACCESS_DESCRIPTION) Cryptography_STACK_OF_ACCESS_DESCRIPTION; """ TYPES = """ +typedef ... Cryptography_STACK_OF_ACCESS_DESCRIPTION; + typedef struct { X509 *issuer_cert; X509 *subject_cert; @@ -92,6 +95,11 @@ typedef struct { ASN1_INTEGER *serial; } AUTHORITY_KEYID; +typedef struct { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + typedef ... Cryptography_LHASH_OF_CONF_VALUE; """ @@ -117,6 +125,12 @@ int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *); int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *); GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int); +int sk_ACCESS_DESCRIPTION_num(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); +ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_value( + Cryptography_STACK_OF_ACCESS_DESCRIPTION *, int +); +void sk_ACCESS_DESCRIPTION_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); + X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *, X509V3_CTX *, int, char *); diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index ad36b5c0..8a227953 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1138,6 +1138,104 @@ class TestAuthorityInformationAccess(object): assert aia != object() +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityInformationAccessExtension(object): + def test_aia_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://gv.symcd.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://gv.symcb.com/gv.crt") + ), + ]) + + def test_aia_multiple_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp2.domain.com") + ), + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, "myCN"), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, "some Org"), + ])) + ), + ]) + + def test_aia_ocsp_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + ]) + + def test_aia_ca_issuers_only(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_oid( + x509.OID_AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess([ + x509.AccessDescription( + x509.OID_CA_ISSUERS, + x509.DirectoryName(x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, "myCN"), + x509.NameAttribute(x509.OID_ORGANIZATION_NAME, "some Org"), + ])) + ), + ]) + + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestAuthorityKeyIdentifierExtension(object): -- cgit v1.2.3