diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2017-09-26 10:23:24 +0800 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2017-09-25 22:23:24 -0400 |
commit | 72c92f5ed1a3fe1b5196e0247bbe4cbe5e93c1a7 (patch) | |
tree | 2d7c2ddc1174a8185ac1a0d13b4189ae1b70b3ad /src/cryptography/x509 | |
parent | 7bb0210ef9e4cd7c822ea3864bd7b18f3877c24b (diff) | |
download | cryptography-72c92f5ed1a3fe1b5196e0247bbe4cbe5e93c1a7.tar.gz cryptography-72c92f5ed1a3fe1b5196e0247bbe4cbe5e93c1a7.tar.bz2 cryptography-72c92f5ed1a3fe1b5196e0247bbe4cbe5e93c1a7.zip |
both parse and encode the ASN1 string type for Name attributes (#3896)
* both parse and encode the ASN1 string type for Name attributes
Previously cryptography encoded everything (except country names) as
UTF8String. This caused problems with chain building in libraries like
NSS where the subject and issuer are expected to match byte-for-byte.
With this change we now parse and store the ASN1 string type as a
private _type in NameAttribute. We then use this to encode when issuing
a new certificate. This allows the CertificateBuilder to properly
construct an identical issuer and fixes the issue with NSS.
* make the sentinel private too
Diffstat (limited to 'src/cryptography/x509')
-rw-r--r-- | src/cryptography/x509/name.py | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 108b60cc..2fbaee91 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -4,14 +4,33 @@ from __future__ import absolute_import, division, print_function +from enum import Enum + import six from cryptography import utils from cryptography.x509.oid import NameOID, ObjectIdentifier +class _ASN1Type(Enum): + UTF8String = 12 + NumericString = 18 + PrintableString = 19 + T61String = 20 + IA5String = 22 + UTCTime = 23 + GeneralizedTime = 24 + VisibleString = 26 + UniversalString = 28 + BMPString = 30 + + +_ASN1_TYPE_TO_ENUM = dict((i.value, i) for i in _ASN1Type) +_SENTINEL = object() + + class NameAttribute(object): - def __init__(self, oid, value): + def __init__(self, oid, value, _type=_SENTINEL): if not isinstance(oid, ObjectIdentifier): raise TypeError( "oid argument must be an ObjectIdentifier instance." @@ -22,16 +41,33 @@ class NameAttribute(object): "value argument must be a text type." ) - if oid == NameOID.COUNTRY_NAME and len(value.encode("utf8")) != 2: - raise ValueError( - "Country name must be a 2 character country code" - ) + if ( + oid == NameOID.COUNTRY_NAME or + oid == NameOID.JURISDICTION_COUNTRY_NAME + ): + if len(value.encode("utf8")) != 2: + raise ValueError( + "Country name must be a 2 character country code" + ) + + if _type == _SENTINEL: + _type = _ASN1Type.PrintableString if len(value) == 0: raise ValueError("Value cannot be an empty string") + # Set the default string type for encoding ASN1 strings to UTF8. This + # is the default for newer OpenSSLs for several years (1.0.1h+) and is + # recommended in RFC 2459. + if _type == _SENTINEL: + _type = _ASN1Type.UTF8String + + if not isinstance(_type, _ASN1Type): + raise TypeError("_type must be from the _ASN1Type enum") + self._oid = oid self._value = value + self._type = _type oid = utils.read_only_property("_oid") value = utils.read_only_property("_value") |