aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cryptography/x509/__init__.py22
-rw-r--r--src/cryptography/x509/base.py251
-rw-r--r--src/cryptography/x509/general_name.py265
3 files changed, 278 insertions, 260 deletions
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
index 353cd5b1..82e83616 100644
--- a/src/cryptography/x509/__init__.py
+++ b/src/cryptography/x509/__init__.py
@@ -8,19 +8,21 @@ from cryptography.x509.base import (
AccessDescription, AuthorityInformationAccess, AuthorityKeyIdentifier,
BasicConstraints, CRLDistributionPoints, Certificate, CertificateBuilder,
CertificatePolicies, CertificateRevocationList, CertificateSigningRequest,
- CertificateSigningRequestBuilder, DNSName, DirectoryName,
- DistributionPoint, DuplicateExtension, ExtendedKeyUsage,
- Extension, ExtensionNotFound, ExtensionType, Extensions, GeneralName,
- GeneralNames, IPAddress, InhibitAnyPolicy, InvalidVersion,
- IssuerAlternativeName, KeyUsage, NameConstraints,
- NoticeReference, OCSPNoCheck, ObjectIdentifier, OtherName,
- PolicyInformation, RFC822Name, ReasonFlags, RegisteredID,
+ CertificateSigningRequestBuilder, DistributionPoint,
+ DuplicateExtension, ExtendedKeyUsage, Extension, ExtensionNotFound,
+ ExtensionType, Extensions, GeneralNames, InhibitAnyPolicy,
+ InvalidVersion, IssuerAlternativeName, KeyUsage, NameConstraints,
+ NoticeReference, OCSPNoCheck, ObjectIdentifier,
+ PolicyInformation, ReasonFlags,
RevokedCertificate, SubjectAlternativeName, SubjectKeyIdentifier,
- UniformResourceIdentifier, UnsupportedExtension,
- UnsupportedGeneralNameType, UserNotice, Version, _GENERAL_NAMES,
- load_der_x509_certificate,
+ UnsupportedExtension, UserNotice, Version, load_der_x509_certificate,
load_der_x509_csr, load_pem_x509_certificate, load_pem_x509_csr,
)
+from cryptography.x509.general_name import (
+ DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name,
+ RegisteredID, UniformResourceIdentifier, UnsupportedGeneralNameType,
+ _GENERAL_NAMES
+)
from cryptography.x509.name import Name, NameAttribute
from cryptography.x509.oid import (
ExtensionOID, NameOID, OID_ANY_POLICY,
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
index 78a3edbb..8eabee88 100644
--- a/src/cryptography/x509/base.py
+++ b/src/cryptography/x509/base.py
@@ -8,21 +8,17 @@ import abc
import datetime
import hashlib
import ipaddress
-from email.utils import parseaddr
from enum import Enum
-import idna
-
from pyasn1.codec.der import decoder
from pyasn1.type import namedtype, univ
import six
-from six.moves import urllib_parse
-
from cryptography import utils
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
+from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
from cryptography.x509.name import Name
from cryptography.x509.oid import (
ExtensionOID, OID_CA_ISSUERS, OID_OCSP, ObjectIdentifier
@@ -57,18 +53,6 @@ def _key_identifier_from_public_key(public_key):
return hashlib.sha1(data).digest()
-_GENERAL_NAMES = {
- 0: "otherName",
- 1: "rfc822Name",
- 2: "dNSName",
- 3: "x400Address",
- 4: "directoryName",
- 5: "ediPartyName",
- 6: "uniformResourceIdentifier",
- 7: "iPAddress",
- 8: "registeredID",
-}
-
_UNIX_EPOCH = datetime.datetime(1970, 1, 1)
@@ -117,12 +101,6 @@ class ExtensionNotFound(Exception):
self.oid = oid
-class UnsupportedGeneralNameType(Exception):
- def __init__(self, msg, type):
- super(UnsupportedGeneralNameType, self).__init__(msg)
- self.type = type
-
-
class Extensions(object):
def __init__(self, extensions):
self._extensions = extensions
@@ -801,233 +779,6 @@ class InhibitAnyPolicy(object):
skip_certs = utils.read_only_property("_skip_certs")
-@six.add_metaclass(abc.ABCMeta)
-class GeneralName(object):
- @abc.abstractproperty
- def value(self):
- """
- Return the value of the object
- """
-
-
-@utils.register_interface(GeneralName)
-class RFC822Name(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- name, address = parseaddr(value)
- parts = address.split(u"@")
- if name or not address:
- # parseaddr has found a name (e.g. Name <email>) or the entire
- # value is an empty string.
- raise ValueError("Invalid rfc822name value")
- elif len(parts) == 1:
- # Single label email name. This is valid for local delivery.
- # No IDNA encoding needed since there is no domain component.
- encoded = address.encode("ascii")
- else:
- # A normal email of the form user@domain.com. Let's attempt to
- # encode the domain component and reconstruct the address.
- encoded = parts[0].encode("ascii") + b"@" + idna.encode(parts[1])
-
- self._value = value
- self._encoded = encoded
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<RFC822Name(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, RFC822Name):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class DNSName(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<DNSName(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, DNSName):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class UniformResourceIdentifier(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- parsed = urllib_parse.urlparse(value)
- if not parsed.hostname:
- netloc = ""
- elif parsed.port:
- netloc = (
- idna.encode(parsed.hostname) +
- ":{0}".format(parsed.port).encode("ascii")
- ).decode("ascii")
- else:
- netloc = idna.encode(parsed.hostname).decode("ascii")
-
- # Note that building a URL in this fashion means it should be
- # semantically indistinguishable from the original but is not
- # guaranteed to be exactly the same.
- uri = urllib_parse.urlunparse((
- parsed.scheme,
- netloc,
- parsed.path,
- parsed.params,
- parsed.query,
- parsed.fragment
- )).encode("ascii")
-
- self._value = value
- self._encoded = uri
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<UniformResourceIdentifier(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, UniformResourceIdentifier):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class DirectoryName(object):
- def __init__(self, value):
- if not isinstance(value, Name):
- raise TypeError("value must be a Name")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<DirectoryName(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, DirectoryName):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class RegisteredID(object):
- def __init__(self, value):
- if not isinstance(value, ObjectIdentifier):
- raise TypeError("value must be an ObjectIdentifier")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<RegisteredID(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, RegisteredID):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class IPAddress(object):
- def __init__(self, value):
- if not isinstance(
- value,
- (
- ipaddress.IPv4Address,
- ipaddress.IPv6Address,
- ipaddress.IPv4Network,
- ipaddress.IPv6Network
- )
- ):
- raise TypeError(
- "value must be an instance of ipaddress.IPv4Address, "
- "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
- "ipaddress.IPv6Network"
- )
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<IPAddress(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, IPAddress):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class OtherName(object):
- def __init__(self, type_id, value):
- if not isinstance(type_id, ObjectIdentifier):
- raise TypeError("type_id must be an ObjectIdentifier")
- if not isinstance(value, bytes):
- raise TypeError("value must be a binary string")
-
- self._type_id = type_id
- self._value = value
-
- type_id = utils.read_only_property("_type_id")
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<OtherName(type_id={0}, value={1!r})>".format(
- self.type_id, self.value)
-
- def __eq__(self, other):
- if not isinstance(other, OtherName):
- return NotImplemented
-
- return self.type_id == other.type_id and self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
class GeneralNames(object):
def __init__(self, general_names):
if not all(isinstance(x, GeneralName) for x in general_names):
diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py
new file mode 100644
index 00000000..f5bd30fb
--- /dev/null
+++ b/src/cryptography/x509/general_name.py
@@ -0,0 +1,265 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+import ipaddress
+from email.utils import parseaddr
+
+import idna
+
+import six
+
+from six.moves import urllib_parse
+
+from cryptography import utils
+from cryptography.x509.name import Name
+from cryptography.x509.oid import ObjectIdentifier
+
+
+_GENERAL_NAMES = {
+ 0: "otherName",
+ 1: "rfc822Name",
+ 2: "dNSName",
+ 3: "x400Address",
+ 4: "directoryName",
+ 5: "ediPartyName",
+ 6: "uniformResourceIdentifier",
+ 7: "iPAddress",
+ 8: "registeredID",
+}
+
+
+class UnsupportedGeneralNameType(Exception):
+ def __init__(self, msg, type):
+ super(UnsupportedGeneralNameType, self).__init__(msg)
+ self.type = type
+
+
+@six.add_metaclass(abc.ABCMeta)
+class GeneralName(object):
+ @abc.abstractproperty
+ def value(self):
+ """
+ Return the value of the object
+ """
+
+
+@utils.register_interface(GeneralName)
+class RFC822Name(object):
+ def __init__(self, value):
+ if not isinstance(value, six.text_type):
+ raise TypeError("value must be a unicode string")
+
+ name, address = parseaddr(value)
+ parts = address.split(u"@")
+ if name or not address:
+ # parseaddr has found a name (e.g. Name <email>) or the entire
+ # value is an empty string.
+ raise ValueError("Invalid rfc822name value")
+ elif len(parts) == 1:
+ # Single label email name. This is valid for local delivery.
+ # No IDNA encoding needed since there is no domain component.
+ encoded = address.encode("ascii")
+ else:
+ # A normal email of the form user@domain.com. Let's attempt to
+ # encode the domain component and reconstruct the address.
+ encoded = parts[0].encode("ascii") + b"@" + idna.encode(parts[1])
+
+ self._value = value
+ self._encoded = encoded
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<RFC822Name(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, RFC822Name):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class DNSName(object):
+ def __init__(self, value):
+ if not isinstance(value, six.text_type):
+ raise TypeError("value must be a unicode string")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<DNSName(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, DNSName):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class UniformResourceIdentifier(object):
+ def __init__(self, value):
+ if not isinstance(value, six.text_type):
+ raise TypeError("value must be a unicode string")
+
+ parsed = urllib_parse.urlparse(value)
+ if not parsed.hostname:
+ netloc = ""
+ elif parsed.port:
+ netloc = (
+ idna.encode(parsed.hostname) +
+ ":{0}".format(parsed.port).encode("ascii")
+ ).decode("ascii")
+ else:
+ netloc = idna.encode(parsed.hostname).decode("ascii")
+
+ # Note that building a URL in this fashion means it should be
+ # semantically indistinguishable from the original but is not
+ # guaranteed to be exactly the same.
+ uri = urllib_parse.urlunparse((
+ parsed.scheme,
+ netloc,
+ parsed.path,
+ parsed.params,
+ parsed.query,
+ parsed.fragment
+ )).encode("ascii")
+
+ self._value = value
+ self._encoded = uri
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<UniformResourceIdentifier(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, UniformResourceIdentifier):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class DirectoryName(object):
+ def __init__(self, value):
+ if not isinstance(value, Name):
+ raise TypeError("value must be a Name")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<DirectoryName(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, DirectoryName):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class RegisteredID(object):
+ def __init__(self, value):
+ if not isinstance(value, ObjectIdentifier):
+ raise TypeError("value must be an ObjectIdentifier")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<RegisteredID(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, RegisteredID):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class IPAddress(object):
+ def __init__(self, value):
+ if not isinstance(
+ value,
+ (
+ ipaddress.IPv4Address,
+ ipaddress.IPv6Address,
+ ipaddress.IPv4Network,
+ ipaddress.IPv6Network
+ )
+ ):
+ raise TypeError(
+ "value must be an instance of ipaddress.IPv4Address, "
+ "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
+ "ipaddress.IPv6Network"
+ )
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<IPAddress(value={0})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, IPAddress):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(GeneralName)
+class OtherName(object):
+ def __init__(self, type_id, value):
+ if not isinstance(type_id, ObjectIdentifier):
+ raise TypeError("type_id must be an ObjectIdentifier")
+ if not isinstance(value, bytes):
+ raise TypeError("value must be a binary string")
+
+ self._type_id = type_id
+ self._value = value
+
+ type_id = utils.read_only_property("_type_id")
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<OtherName(type_id={0}, value={1!r})>".format(
+ self.type_id, self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, OtherName):
+ return NotImplemented
+
+ return self.type_id == other.type_id and self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other