aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/glossary.rst4
-rw-r--r--docs/x509.rst120
-rw-r--r--src/cryptography/x509.py86
-rw-r--r--tests/test_x509.py42
4 files changed, 252 insertions, 0 deletions
diff --git a/docs/glossary.rst b/docs/glossary.rst
index ef422a6e..dc6f3ebf 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -60,3 +60,7 @@ Glossary
This is a property of encryption systems whereby two encrypted messages
aren't distinguishable without knowing the encryption key. This is
considered a basic, necessary property for a working encryption system.
+
+ text
+ This type corresponds to ``unicode`` on Python 2 and ``str`` on Python
+ 3. This is equivalent to ``six.text_type``.
diff --git a/docs/x509.rst b/docs/x509.rst
index 26b91873..26dd2a07 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -181,6 +181,126 @@ X.509 Certificate Object
For version 3 X.509 certificates.
+.. class:: NameAttribute
+
+ .. versionadded:: 0.8
+
+ An X.509 name consists of a list of NameAttribute instances.
+
+ .. attribute:: oid
+
+ :type: :class:`ObjectIdentifier`
+
+ The attribute OID.
+
+ .. attribute:: value
+
+ :type: :term:`text`
+
+ The value of the attribute.
+
+.. class:: ObjectIdentifier
+
+ .. versionadded:: 0.8
+
+ Object identifiers (frequently seen abbreviated as OID) identify the type
+ of a value (see: :class:`NameAttribute`).
+
+ .. attribute:: dotted_string
+
+ :type: :class:`str`
+
+ The dotted string value of the OID (e.g. ``"2.5.4.3"``)
+
+Object Identifiers
+~~~~~~~~~~~~~~~~~~
+
+X.509 elements are frequently identified by :class:`ObjectIdentifier`
+instances. The following common OIDs are available as constants.
+
+.. data:: OID_COMMON_NAME
+
+ Corresponds to the dotted string ``"2.5.4.3"``. Historically the domain
+ name would be encoded here for server certificates. :rfc:`2818` deprecates
+ this practice and names of that type should now be located in a
+ SubjectAlternativeName extension. This OID is typically seen in X.509 names.
+
+.. data:: OID_COUNTRY_NAME
+
+ Corresponds to the dotted string ``"2.5.4.6"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_LOCALITY_NAME
+
+ Corresponds to the dotted string ``"2.5.4.7"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_STATE_OR_PROVINCE_NAME
+
+ Corresponds to the dotted string ``"2.5.4.8"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_ORGANIZATION_NAME
+
+ Corresponds to the dotted string ``"2.5.4.10"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_ORGANIZATIONAL_UNIT_NAME
+
+ Corresponds to the dotted string ``"2.5.4.11"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_SERIAL_NUMBER
+
+ Corresponds to the dotted string ``"2.5.4.5"``. This is distinct from the
+ serial number of the certificate itself (which can be obtained with
+ :func:`Certificate.serial`). This OID is typically seen in X.509 names.
+
+.. data:: OID_SURNAME
+
+ Corresponds to the dotted string ``"2.5.4.4"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_GIVEN_NAME
+
+ Corresponds to the dotted string ``"2.5.4.42"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_TITLE
+
+ Corresponds to the dotted string ``"2.5.4.12"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_GENERATION_QUALIFIER
+
+ Corresponds to the dotted string ``"2.5.4.44"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_DN_QUALIFIER
+
+ Corresponds to the dotted string ``"2.5.4.46"``. This specifies
+ disambiguating information to add to the relative distinguished name of an
+ entry. See :rfc:`2256`. This OID is typically seen in X.509 names.
+
+.. data:: OID_PSEUDONYM
+
+ Corresponds to the dotted string ``"2.5.4.65"``. This OID is typically seen
+ in X.509 names.
+
+.. data:: OID_DOMAIN_COMPONENT
+
+ Corresponds to the dotted string ``"0.9.2342.19200300.100.1.25"``. A string
+ holding one component of a domain name. See :rfc:`4519`. This OID is
+ typically seen in X.509 names.
+
+.. data:: OID_EMAIL_ADDRESS
+
+ Corresponds to the dotted string ``"1.2.840.113549.1.9.1"``. This OID is
+ typically seen in X.509 names.
+
+Exceptions
+~~~~~~~~~~
+
.. class:: InvalidVersion
This is raised when an X.509 certificate has an invalid version number.
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index be1298b6..e280980b 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -9,6 +9,27 @@ from enum import Enum
import six
+from cryptography import utils
+
+
+_OID_NAMES = {
+ "2.5.4.3": "commonName",
+ "2.5.4.6": "countryName",
+ "2.5.4.7": "localityName",
+ "2.5.4.8": "stateOrProvinceName",
+ "2.5.4.10": "organizationName",
+ "2.5.4.11": "organizationalUnitName",
+ "2.5.4.5": "serialNumber",
+ "2.5.4.4": "surname",
+ "2.5.4.42": "givenName",
+ "2.5.4.12": "title",
+ "2.5.4.44": "generationQualifier",
+ "2.5.4.46": "dnQualifier",
+ "2.5.4.65": "pseudonym",
+ "0.9.2342.19200300.100.1.25": "domainComponent",
+ "1.2.840.113549.1.9.1": "emailAddress",
+}
+
class Version(Enum):
v1 = 0
@@ -29,6 +50,71 @@ class InvalidVersion(Exception):
self.parsed_version = parsed_version
+class NameAttribute(object):
+ def __init__(self, oid, value):
+ if not isinstance(oid, ObjectIdentifier):
+ raise TypeError(
+ "oid argument must be an ObjectIdentifier instance."
+ )
+
+ self._oid = oid
+ self._value = value
+
+ oid = utils.read_only_property("_oid")
+ value = utils.read_only_property("_value")
+
+ def __eq__(self, other):
+ if not isinstance(other, NameAttribute):
+ return NotImplemented
+
+ return (
+ self.oid == other.oid and
+ self.value == other.value
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+
+class ObjectIdentifier(object):
+ def __init__(self, dotted_string):
+ self._dotted_string = dotted_string
+
+ def __eq__(self, other):
+ if not isinstance(other, ObjectIdentifier):
+ return NotImplemented
+
+ return self._dotted_string == other._dotted_string
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __repr__(self):
+ return "<ObjectIdentifier(oid={0}, name={1})>".format(
+ self._dotted_string,
+ _OID_NAMES.get(self._dotted_string, "Unknown OID")
+ )
+
+ dotted_string = utils.read_only_property("_dotted_string")
+
+
+OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
+OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
+OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
+OID_STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
+OID_ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
+OID_ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
+OID_SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
+OID_SURNAME = ObjectIdentifier("2.5.4.4")
+OID_GIVEN_NAME = ObjectIdentifier("2.5.4.42")
+OID_TITLE = ObjectIdentifier("2.5.4.12")
+OID_GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
+OID_DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
+OID_PSEUDONYM = ObjectIdentifier("2.5.4.65")
+OID_DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
+OID_EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
+
+
@six.add_metaclass(abc.ABCMeta)
class Certificate(object):
@abc.abstractmethod
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 5383871a..cf583247 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -248,3 +248,45 @@ class TestECDSACertificate(object):
)
with pytest.raises(NotImplementedError):
cert.public_key()
+
+
+class TestNameAttribute(object):
+ def test_eq(self):
+ assert x509.NameAttribute(
+ x509.ObjectIdentifier('oid'), 'value'
+ ) == x509.NameAttribute(
+ x509.ObjectIdentifier('oid'), 'value'
+ )
+
+ def test_ne(self):
+ assert x509.NameAttribute(
+ x509.ObjectIdentifier('2.5.4.3'), 'value'
+ ) != x509.NameAttribute(
+ x509.ObjectIdentifier('2.5.4.5'), 'value'
+ )
+ assert x509.NameAttribute(
+ x509.ObjectIdentifier('oid'), 'value'
+ ) != x509.NameAttribute(
+ x509.ObjectIdentifier('oid'), 'value2'
+ )
+ assert x509.NameAttribute(
+ x509.ObjectIdentifier('oid'), 'value'
+ ) != object()
+
+
+class TestObjectIdentifier(object):
+ def test_eq(self):
+ oid1 = x509.ObjectIdentifier('oid')
+ oid2 = x509.ObjectIdentifier('oid')
+ assert oid1 == oid2
+
+ def test_ne(self):
+ oid1 = x509.ObjectIdentifier('oid')
+ assert oid1 != x509.ObjectIdentifier('oid1')
+ assert oid1 != object()
+
+ def test_repr(self):
+ oid = x509.ObjectIdentifier("2.5.4.3")
+ assert repr(oid) == "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>"
+ oid = x509.ObjectIdentifier("oid1")
+ assert repr(oid) == "<ObjectIdentifier(oid=oid1, name=Unknown OID)>"