Skip to content

Commit

Permalink
Merge pull request #1645 from reaperhulk/x509-attrs
Browse files Browse the repository at this point in the history
add attribute and objectidentifier classes for x509 name
  • Loading branch information
alex committed Feb 10, 2015
2 parents 7d93ad6 + 4bb4649 commit cd18ac0
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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``.
120 changes: 120 additions & 0 deletions docs/x509.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
86 changes: 86 additions & 0 deletions src/cryptography/x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@

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
Expand All @@ -29,6 +50,71 @@ def __init__(self, msg, parsed_version):
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
Expand Down
42 changes: 42 additions & 0 deletions tests/test_x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,45 @@ def test_load_ecdsa_no_named_curve(self, backend):
)
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)>"

0 comments on commit cd18ac0

Please sign in to comment.