Skip to content

Commit

Permalink
Enforce length for CommonName
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed Jul 5, 2024
1 parent 2b371f4 commit 0f2c5b5
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ Changelog
* Added :meth:`~cryptography.hazmat.primitives.ciphers.CipherContext.reset_nonce`
for altering the ``nonce`` of a cipher context without initializing a new
instance. See the docs for additional restrictions.
* :class:`~cryptography.x509.NameAttribute` now raises an exception when
attempting to create a common name whose length is shorter or longer than
:rfc:`5280` permits.

.. _v42-0-8:

Expand Down
27 changes: 17 additions & 10 deletions src/cryptography/x509/name.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class _ASN1Type(utils.Enum):
}
_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()}

_NAMEOID_LENGTH_LIMIT = {
NameOID.COUNTRY_NAME: (2, 2),
NameOID.JURISDICTION_COUNTRY_NAME: (2, 2),
NameOID.COMMON_NAME: (1, 64),
}


def _escape_dn_value(val: str | bytes) -> str:
"""Escape special characters in RFC4514 Distinguished Name value."""
Expand Down Expand Up @@ -132,19 +138,20 @@ def __init__(
if not isinstance(value, str):
raise TypeError("value argument must be a str")

if oid in (NameOID.COUNTRY_NAME, NameOID.JURISDICTION_COUNTRY_NAME):
length_limits = _NAMEOID_LENGTH_LIMIT.get(oid)
if length_limits is not None:
min_length, max_length = length_limits
assert isinstance(value, str)
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 "
f"attribute is {c_len} characters in length.",
stacklevel=2,
if c_len < min_length or c_len > max_length:
msg = (
f"Attribute's length must be >= {min_length} and "
f"<= {max_length}, but it was {c_len}"
)
if _validate is True:
raise ValueError(msg)
else:
warnings.warn(msg, stacklevel=2)

# The appropriate ASN1 string type varies by OID and is defined across
# multiple RFCs including 2459, 3280, and 5280. In general UTF8String
Expand Down
9 changes: 8 additions & 1 deletion tests/x509/test_x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -5809,14 +5809,21 @@ def test_init_none_value(self):
None, # type:ignore[arg-type]
)

def test_init_bad_country_code_value(self):
def test_init_bad_length(self):
with pytest.raises(ValueError):
x509.NameAttribute(NameOID.COUNTRY_NAME, "United States")

# unicode string of length 2, but > 2 bytes
with pytest.raises(ValueError):
x509.NameAttribute(NameOID.COUNTRY_NAME, "\U0001f37a\U0001f37a")

with pytest.raises(ValueError):
x509.NameAttribute(NameOID.JURISDICTION_COUNTRY_NAME, "Too Long")
with pytest.raises(ValueError):
x509.NameAttribute(NameOID.COMMON_NAME, "Too Long" * 10)
with pytest.raises(ValueError):
x509.NameAttribute(NameOID.COMMON_NAME, "")

def test_invalid_type(self):
with pytest.raises(TypeError):
x509.NameAttribute(
Expand Down

0 comments on commit 0f2c5b5

Please sign in to comment.