diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-05-13 07:28:36 -0400 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-05-13 07:28:36 -0400 |
commit | 91ea3a91fe67ecf2577b3f88955c4baad4d4f131 (patch) | |
tree | 4619a7c2b364676ff615a4d70198eecc670f0449 | |
parent | 8eca316a8f98bb607d886a0503d4fd50c4d20fd0 (diff) | |
parent | 2008d9c83cf99c56f961b6b726cfdfae426f2a31 (diff) | |
download | cryptography-91ea3a91fe67ecf2577b3f88955c4baad4d4f131.tar.gz cryptography-91ea3a91fe67ecf2577b3f88955c4baad4d4f131.tar.bz2 cryptography-91ea3a91fe67ecf2577b3f88955c4baad4d4f131.zip |
Merge pull request #1940 from reaperhulk/x509-ossl-cp
support certificate policies in the openssl backend
-rw-r--r-- | docs/x509.rst | 1 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 71 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 94 |
3 files changed, 166 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst index a40727cc..ff43be01 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -320,6 +320,7 @@ X.509 Certificate Object <Extension(oid=<ObjectIdentifier(oid=2.5.29.35, name=authorityKeyIdentifier)>, critical=False, value=<AuthorityKeyIdentifier(key_identifier='\xe4}_\xd1\\\x95\x86\x08,\x05\xae\xbeu\xb6e\xa7\xd9]\xa8f', authority_cert_issuer=None, authority_cert_serial_number=None)>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.14, name=subjectKeyIdentifier)>, critical=False, value=<SubjectKeyIdentifier(digest='X\x01\x84$\x1b\xbc+R\x94J=\xa5\x10r\x14Q\xf5\xaf:\xc9')>)> <Extension(oid=<ObjectIdentifier(oid=2.5.29.15, name=keyUsage)>, critical=True, value=<KeyUsage(digital_signature=False, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, key_cert_sign=True, crl_sign=True, encipher_only=None, decipher_only=None)>)> + <Extension(oid=<ObjectIdentifier(oid=2.5.29.32, name=certificatePolicies)>, critical=False, value=<CertificatePolicies([<PolicyInformation(policy_identifier=<ObjectIdentifier(oid=2.16.840.1.101.3.2.1.48.1, name=Unknown OID)>, policy_qualifiers=None)>])>)> <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 diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 8b5f3920..9d70d72f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -290,6 +290,8 @@ class _Certificate(object): value = self._build_authority_key_identifier(ext) elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS: value = self._build_authority_information_access(ext) + elif oid == x509.OID_CERTIFICATE_POLICIES: + value = self._build_certificate_policies(ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -304,6 +306,75 @@ class _Certificate(object): return x509.Extensions(extensions) + def _build_certificate_policies(self, ext): + cp = self._backend._ffi.cast( + "Cryptography_STACK_OF_POLICYINFO *", + self._backend._lib.X509V3_EXT_d2i(ext) + ) + assert cp != self._backend._ffi.NULL + cp = self._backend._ffi.gc(cp, self._backend._lib.sk_POLICYINFO_free) + num = self._backend._lib.sk_POLICYINFO_num(cp) + certificate_policies = [] + for i in range(num): + qualifiers = None + pi = self._backend._lib.sk_POLICYINFO_value(cp, i) + oid = x509.ObjectIdentifier(_obj2txt(self._backend, pi.policyid)) + if pi.qualifiers != self._backend._ffi.NULL: + qnum = self._backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) + qualifiers = [] + for j in range(qnum): + pqi = self._backend._lib.sk_POLICYQUALINFO_value( + pi.qualifiers, j + ) + pqualid = x509.ObjectIdentifier( + _obj2txt(self._backend, pqi.pqualid) + ) + if pqualid == x509.OID_CPS_QUALIFIER: + cpsuri = self._backend._ffi.buffer( + pqi.d.cpsuri.data, pqi.d.cpsuri.length + )[:].decode('ascii') + qualifiers.append(cpsuri) + elif pqualid == x509.OID_CPS_USER_NOTICE: + user_notice = self._build_user_notice(pqi.d.usernotice) + qualifiers.append(user_notice) + + certificate_policies.append( + x509.PolicyInformation(oid, qualifiers) + ) + + return x509.CertificatePolicies(certificate_policies) + + def _build_user_notice(self, un): + explicit_text = None + notice_reference = None + + if un.exptext != self._backend._ffi.NULL: + explicit_text = _asn1_string_to_utf8(self._backend, un.exptext) + + if un.noticeref != self._backend._ffi.NULL: + organization = _asn1_string_to_utf8( + self._backend, un.noticeref.organization + ) + + num = self._backend._lib.sk_ASN1_INTEGER_num( + un.noticeref.noticenos + ) + notice_numbers = [] + for i in range(num): + asn1_int = self._backend._lib.sk_ASN1_INTEGER_value( + un.noticeref.noticenos, i + ) + notice_num = _asn1_integer_to_int( + self._backend, asn1_int + ) + notice_numbers.append(notice_num) + + notice_reference = x509.NoticeReference( + organization, notice_numbers + ) + + return x509.UserNotice(notice_reference, explicit_text) + def _build_basic_constraints(self, ext): bc_st = self._backend._lib.X509V3_EXT_d2i(ext) assert bc_st != self._backend._ffi.NULL diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 701ea167..2852776b 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -235,6 +235,100 @@ class TestCertificatePolicies(object): assert cp != object() +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestCertificatePoliciesExtension(object): + def test_cps_uri_policy_qualifier(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "cp_cps_uri.pem"), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [u"http://other.com/cps"] + ) + ]) + + def test_user_notice_with_notice_reference(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_with_notice_reference.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + u"http://example.com/cps", + u"http://other.com/cps", + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + u"thing" + ) + ] + ) + ]) + + def test_user_notice_with_explicit_text(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_with_explicit_text.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [x509.UserNotice(None, u"thing")] + ) + ]) + + def test_user_notice_no_explicit_text(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "cp_user_notice_no_explicit_text.pem" + ), + x509.load_pem_x509_certificate, + backend + ) + + cp = cert.extensions.get_extension_for_oid( + x509.OID_CERTIFICATE_POLICIES + ).value + + assert cp == x509.CertificatePolicies([ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + None + ) + ] + ) + ]) + + class TestKeyUsage(object): def test_key_agreement_false_encipher_decipher_true(self): with pytest.raises(ValueError): |