diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 6a81da2c359d..0cd10439c083 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -444,6 +444,9 @@ Custom X.509 Vectors version. * ``invalid-sct-length.der`` - A certificate with an SCT with an internal length greater than the amount of data. +* ``bad_country.pem`` - A certificate with country name and jurisdiction + country name values in its subject and issuer distinguished names which + are longer than 2 characters. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 925a88f07e01..b02f08babc4a 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -3,6 +3,7 @@ # for complete details. import typing +import warnings from cryptography import utils from cryptography.hazmat.bindings._rust import ( @@ -79,7 +80,12 @@ def _escape_dn_value(val: str) -> str: class NameAttribute(object): def __init__( - self, oid: ObjectIdentifier, value: str, _type=_SENTINEL + self, + oid: ObjectIdentifier, + value: str, + _type=_SENTINEL, + *, + _validate=True, ) -> None: if not isinstance(oid, ObjectIdentifier): raise TypeError( @@ -93,10 +99,17 @@ def __init__( oid == NameOID.COUNTRY_NAME or oid == NameOID.JURISDICTION_COUNTRY_NAME ): - if len(value.encode("utf8")) != 2: + c_len = len(value.encode("utf8")) + if c_len != 2 and _validate is True: raise ValueError( "Country name must be a 2 character country code" ) + elif c_len != 2: + warnings.warn( + "Country names should be two characters, but the " + "attribute is {} characters in length.".format(c_len), + stacklevel=2, + ) # The appropriate ASN1 string type varies by OID and is defined across # multiple RFCs including 2459, 3280, and 5280. In general UTF8String diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 4b3ae5b01963..e3b36c8a26dc 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -5,6 +5,7 @@ use crate::asn1::PyAsn1Error; use crate::x509; use chrono::{Datelike, TimeZone, Timelike}; +use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::HashSet; use std::convert::TryInto; @@ -382,8 +383,9 @@ fn parse_name_attribute( _ => std::str::from_utf8(attribute.value.data()) .map_err(|_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue))?, }; + let kwargs = [("_validate", false)].into_py_dict(py); Ok(x509_module - .call_method1("NameAttribute", (oid, py_data, py_tag))? + .call_method("NameAttribute", (oid, py_data, py_tag), Some(kwargs))? .to_object(py)) } diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 17076d992c34..23e97a7684f7 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -747,6 +747,28 @@ def test_negative_serial_number(self, backend): with pytest.warns(utils.DeprecatedIn36): assert cert.serial_number == -18008675309 + def test_country_jurisdiction_country_too_long(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "bad_country.pem"), + x509.load_pem_x509_certificate, + backend, + ) + with pytest.warns(UserWarning): + assert ( + cert.subject.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)[ + 0 + ].value + == "too long" + ) + + with pytest.warns(UserWarning): + assert ( + cert.subject.get_attributes_for_oid( + x509.NameOID.JURISDICTION_COUNTRY_NAME + )[0].value + == "also too long" + ) + def test_alternate_rsa_with_sha1_oid(self, backend): cert = _load_cert( os.path.join("x509", "custom", "alternate-rsa-sha1-oid.der"), diff --git a/vectors/cryptography_vectors/x509/custom/bad_country.pem b/vectors/cryptography_vectors/x509/custom/bad_country.pem new file mode 100644 index 000000000000..fd4d60170cb2 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/bad_country.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC4DCCAcigAwIBAgICAwkwDQYJKoZIhvcNAQENBQAwMzERMA8GA1UEBhMIdG9v +IGxvbmcxHjAcBgsrBgEEAYI3PAIBAxMNYWxzbyB0b28gbG9uZzAeFw0wMjAxMDEx +MjAxMDBaFw0zMDEyMzEwODMwMDBaMDMxETAPBgNVBAYTCHRvbyBsb25nMR4wHAYL +KwYBBAGCNzwCAQMTDWFsc28gdG9vIGxvbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDBevx+d0dMqlqoMDYVij/797UhaFG6IjDl1qv8wcbP71npI+oT +MLxZO3OAKrYIpuSjMGUjoxFrpao5ZhRRdOE7bEnpt4Bi5EnXLvsQ/UnpH6CLltBR +54Lp9avFtab3mEgnrbjnPaAPIrLv3Nt26rRu2tmO1lZidD/cbA4zal0M26p9wp5T +Y14kyHpbLEIVloBjzetoqXK6u8Hjz/APuagONypNDCySDR6M7jM85HDcLoFFrbBb +8pruHSTxQejMeEmJxYf8b7rNl58/IWPB1ymbNlvHL/4oSOlnrtHkjcxRWzpQ7U3g +T9BThGyhCiI7EMyEHMgP3r7kTzEUwT6IavWDAgMBAAEwDQYJKoZIhvcNAQENBQAD +ggEBALEK2PhqEfqH6/q3M7Guq9E/GuB0qAlqBkZNqIzX8WdRuMKRCnE2I0TDFtbp +jGrhqYcugOB12HeOWT3iSg491KDphsWGFR+La7zZkFKdSf3Cc/ktw6lOgu66CQxI +Bfgp0O4yGexKYkeW1C/gQVoAzczelykfSFthG+BJsX4OGsb6g98y6fsOnHfx7s2t +UkPMYUgom3fhs/J4RhRTKHAOiPBTKg91qGRcGr4TjqCRmiWVw1hFJL0p4vZopnS8 +VX/OrLRnNsj+VxoSIksoEUuxNdUuN4lw14IDZFUEw9CErnyisX2DEozjrg6jca8n +gdJuDRk4TlNl/CpgNraJcu47pME= +-----END CERTIFICATE-----