aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2015-01-01 20:03:52 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2015-02-12 18:58:14 -0600
commit719d536dd691e84e208534798f2eb4f82aaa2e07 (patch)
treeecbe47cdda225afe629273d702d1ee2fd8d86811
parentcd9bdcddf7ea7fe041ffcb01965a035e64ab719e (diff)
downloadcryptography-719d536dd691e84e208534798f2eb4f82aaa2e07.tar.gz
cryptography-719d536dd691e84e208534798f2eb4f82aaa2e07.tar.bz2
cryptography-719d536dd691e84e208534798f2eb4f82aaa2e07.zip
X509 distinguished name parsing support in the OpenSSL backend
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/x509.rst137
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py42
-rw-r--r--src/cryptography/x509.py93
-rw-r--r--tests/test_x509.py332
5 files changed, 606 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c916beaa..cee4a321 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -33,6 +33,8 @@ Changelog
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithNumbers`
were moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric.rsa`.
+* Added support for parsing X.509 names. See the
+ :doc:`X.509 documentation</x509>` for more information.
0.7.2 - 2015-01-16
~~~~~~~~~~~~~~~~~~
diff --git a/docs/x509.rst b/docs/x509.rst
index 26dd2a07..33047262 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -166,6 +166,143 @@ X.509 Certificate Object
>>> cert.not_valid_after
datetime.datetime(2030, 12, 31, 8, 30)
+ .. attribute:: issuer
+
+ .. versionadded:: 0.8
+
+ :type: :class:`Name`
+
+ The :class:`Name` of the issuer.
+
+ .. attribute:: subject
+
+ .. versionadded:: 0.8
+
+ :type: :class:`Name`
+
+ The :class:`Name` of the subject.
+
+
+.. class:: Name
+
+ .. versionadded:: 0.8
+
+ An X509 Name is an ordered list of attributes. The entire list can be
+ obtained with :attr:`attributes` or you can use the helper properties to
+ obtain the specific type you want. Names are sometimes represented as a
+ slash or comma delimited string (e.g. ``/CN=mydomain.com/O=My Org/C=US``).
+
+ .. attribute:: attributes
+
+ :type: :class:`list`
+
+ A list of all the :class:`NameAttribute` objects.
+
+ .. doctest::
+
+ >>> len(cert.subject.attributes)
+ 3
+
+ .. attribute:: country_name
+
+ :type: :class:`list`
+
+ A list of country name :class:`NameAttribute` objects.
+
+ .. doctest::
+
+ >>> cert.subject.country_name == [
+ ... x509.NameAttribute(
+ ... x509.OID_COUNTRY_NAME,
+ ... 'US'
+ ... )
+ ... ]
+ True
+
+ .. attribute:: organization_name
+
+ :type: :class:`list`
+
+ A list of organization name :class:`NameAttribute` objects.
+
+ .. attribute:: organizational_unit_name
+
+ :type: :class:`list`
+
+ A list of organizational unit name :class:`NameAttribute` objects.
+
+ .. attribute:: dn_qualifier
+
+ :type: :class:`list`
+
+ A list of DN qualifier :class:`NameAttribute` objects.
+
+ .. attribute:: state_or_province_name
+
+ :type: :class:`list`
+
+ A list of state or province name :class:`NameAttribute` objects.
+
+ .. attribute:: common_name
+
+ :type: :class:`list`
+
+ A list of common name :class:`NameAttribute` objects.
+
+ .. attribute:: serial_number
+
+ :type: :class:`list`
+
+ A list of serial number :class:`NameAttribute` objects. This is not the
+ same as the certificate's serial number.
+
+ .. attribute:: locality_name
+
+ :type: :class:`list`
+
+ A list of locality name :class:`NameAttribute` objects.
+
+ .. attribute:: title
+
+ :type: :class:`list`
+
+ A list of title :class:`NameAttribute` objects.
+
+ .. attribute:: surname
+
+ :type: :class:`list`
+
+ A list of surname :class:`NameAttribute` objects.
+
+ .. attribute:: given_name
+
+ :type: :class:`list`
+
+ A list of given name :class:`NameAttribute` objects.
+
+ .. attribute:: pseudonym
+
+ :type: :class:`list`
+
+ A list of pseudonym :class:`NameAttribute` objects.
+
+ .. attribute:: generation_qualifier
+
+ :type: :class:`list`
+
+ A list of generation qualifier :class:`NameAttribute` objects.
+
+ .. attribute:: domain_component
+
+ :type: :class:`list`
+
+ A list of domain component :class:`NameAttribute` objects.
+
+ .. attribute:: email_address
+
+ :type: :class:`list`
+
+ A list of email address :class:`NameAttribute` objects.
.. class:: Version
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 66c99c9f..e27d32f8 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -91,3 +91,45 @@ class _Certificate(object):
)
).decode("ascii")
return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+
+ @property
+ def issuer(self):
+ issuer = self._backend._lib.X509_get_issuer_name(self._x509)
+ assert issuer != self._backend._ffi.NULL
+ return self._build_x509_name(issuer)
+
+ @property
+ def subject(self):
+ subject = self._backend._lib.X509_get_subject_name(self._x509)
+ assert subject != self._backend._ffi.NULL
+ return self._build_x509_name(subject)
+
+ def _build_x509_name(self, x509_name):
+ count = self._backend._lib.X509_NAME_entry_count(x509_name)
+ attributes = []
+ for x in range(0, count):
+ entry = self._backend._lib.X509_NAME_get_entry(x509_name, x)
+ obj = self._backend._lib.X509_NAME_ENTRY_get_object(entry)
+ assert obj != self._backend._ffi.NULL
+ data = self._backend._lib.X509_NAME_ENTRY_get_data(entry)
+ assert data != self._backend._ffi.NULL
+ buf = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.ASN1_STRING_to_UTF8(buf, data)
+ assert buf[0] != self._backend._ffi.NULL
+ buf = self._backend._ffi.gc(
+ buf, lambda buf: self._backend._lib.OPENSSL_free(buf[0])
+ )
+ value = self._backend._ffi.buffer(buf[0], res)[:].decode('utf8')
+ buf_len = 50
+ buf = self._backend._ffi.new("char[]", buf_len)
+ res = self._backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
+ assert res > 0
+ oid = self._backend._ffi.buffer(buf, res)[:].decode()
+
+ attributes.append(
+ x509.NameAttribute(
+ x509.ObjectIdentifier(oid), value
+ )
+ )
+
+ return x509.Name(attributes)
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 71062588..2371b36c 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -104,6 +104,87 @@ class ObjectIdentifier(object):
dotted_string = utils.read_only_property("_dotted_string")
+class Name(object):
+ def __init__(self, attributes):
+ self._attributes = attributes
+
+ def _filter_attr_list(self, oid):
+ return [i for i in self._attributes if i.oid == oid]
+
+ @property
+ def common_name(self):
+ return self._filter_attr_list(OID_COMMON_NAME)
+
+ @property
+ def country_name(self):
+ return self._filter_attr_list(OID_COUNTRY_NAME)
+
+ @property
+ def locality_name(self):
+ return self._filter_attr_list(OID_LOCALITY_NAME)
+
+ @property
+ def state_or_province_name(self):
+ return self._filter_attr_list(OID_STATE_OR_PROVINCE_NAME)
+
+ @property
+ def organization_name(self):
+ return self._filter_attr_list(OID_ORGANIZATION_NAME)
+
+ @property
+ def organizational_unit_name(self):
+ return self._filter_attr_list(OID_ORGANIZATIONAL_UNIT_NAME)
+
+ @property
+ def serial_number(self):
+ return self._filter_attr_list(OID_SERIAL_NUMBER)
+
+ @property
+ def surname(self):
+ return self._filter_attr_list(OID_SURNAME)
+
+ @property
+ def given_name(self):
+ return self._filter_attr_list(OID_GIVEN_NAME)
+
+ @property
+ def title(self):
+ return self._filter_attr_list(OID_TITLE)
+
+ @property
+ def generation_qualifier(self):
+ return self._filter_attr_list(OID_GENERATION_QUALIFIER)
+
+ @property
+ def dn_qualifier(self):
+ return self._filter_attr_list(OID_DN_QUALIFIER)
+
+ @property
+ def pseudonym(self):
+ return self._filter_attr_list(OID_PSEUDONYM)
+
+ @property
+ def domain_component(self):
+ return self._filter_attr_list(OID_DOMAIN_COMPONENT)
+
+ @property
+ def email_address(self):
+ return self._filter_attr_list(OID_EMAIL_ADDRESS)
+
+ @property
+ def attributes(self):
+ return self._attributes[:]
+
+ def __eq__(self, other):
+ if not isinstance(other, Name):
+ return NotImplemented
+
+ return self.attributes == other.attributes
+
+ def __ne__(self, other):
+ return not self == other
+
+
OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
@@ -158,3 +239,15 @@ class Certificate(object):
"""
Not after time (represented as UTC datetime)
"""
+
+ @abc.abstractproperty
+ def issuer(self):
+ """
+ Returns the issuer name object.
+ """
+
+ @abc.abstractproperty
+ def subject(self):
+ """
+ Returns the subject name object.
+ """
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 09275207..4794f338 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -55,6 +55,313 @@ class TestRSACertificate(object):
fingerprint = binascii.hexlify(cert.fingerprint(hashes.SHA1()))
assert fingerprint == b"6f49779533d565e8b7c1062503eab41492c38e4d"
+ def test_issuer(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "PKITS_data", "certs",
+ "Validpre2000UTCnotBeforeDateTest3EE.crt"
+ ),
+ x509.load_der_x509_certificate,
+ backend
+ )
+ issuer = cert.issuer
+ assert isinstance(issuer, x509.Name)
+ assert issuer.attributes == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011'
+ ),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'Good CA')
+ ]
+ assert issuer.common_name == [
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'Good CA')
+ ]
+ assert issuer.country_name == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ ]
+ assert issuer.organization_name == [
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011'
+ ),
+ ]
+
+ def test_all_issuer_name_types(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom",
+ "all_supported_names.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ issuer = cert.issuer
+
+ assert isinstance(issuer, x509.Name)
+ assert issuer.attributes == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'CA'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Illinois'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Chicago'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Zero, LLC'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'One, LLC'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'common name 0'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'common name 1'),
+ x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, 'OU 0'),
+ x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, 'OU 1'),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'dnQualifier0'),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'dnQualifier1'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '123'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '456'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title 0'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title 1'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Surname 0'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Surname 1'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'Given Name 0'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'Given Name 1'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Incognito 0'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Incognito 1'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Last Gen'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Next Gen'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc0'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc1'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test0@test.local'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test1@test.local'),
+ ]
+
+ assert issuer.country_name == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'CA'),
+ ]
+ assert issuer.state_or_province_name == [
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Illinois'),
+ ]
+ assert issuer.locality_name == [
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Chicago'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'),
+ ]
+ assert issuer.organization_name == [
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Zero, LLC'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'One, LLC'),
+ ]
+ assert issuer.common_name == [
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'common name 0'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'common name 1'),
+ ]
+ assert issuer.organizational_unit_name == [
+ x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, 'OU 0'),
+ x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, 'OU 1'),
+ ]
+ assert issuer.dn_qualifier == [
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'dnQualifier0'),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'dnQualifier1'),
+ ]
+ assert issuer.serial_number == [
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '123'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '456'),
+ ]
+ assert issuer.title == [
+ x509.NameAttribute(x509.OID_TITLE, 'Title 0'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title 1'),
+ ]
+ assert issuer.surname == [
+ x509.NameAttribute(x509.OID_SURNAME, 'Surname 0'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Surname 1'),
+ ]
+ assert issuer.given_name == [
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'Given Name 0'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'Given Name 1'),
+ ]
+ assert issuer.pseudonym == [
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Incognito 0'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Incognito 1'),
+ ]
+ assert issuer.generation_qualifier == [
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Last Gen'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Next Gen'),
+ ]
+ assert issuer.domain_component == [
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc0'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc1'),
+ ]
+ assert issuer.email_address == [
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test0@test.local'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test1@test.local'),
+ ]
+
+ def test_subject(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "PKITS_data", "certs",
+ "Validpre2000UTCnotBeforeDateTest3EE.crt"
+ ),
+ x509.load_der_x509_certificate,
+ backend
+ )
+ subject = cert.subject
+ assert isinstance(subject, x509.Name)
+ assert subject.attributes == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011'
+ ),
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ 'Valid pre2000 UTC notBefore Date EE Certificate Test3'
+ )
+ ]
+ assert subject.common_name == [
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ 'Valid pre2000 UTC notBefore Date EE Certificate Test3'
+ )
+ ]
+ assert subject.country_name == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+ ]
+ assert subject.organization_name == [
+ x509.NameAttribute(
+ x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011'
+ ),
+ ]
+
+ def test_unicode_name(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom",
+ "utf8_common_name.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ assert cert.subject.common_name == [
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ b'We heart UTF8!\xe2\x84\xa2'.decode('utf8')
+ )
+ ]
+ assert cert.issuer.common_name == [
+ x509.NameAttribute(
+ x509.OID_COMMON_NAME,
+ b'We heart UTF8!\xe2\x84\xa2'.decode('utf8')
+ )
+ ]
+
+ def test_all_subject_name_types(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509", "custom",
+ "all_supported_names.pem"
+ ),
+ x509.load_pem_x509_certificate,
+ backend
+ )
+ subject = cert.subject
+ assert isinstance(subject, x509.Name)
+ assert subject.attributes == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'AU'),
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'DE'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'California'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'New York'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'San Francisco'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Ithaca'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Org Zero, LLC'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Org One, LLC'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'CN 0'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'CN 1'),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME, 'Engineering 0'
+ ),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME, 'Engineering 1'
+ ),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'qualified0'),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'qualified1'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '789'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '012'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title IX'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title X'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Last 0'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Last 1'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'First 0'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'First 1'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Guy Incognito 0'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Guy Incognito 1'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, '32X'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Dreamcast'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc2'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc3'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test2@test.local'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test3@test.local'),
+ ]
+
+ assert subject.country_name == [
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'AU'),
+ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'DE'),
+ ]
+ assert subject.state_or_province_name == [
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'California'),
+ x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'New York'),
+ ]
+ assert subject.locality_name == [
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'San Francisco'),
+ x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Ithaca'),
+ ]
+ assert subject.organization_name == [
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Org Zero, LLC'),
+ x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'Org One, LLC'),
+ ]
+ assert subject.common_name == [
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'CN 0'),
+ x509.NameAttribute(x509.OID_COMMON_NAME, 'CN 1'),
+ ]
+ assert subject.organizational_unit_name == [
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME, 'Engineering 0'
+ ),
+ x509.NameAttribute(
+ x509.OID_ORGANIZATIONAL_UNIT_NAME, 'Engineering 1'
+ ),
+ ]
+ assert subject.dn_qualifier == [
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'qualified0'),
+ x509.NameAttribute(x509.OID_DN_QUALIFIER, 'qualified1'),
+ ]
+ assert subject.serial_number == [
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '789'),
+ x509.NameAttribute(x509.OID_SERIAL_NUMBER, '012'),
+ ]
+ assert subject.title == [
+ x509.NameAttribute(x509.OID_TITLE, 'Title IX'),
+ x509.NameAttribute(x509.OID_TITLE, 'Title X'),
+ ]
+ assert subject.surname == [
+ x509.NameAttribute(x509.OID_SURNAME, 'Last 0'),
+ x509.NameAttribute(x509.OID_SURNAME, 'Last 1'),
+ ]
+ assert subject.given_name == [
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'First 0'),
+ x509.NameAttribute(x509.OID_GIVEN_NAME, 'First 1'),
+ ]
+ assert subject.pseudonym == [
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Guy Incognito 0'),
+ x509.NameAttribute(x509.OID_PSEUDONYM, 'Guy Incognito 1'),
+ ]
+ assert subject.generation_qualifier == [
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, '32X'),
+ x509.NameAttribute(x509.OID_GENERATION_QUALIFIER, 'Dreamcast'),
+ ]
+ assert subject.domain_component == [
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc2'),
+ x509.NameAttribute(x509.OID_DOMAIN_COMPONENT, 'dc3'),
+ ]
+ assert subject.email_address == [
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test2@test.local'),
+ x509.NameAttribute(x509.OID_EMAIL_ADDRESS, 'test3@test.local'),
+ ]
+
def test_load_good_ca_cert(self, backend):
cert = _load_cert(
os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"),
@@ -301,3 +608,28 @@ class TestObjectIdentifier(object):
assert repr(oid) == "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>"
oid = x509.ObjectIdentifier("oid1")
assert repr(oid) == "<ObjectIdentifier(oid=oid1, name=Unknown OID)>"
+
+
+class TestName(object):
+ def test_eq(self):
+ name1 = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ ])
+ name2 = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ ])
+ assert name1 == name2
+
+ def test_ne(self):
+ name1 = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ ])
+ name2 = x509.Name([
+ x509.NameAttribute(x509.ObjectIdentifier('oid2'), 'value2'),
+ x509.NameAttribute(x509.ObjectIdentifier('oid'), 'value1'),
+ ])
+ assert name1 != name2
+ assert name1 != object()