diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 0e0ca53a79241..0d35fae0c1b44 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -1188,7 +1188,33 @@ def _create_x509_extension(self, handlers, rust_handler, extension): ) def _convert_x509_extension_to_bytes(self, extension): - ext = self._create_x509_extension(self._all_encode_handlers, extension) + if isinstance(extension.value, x509.UnrecognizedExtension): + return extension.value.value + + for rust_handler in [ + rust_x509.encode_certificate_extension, + rust_x509.encode_crl_extension, + rust_x509.encode_crl_entry_extension, + rust_ocsp.encode_ocsp_request_extension, + rust_ocsp.encode_ocsp_basic_response_extension, + ]: + try: + return rust_handler(extension) + except NotImplementedError: + pass + + # Once all extensions are handled by Rust code, the following needs to + # be replaced by something like: + # raise NotImplementedError( + # f"Extension not supported: {extension.oid.dotted_string}" + # ) + + ext = self._create_x509_extension( + self._all_encode_handlers, + # pick a random one here: + rust_handler=rust_x509.encode_certificate_extension, + extension=extension, + ) data = self._lib.X509_EXTENSION_get_data(ext) self.openssl_assert(data != self._ffi.NULL) return self._ffi.buffer(data.data, data.length)[:] diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 3a8d78168df77..25721089344a2 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -198,6 +198,12 @@ def test_indexing(self): assert ext[-1] == ext[1] assert ext[0] == x509.TLSFeatureType.status_request + def test_der_string(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + assert ext1.to_der_string() == b"\x30\x03\x02\x01\x05" + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request_v2]) + assert ext2.to_der_string() == b"\x30\x03\x02\x01\x11" + class TestUnrecognizedExtension(object): def test_invalid_oid(self): @@ -251,6 +257,20 @@ def test_hash(self): assert hash(ext1) == hash(ext2) assert hash(ext1) != hash(ext3) + def test_der_string(self): + ext1 = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.5"), b"\x03\x02\x01" + ) + assert ext1.to_der_string() == b"\x03\x02\x01" + + # The following creates a BasicConstraints extension with an invalid + # value. The serialization code should still handle it correctly by + # special-casing UnrecognizedExtension. + ext2 = x509.UnrecognizedExtension( + x509.oid.ExtensionOID.BASIC_CONSTRAINTS, b"\x03\x02\x01" + ) + assert ext2.to_der_string() == b"\x03\x02\x01" + class TestCertificateIssuer(object): def test_iter_names(self): @@ -2159,6 +2179,10 @@ def test_hash(self): assert hash(c1) == hash(c2) assert hash(c1) != hash(c3) + def test_der_string(self): + ext = x509.CRLNumber(15) + assert ext.to_der_string() == b"\x02\x01\x0f" + class TestSubjectAlternativeName(object): def test_get_values_for_type(self): @@ -2701,6 +2725,13 @@ def test_require_explicit_policy(self, backend): inhibit_policy_mapping=None, ) + def test_der_string(self): + ext = x509.PolicyConstraints( + require_explicit_policy=None, + inhibit_policy_mapping=0, + ) + assert ext.to_der_string() == b"\x30\x03\x81\x01\x00" + class TestAuthorityInformationAccess(object): def test_invalid_descriptions(self): @@ -5640,6 +5671,10 @@ def test_hash(self): assert hash(nonce1) == hash(nonce2) assert hash(nonce1) != hash(nonce3) + def test_der_string(self): + ext = x509.OCSPNonce(b"0" * 5) + assert ext.to_der_string() == b"00000" + def test_all_extension_oid_members_have_names_defined(): for oid in dir(ExtensionOID):