diff options
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/encode_asn1.py | 15 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 44 |
2 files changed, 54 insertions, 5 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index b0e2e73e..944dedc6 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -358,6 +358,15 @@ def _encode_subject_key_identifier(backend, ski): return _encode_asn1_str_gc(backend, ski.digest, len(ski.digest)) +def _idna_encode(value): + # Retain prefixes '*.' for common/alt names and '.' for name constraints + for prefix in ['*.', '.']: + if value.startswith(prefix): + value = value[len(prefix):] + return prefix.encode('ascii') + idna.encode(value) + return idna.encode(value) + + def _encode_general_name(backend, name): if isinstance(name, x509.DNSName): gn = backend._lib.GENERAL_NAME_new() @@ -366,11 +375,7 @@ def _encode_general_name(backend, name): ia5 = backend._lib.ASN1_IA5STRING_new() backend.openssl_assert(ia5 != backend._ffi.NULL) - - if name.value.startswith(u"*."): - value = b"*." + idna.encode(name.value[2:]) - else: - value = idna.encode(name.value) + value = _idna_encode(name.value) res = backend._lib.ASN1_STRING_set(ia5, value, len(value)) backend.openssl_assert(res == 1) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 28ddab87..f3677d11 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -17,16 +17,33 @@ from cryptography import x509 from cryptography.hazmat.backends.interfaces import ( DSABackend, EllipticCurveBackend, RSABackend, X509Backend ) +from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName from cryptography.x509.oid import ( AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, NameOID, ObjectIdentifier ) +from .hazmat.primitives.fixtures_rsa import RSA_KEY_2048 from .hazmat.primitives.test_ec import _skip_curve_unsupported from .test_x509 import _load_cert +def _make_certbuilder(private_key): + name = x509.Name( + [x509.NameAttribute(NameOID.COMMON_NAME, u'example.org')]) + return ( + x509.CertificateBuilder() + .subject_name(name) + .issuer_name(name) + .public_key(private_key.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(1999, 1, 1)) + .not_valid_after(datetime.datetime(2020, 1, 1)) + ) + + class TestExtension(object): def test_not_an_oid(self): bc = x509.BasicConstraints(ca=False, path_length=None) @@ -2141,6 +2158,19 @@ class TestRSASubjectAlternativeNameExtension(object): othernames = ext.value.get_values_for_type(x509.OtherName) assert othernames == [expected] + def test_certbuilder(self, backend): + sans = [u'*.example.org', u'*.\xf5\xe4\xf6\xfc.example.com', + u'foobar.example.net'] + private_key = RSA_KEY_2048.private_key(backend) + builder = _make_certbuilder(private_key) + builder = builder.add_extension( + SubjectAlternativeName(list(map(DNSName, sans))), True) + + cert = builder.sign(private_key, hashes.SHA1(), backend) + result = [x.value for x in cert.extensions.get_extension_for_class( + SubjectAlternativeName).value] + assert result == sans + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -2889,6 +2919,20 @@ class TestNameConstraintsExtension(object): ExtensionOID.NAME_CONSTRAINTS ) + def test_certbuilder(self, backend): + permitted = [u'.example.org', u'.\xf5\xe4\xf6\xfc.example.com', + u'foobar.example.net'] + private_key = RSA_KEY_2048.private_key(backend) + builder = _make_certbuilder(private_key) + builder = builder.add_extension( + NameConstraints(permitted_subtrees=list(map(DNSName, permitted)), + excluded_subtrees=[]), True) + + cert = builder.sign(private_key, hashes.SHA1(), backend) + result = [x.value for x in cert.extensions.get_extension_for_class( + NameConstraints).value.permitted_subtrees] + assert result == permitted + class TestDistributionPoint(object): def test_distribution_point_full_name_not_general_names(self): |