Skip to content

Commit 5bd0c10

Browse files
authored
allow parsing of nonstandard country name and jurisdiction country name (#6641)
The spec requires both of these to be exactly two characters to correspond with ISO country codes. Reality is sometimes messier, so this allows parsing (but not encoding) of this invalid data. Parsing will raise a UserWarning if incorrect lengths are detected.
1 parent 2b22df1 commit 5bd0c10

File tree

5 files changed

+61
-3
lines changed

5 files changed

+61
-3
lines changed

docs/development/test-vectors.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ Custom X.509 Vectors
444444
version.
445445
* ``invalid-sct-length.der`` - A certificate with an SCT with an internal
446446
length greater than the amount of data.
447+
* ``bad_country.pem`` - A certificate with country name and jurisdiction
448+
country name values in its subject and issuer distinguished names which
449+
are longer than 2 characters.
447450

448451
Custom X.509 Request Vectors
449452
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/cryptography/x509/name.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# for complete details.
44

55
import typing
6+
import warnings
67

78
from cryptography import utils
89
from cryptography.hazmat.bindings._rust import (
@@ -79,7 +80,12 @@ def _escape_dn_value(val: str) -> str:
7980

8081
class NameAttribute(object):
8182
def __init__(
82-
self, oid: ObjectIdentifier, value: str, _type=_SENTINEL
83+
self,
84+
oid: ObjectIdentifier,
85+
value: str,
86+
_type=_SENTINEL,
87+
*,
88+
_validate=True,
8389
) -> None:
8490
if not isinstance(oid, ObjectIdentifier):
8591
raise TypeError(
@@ -93,10 +99,17 @@ def __init__(
9399
oid == NameOID.COUNTRY_NAME
94100
or oid == NameOID.JURISDICTION_COUNTRY_NAME
95101
):
96-
if len(value.encode("utf8")) != 2:
102+
c_len = len(value.encode("utf8"))
103+
if c_len != 2 and _validate is True:
97104
raise ValueError(
98105
"Country name must be a 2 character country code"
99106
)
107+
elif c_len != 2:
108+
warnings.warn(
109+
"Country names should be two characters, but the "
110+
"attribute is {} characters in length.".format(c_len),
111+
stacklevel=2,
112+
)
100113

101114
# The appropriate ASN1 string type varies by OID and is defined across
102115
# multiple RFCs including 2459, 3280, and 5280. In general UTF8String

src/rust/src/x509/common.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use crate::asn1::PyAsn1Error;
66
use crate::x509;
77
use chrono::{Datelike, TimeZone, Timelike};
8+
use pyo3::types::IntoPyDict;
89
use pyo3::ToPyObject;
910
use std::collections::HashSet;
1011
use std::convert::TryInto;
@@ -382,8 +383,9 @@ fn parse_name_attribute(
382383
_ => std::str::from_utf8(attribute.value.data())
383384
.map_err(|_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue))?,
384385
};
386+
let kwargs = [("_validate", false)].into_py_dict(py);
385387
Ok(x509_module
386-
.call_method1("NameAttribute", (oid, py_data, py_tag))?
388+
.call_method("NameAttribute", (oid, py_data, py_tag), Some(kwargs))?
387389
.to_object(py))
388390
}
389391

tests/x509/test_x509.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,28 @@ def test_negative_serial_number(self, backend):
747747
with pytest.warns(utils.DeprecatedIn36):
748748
assert cert.serial_number == -18008675309
749749

750+
def test_country_jurisdiction_country_too_long(self, backend):
751+
cert = _load_cert(
752+
os.path.join("x509", "custom", "bad_country.pem"),
753+
x509.load_pem_x509_certificate,
754+
backend,
755+
)
756+
with pytest.warns(UserWarning):
757+
assert (
758+
cert.subject.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)[
759+
0
760+
].value
761+
== "too long"
762+
)
763+
764+
with pytest.warns(UserWarning):
765+
assert (
766+
cert.subject.get_attributes_for_oid(
767+
x509.NameOID.JURISDICTION_COUNTRY_NAME
768+
)[0].value
769+
== "also too long"
770+
)
771+
750772
def test_alternate_rsa_with_sha1_oid(self, backend):
751773
cert = _load_cert(
752774
os.path.join("x509", "custom", "alternate-rsa-sha1-oid.der"),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIC4DCCAcigAwIBAgICAwkwDQYJKoZIhvcNAQENBQAwMzERMA8GA1UEBhMIdG9v
3+
IGxvbmcxHjAcBgsrBgEEAYI3PAIBAxMNYWxzbyB0b28gbG9uZzAeFw0wMjAxMDEx
4+
MjAxMDBaFw0zMDEyMzEwODMwMDBaMDMxETAPBgNVBAYTCHRvbyBsb25nMR4wHAYL
5+
KwYBBAGCNzwCAQMTDWFsc28gdG9vIGxvbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IB
6+
DwAwggEKAoIBAQDBevx+d0dMqlqoMDYVij/797UhaFG6IjDl1qv8wcbP71npI+oT
7+
MLxZO3OAKrYIpuSjMGUjoxFrpao5ZhRRdOE7bEnpt4Bi5EnXLvsQ/UnpH6CLltBR
8+
54Lp9avFtab3mEgnrbjnPaAPIrLv3Nt26rRu2tmO1lZidD/cbA4zal0M26p9wp5T
9+
Y14kyHpbLEIVloBjzetoqXK6u8Hjz/APuagONypNDCySDR6M7jM85HDcLoFFrbBb
10+
8pruHSTxQejMeEmJxYf8b7rNl58/IWPB1ymbNlvHL/4oSOlnrtHkjcxRWzpQ7U3g
11+
T9BThGyhCiI7EMyEHMgP3r7kTzEUwT6IavWDAgMBAAEwDQYJKoZIhvcNAQENBQAD
12+
ggEBALEK2PhqEfqH6/q3M7Guq9E/GuB0qAlqBkZNqIzX8WdRuMKRCnE2I0TDFtbp
13+
jGrhqYcugOB12HeOWT3iSg491KDphsWGFR+La7zZkFKdSf3Cc/ktw6lOgu66CQxI
14+
Bfgp0O4yGexKYkeW1C/gQVoAzczelykfSFthG+BJsX4OGsb6g98y6fsOnHfx7s2t
15+
UkPMYUgom3fhs/J4RhRTKHAOiPBTKg91qGRcGr4TjqCRmiWVw1hFJL0p4vZopnS8
16+
VX/OrLRnNsj+VxoSIksoEUuxNdUuN4lw14IDZFUEw9CErnyisX2DEozjrg6jca8n
17+
gdJuDRk4TlNl/CpgNraJcu47pME=
18+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)