From 719d536dd691e84e208534798f2eb4f82aaa2e07 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 1 Jan 2015 20:03:52 -0600 Subject: X509 distinguished name parsing support in the OpenSSL backend --- CHANGELOG.rst | 2 + docs/x509.rst | 137 ++++++++++ src/cryptography/hazmat/backends/openssl/x509.py | 42 +++ src/cryptography/x509.py | 93 +++++++ tests/test_x509.py | 332 +++++++++++++++++++++++ 5 files changed, 606 insertions(+) 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` 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) == "" oid = x509.ObjectIdentifier("oid1") assert repr(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() -- cgit v1.2.3 From e901d642548dd268dcdc2efa60087a3fa1774fa6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 11 Feb 2015 18:50:58 -0600 Subject: refactor x509.Name to use get_attributes_by_oid --- docs/x509.rst | 101 +-------------- src/cryptography/hazmat/backends/openssl/x509.py | 2 +- src/cryptography/x509.py | 62 +--------- tests/test_x509.py | 150 +---------------------- 4 files changed, 12 insertions(+), 303 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index 33047262..282744f3 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -203,106 +203,17 @@ X.509 Certificate Object >>> len(cert.subject.attributes) 3 - .. attribute:: country_name + .. method:: get_attributes_for_oid(oid) - :type: :class:`list` + :param oid: An :class:`ObjectIdentifier` instance. - A list of country name :class:`NameAttribute` objects. + :returns: A list of :class:`NameAttribute` instances that match the + OID provided. If nothing matches an empty list will be returned. .. 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. + >>> cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME) + [, value=u'Good CA')>] .. class:: Version diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index e27d32f8..6bc7137c 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -107,7 +107,7 @@ class _Certificate(object): def _build_x509_name(self, x509_name): count = self._backend._lib.X509_NAME_entry_count(x509_name) attributes = [] - for x in range(0, count): + for x in range(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 diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 2371b36c..7eb9a608 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -108,69 +108,9 @@ class Name(object): def __init__(self, attributes): self._attributes = attributes - def _filter_attr_list(self, oid): + def get_attributes_for_oid(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[:] diff --git a/tests/test_x509.py b/tests/test_x509.py index 4794f338..c5a9e50a 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -73,17 +73,9 @@ class TestRSACertificate(object): ), x509.NameAttribute(x509.OID_COMMON_NAME, 'Good CA') ] - assert issuer.common_name == [ + assert issuer.get_attributes_for_oid(x509.OID_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( @@ -130,67 +122,6 @@ class TestRSACertificate(object): 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( @@ -212,20 +143,12 @@ class TestRSACertificate(object): 'Valid pre2000 UTC notBefore Date EE Certificate Test3' ) ] - assert subject.common_name == [ + assert subject.get_attributes_for_oid(x509.OID_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( @@ -236,13 +159,13 @@ class TestRSACertificate(object): x509.load_pem_x509_certificate, backend ) - assert cert.subject.common_name == [ + assert cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ x509.NameAttribute( x509.OID_COMMON_NAME, b'We heart UTF8!\xe2\x84\xa2'.decode('utf8') ) ] - assert cert.issuer.common_name == [ + assert cert.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ x509.NameAttribute( x509.OID_COMMON_NAME, b'We heart UTF8!\xe2\x84\xa2'.decode('utf8') @@ -297,71 +220,6 @@ class TestRSACertificate(object): 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"), -- cgit v1.2.3 From 53d8d49454d7cef5cd41fc854116090ca78026ce Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 13 Feb 2015 18:47:30 -0600 Subject: make x509.Name iterable and address other review feedback --- docs/spelling_wordlist.txt | 1 + docs/x509.rst | 23 +++++++++++------------ src/cryptography/x509.py | 12 +++++++----- tests/test_x509.py | 26 ++++++++++++++++++++------ 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 003e37d5..fefd26b3 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -29,6 +29,7 @@ interoperable introspectability invariants iOS +iterable Koblitz Lange metadata diff --git a/docs/x509.rst b/docs/x509.rst index 282744f3..473efc36 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -187,21 +187,20 @@ X.509 Certificate Object .. 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 + An X509 Name is an ordered list of attributes. The object is iterable to + get every attribute 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``). + slash or comma delimited string (e.g. ``/CN=mydomain.com/O=My Org/C=US`` or + ``CN=mydomain.com, O=My Org, C=US``). - .. attribute:: attributes + .. doctest:: - :type: :class:`list` - - A list of all the :class:`NameAttribute` objects. - - .. doctest:: - - >>> len(cert.subject.attributes) - 3 + >>> assert len(cert.subject) == 3 + >>> attributes = [] + >>> for attribute in cert.subject: + ... attributes.append(attribute) + >>> len(attributes) + 3 .. method:: get_attributes_for_oid(oid) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 7eb9a608..21693ed4 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -111,19 +111,21 @@ class Name(object): def get_attributes_for_oid(self, oid): return [i for i in self._attributes if i.oid == oid] - @property - def attributes(self): - return self._attributes[:] - def __eq__(self, other): if not isinstance(other, Name): return NotImplemented - return self.attributes == other.attributes + return self._attributes == other._attributes def __ne__(self, other): return not self == other + def __iter__(self): + return iter(self._attributes[:]) + + def __len__(self): + return len(self._attributes) + OID_COMMON_NAME = ObjectIdentifier("2.5.4.3") OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6") diff --git a/tests/test_x509.py b/tests/test_x509.py index c5a9e50a..0e95b258 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -10,6 +10,8 @@ import os import pytest +import six + from cryptography import x509 from cryptography.hazmat.backends.interfaces import ( DSABackend, EllipticCurveBackend, RSABackend, X509Backend @@ -66,7 +68,10 @@ class TestRSACertificate(object): ) issuer = cert.issuer assert isinstance(issuer, x509.Name) - assert issuer.attributes == [ + attributes = [] + for attrs in issuer: + attributes.append(attrs) + assert attributes == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute( x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011' @@ -89,7 +94,10 @@ class TestRSACertificate(object): issuer = cert.issuer assert isinstance(issuer, x509.Name) - assert issuer.attributes == [ + attributes = [] + for attrs in issuer: + attributes.append(attrs) + assert attributes == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute(x509.OID_COUNTRY_NAME, 'CA'), x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), @@ -133,7 +141,10 @@ class TestRSACertificate(object): ) subject = cert.subject assert isinstance(subject, x509.Name) - assert subject.attributes == [ + attributes = [] + for attrs in subject: + attributes.append(attrs) + assert attributes == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute( x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011' @@ -162,13 +173,13 @@ class TestRSACertificate(object): assert cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ x509.NameAttribute( x509.OID_COMMON_NAME, - b'We heart UTF8!\xe2\x84\xa2'.decode('utf8') + six.u('We heart UTF8!\u2122') ) ] assert cert.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ x509.NameAttribute( x509.OID_COMMON_NAME, - b'We heart UTF8!\xe2\x84\xa2'.decode('utf8') + six.u('We heart UTF8!\u2122') ) ] @@ -183,7 +194,10 @@ class TestRSACertificate(object): ) subject = cert.subject assert isinstance(subject, x509.Name) - assert subject.attributes == [ + attributes = [] + for attrs in subject: + attributes.append(attrs) + assert attributes == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'AU'), x509.NameAttribute(x509.OID_COUNTRY_NAME, 'DE'), x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'California'), -- cgit v1.2.3 From 5ab6d6a5c05572bd1c75f05baf264a2d0001894a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 13 Feb 2015 19:19:16 -0600 Subject: update buffer length for OBJ_obj2txt --- src/cryptography/hazmat/backends/openssl/x509.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 6bc7137c..ebfbf331 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -120,7 +120,9 @@ class _Certificate(object): buf, lambda buf: self._backend._lib.OPENSSL_free(buf[0]) ) value = self._backend._ffi.buffer(buf[0], res)[:].decode('utf8') - buf_len = 50 + # Set to 80 on the recommendation of + # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html + buf_len = 80 buf = self._backend._ffi.new("char[]", buf_len) res = self._backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1) assert res > 0 -- cgit v1.2.3 From 8b21a4a34a82ca0e73ca67bd3f148b25d6c7bdc6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 14 Feb 2015 07:56:36 -0600 Subject: simplify things based on review feedback --- docs/x509.rst | 11 ++++++----- src/cryptography/hazmat/backends/openssl/x509.py | 1 + src/cryptography/x509.py | 2 +- tests/test_x509.py | 20 ++++---------------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index 473efc36..099d3f87 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -195,12 +195,13 @@ X.509 Certificate Object .. doctest:: - >>> assert len(cert.subject) == 3 - >>> attributes = [] - >>> for attribute in cert.subject: - ... attributes.append(attribute) - >>> len(attributes) + >>> len(cert.subject) 3 + >>> for attribute in cert.subject: + ... print(attribute) + , value=u'US')> + , value=u'Test Certificates 2011')> + , value=u'Good CA')> .. method:: get_attributes_for_oid(oid) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index ebfbf331..76dcf32f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -115,6 +115,7 @@ class _Certificate(object): assert data != self._backend._ffi.NULL buf = self._backend._ffi.new("unsigned char **") res = self._backend._lib.ASN1_STRING_to_UTF8(buf, data) + assert res >= 0 assert buf[0] != self._backend._ffi.NULL buf = self._backend._ffi.gc( buf, lambda buf: self._backend._lib.OPENSSL_free(buf[0]) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 21693ed4..8a888d2a 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -121,7 +121,7 @@ class Name(object): return not self == other def __iter__(self): - return iter(self._attributes[:]) + return iter(self._attributes) def __len__(self): return len(self._attributes) diff --git a/tests/test_x509.py b/tests/test_x509.py index 0e95b258..55a94084 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -68,10 +68,7 @@ class TestRSACertificate(object): ) issuer = cert.issuer assert isinstance(issuer, x509.Name) - attributes = [] - for attrs in issuer: - attributes.append(attrs) - assert attributes == [ + assert list(issuer) == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute( x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011' @@ -94,10 +91,7 @@ class TestRSACertificate(object): issuer = cert.issuer assert isinstance(issuer, x509.Name) - attributes = [] - for attrs in issuer: - attributes.append(attrs) - assert attributes == [ + assert list(issuer) == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute(x509.OID_COUNTRY_NAME, 'CA'), x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'), @@ -141,10 +135,7 @@ class TestRSACertificate(object): ) subject = cert.subject assert isinstance(subject, x509.Name) - attributes = [] - for attrs in subject: - attributes.append(attrs) - assert attributes == [ + assert list(subject) == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'), x509.NameAttribute( x509.OID_ORGANIZATION_NAME, 'Test Certificates 2011' @@ -194,10 +185,7 @@ class TestRSACertificate(object): ) subject = cert.subject assert isinstance(subject, x509.Name) - attributes = [] - for attrs in subject: - attributes.append(attrs) - assert attributes == [ + assert list(subject) == [ x509.NameAttribute(x509.OID_COUNTRY_NAME, 'AU'), x509.NameAttribute(x509.OID_COUNTRY_NAME, 'DE'), x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'California'), -- cgit v1.2.3 From d21596e1704103d6345cd7979d1f97a2d8ca8bea Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 14 Feb 2015 09:17:26 -0600 Subject: update docs --- docs/x509.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/x509.rst b/docs/x509.rst index 099d3f87..6067ca55 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -188,7 +188,7 @@ X.509 Certificate Object .. versionadded:: 0.8 An X509 Name is an ordered list of attributes. The object is iterable to - get every attribute or you can use the helper properties to + get every attribute or you can use :meth:`Name.get_attributes_for_oid` 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`` or ``CN=mydomain.com, O=My Org, C=US``). -- cgit v1.2.3