blob: c053dd61ae81cb79bd5f4eeb4d5d4725fe4accfd [file] [log] [blame]
Paul Kehrer016e08a2014-11-26 09:41:18 -10001# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
Paul Kehrerb2de9482014-12-11 14:54:48 -06007import abc
Paul Kehrer016e08a2014-11-26 09:41:18 -10008from enum import Enum
9
Paul Kehrerb2de9482014-12-11 14:54:48 -060010import six
11
Paul Kehrer912d3fb2015-01-29 11:19:22 -060012from cryptography import utils
Paul Kehrer8802a5b2015-02-13 12:06:57 -060013from cryptography.hazmat.primitives import hashes
Paul Kehrer912d3fb2015-01-29 11:19:22 -060014
Paul Kehrer016e08a2014-11-26 09:41:18 -100015
Paul Kehrer806bfb22015-02-02 17:05:24 -060016_OID_NAMES = {
17 "2.5.4.3": "commonName",
18 "2.5.4.6": "countryName",
19 "2.5.4.7": "localityName",
20 "2.5.4.8": "stateOrProvinceName",
21 "2.5.4.10": "organizationName",
22 "2.5.4.11": "organizationalUnitName",
23 "2.5.4.5": "serialNumber",
24 "2.5.4.4": "surname",
25 "2.5.4.42": "givenName",
26 "2.5.4.12": "title",
27 "2.5.4.44": "generationQualifier",
28 "2.5.4.46": "dnQualifier",
29 "2.5.4.65": "pseudonym",
30 "0.9.2342.19200300.100.1.25": "domainComponent",
31 "1.2.840.113549.1.9.1": "emailAddress",
Paul Kehrer71d40c62015-02-19 08:21:04 -060032 "1.2.840.113549.1.1.4": "md5WithRSAEncryption",
33 "1.2.840.113549.1.1.5": "sha1WithRSAEncryption",
Paul Kehrer56da2a52015-02-11 23:35:07 -060034 "1.2.840.113549.1.1.14": "sha224WithRSAEncryption",
35 "1.2.840.113549.1.1.11": "sha256WithRSAEncryption",
36 "1.2.840.113549.1.1.12": "sha384WithRSAEncryption",
37 "1.2.840.113549.1.1.13": "sha512WithRSAEncryption",
Paul Kehrer71d40c62015-02-19 08:21:04 -060038 "1.2.840.10045.4.3.1": "ecdsa-with-SHA224",
39 "1.2.840.10045.4.3.2": "ecdsa-with-SHA256",
40 "1.2.840.10045.4.3.3": "ecdsa-with-SHA384",
41 "1.2.840.10045.4.3.4": "ecdsa-with-SHA512",
42 "1.2.840.10040.4.3": "dsa-with-sha1",
43 "2.16.840.1.101.3.4.3.1": "dsa-with-sha224",
44 "2.16.840.1.101.3.4.3.2": "dsa-with-sha256",
Paul Kehrer806bfb22015-02-02 17:05:24 -060045}
46
47
Paul Kehrere76cd272014-12-14 19:00:51 -060048class Version(Enum):
Paul Kehrer016e08a2014-11-26 09:41:18 -100049 v1 = 0
50 v3 = 2
51
52
Paul Kehrer016e08a2014-11-26 09:41:18 -100053def load_pem_x509_certificate(data, backend):
54 return backend.load_pem_x509_certificate(data)
55
56
Paul Kehrer016e08a2014-11-26 09:41:18 -100057def load_der_x509_certificate(data, backend):
58 return backend.load_der_x509_certificate(data)
Paul Kehrera68fd332014-11-27 07:08:40 -100059
60
Paul Kehrere76cd272014-12-14 19:00:51 -060061class InvalidVersion(Exception):
Paul Kehrerd5cccf72014-12-15 17:20:33 -060062 def __init__(self, msg, parsed_version):
63 super(InvalidVersion, self).__init__(msg)
64 self.parsed_version = parsed_version
Paul Kehrerb2de9482014-12-11 14:54:48 -060065
66
Paul Kehrer806bfb22015-02-02 17:05:24 -060067class NameAttribute(object):
Paul Kehrer912d3fb2015-01-29 11:19:22 -060068 def __init__(self, oid, value):
69 if not isinstance(oid, ObjectIdentifier):
Paul Kehrer858b9b72015-02-05 09:50:31 -060070 raise TypeError(
71 "oid argument must be an ObjectIdentifier instance."
72 )
Paul Kehrer912d3fb2015-01-29 11:19:22 -060073
74 self._oid = oid
75 self._value = value
76
77 oid = utils.read_only_property("_oid")
78 value = utils.read_only_property("_value")
79
80 def __eq__(self, other):
Paul Kehrer806bfb22015-02-02 17:05:24 -060081 if not isinstance(other, NameAttribute):
Paul Kehrer912d3fb2015-01-29 11:19:22 -060082 return NotImplemented
83
84 return (
85 self.oid == other.oid and
86 self.value == other.value
87 )
88
89 def __ne__(self, other):
90 return not self == other
91
Paul Kehrera498be82015-02-12 15:00:56 -060092 def __repr__(self):
93 return "<NameAttribute(oid={oid}, value={value!r})>".format(
94 oid=self.oid,
95 value=self.value
96 )
97
Paul Kehrer912d3fb2015-01-29 11:19:22 -060098
99class ObjectIdentifier(object):
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600100 def __init__(self, dotted_string):
101 self._dotted_string = dotted_string
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600102
103 def __eq__(self, other):
104 if not isinstance(other, ObjectIdentifier):
105 return NotImplemented
106
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600107 return self._dotted_string == other._dotted_string
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600108
109 def __ne__(self, other):
110 return not self == other
111
112 def __repr__(self):
113 return "<ObjectIdentifier(oid={0}, name={1})>".format(
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600114 self._dotted_string,
115 _OID_NAMES.get(self._dotted_string, "Unknown OID")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600116 )
117
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600118 dotted_string = utils.read_only_property("_dotted_string")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600119
120
Paul Kehrer719d5362015-01-01 20:03:52 -0600121class Name(object):
122 def __init__(self, attributes):
123 self._attributes = attributes
124
Paul Kehrere901d642015-02-11 18:50:58 -0600125 def get_attributes_for_oid(self, oid):
Alex Gaynorf9574232015-02-19 13:56:50 -0800126 return [i for i in self if i.oid == oid]
Paul Kehrer719d5362015-01-01 20:03:52 -0600127
Paul Kehrer719d5362015-01-01 20:03:52 -0600128 def __eq__(self, other):
129 if not isinstance(other, Name):
130 return NotImplemented
131
Paul Kehrer53d8d492015-02-13 18:47:30 -0600132 return self._attributes == other._attributes
Paul Kehrer719d5362015-01-01 20:03:52 -0600133
134 def __ne__(self, other):
135 return not self == other
136
Paul Kehrer53d8d492015-02-13 18:47:30 -0600137 def __iter__(self):
Paul Kehrer8b21a4a2015-02-14 07:56:36 -0600138 return iter(self._attributes)
Paul Kehrer53d8d492015-02-13 18:47:30 -0600139
140 def __len__(self):
141 return len(self._attributes)
142
Paul Kehrer719d5362015-01-01 20:03:52 -0600143
Paul Kehrer8cf26422015-03-21 09:50:24 -0500144OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
145
146
147@six.add_metaclass(abc.ABCMeta)
148class Extension(object):
149 @abc.abstractproperty
150 def critical(self):
151 """
152 Returns the boolean value of the critical extension field.
153 """
154
155
156@utils.register_interface(Extension)
157class BasicConstraints(object):
158 oid = OID_BASIC_CONSTRAINTS
159
160 def __init__(self, ca, path_length, critical):
161 if not isinstance(ca, bool):
162 raise TypeError("ca must be a boolean value")
163
164 if not isinstance(critical, bool):
165 raise TypeError("critical must be a boolean value")
166
167 if path_length is not None and ca is False:
168 raise ValueError("path_length must be None when ca is False")
169
170 if path_length is not None and (not isinstance(path_length, int)
171 or path_length < 0):
172 raise TypeError(
173 "path_length must be a non-negative integer or None"
174 )
175
176 self._ca = ca
177 self._path_length = path_length
178 self._critical = critical
179
180 ca = utils.read_only_property("_ca")
181 path_length = utils.read_only_property("_path_length")
182 critical = utils.read_only_property("_critical")
183
184 def __repr__(self):
185 return "<BasicConstraints(ca={}, path_length={}, critical={})>".format(
186 self.ca, self.path_length, self.critical
187 )
188
189
Paul Kehrer806bfb22015-02-02 17:05:24 -0600190OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
191OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
192OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
193OID_STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
194OID_ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
195OID_ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
196OID_SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
197OID_SURNAME = ObjectIdentifier("2.5.4.4")
198OID_GIVEN_NAME = ObjectIdentifier("2.5.4.42")
199OID_TITLE = ObjectIdentifier("2.5.4.12")
200OID_GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
201OID_DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
202OID_PSEUDONYM = ObjectIdentifier("2.5.4.65")
203OID_DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
204OID_EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600205
Paul Kehrer1a7ba872015-02-19 18:09:05 -0600206OID_RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4")
207OID_RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5")
208OID_RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14")
209OID_RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11")
210OID_RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12")
211OID_RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13")
Paul Kehrer56da2a52015-02-11 23:35:07 -0600212OID_ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1")
213OID_ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2")
214OID_ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3")
215OID_ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4")
216OID_DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3")
217OID_DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1")
218OID_DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2")
219
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600220_SIG_OIDS_TO_HASH = {
Paul Kehrer1a7ba872015-02-19 18:09:05 -0600221 OID_RSA_WITH_MD5.dotted_string: hashes.MD5(),
222 OID_RSA_WITH_SHA1.dotted_string: hashes.SHA1(),
223 OID_RSA_WITH_SHA224.dotted_string: hashes.SHA224(),
224 OID_RSA_WITH_SHA256.dotted_string: hashes.SHA256(),
225 OID_RSA_WITH_SHA384.dotted_string: hashes.SHA384(),
226 OID_RSA_WITH_SHA512.dotted_string: hashes.SHA512(),
Paul Kehrer42a87cb2015-02-13 18:53:24 -0600227 OID_ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(),
228 OID_ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(),
229 OID_ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(),
230 OID_ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(),
231 OID_DSA_WITH_SHA1.dotted_string: hashes.SHA1(),
232 OID_DSA_WITH_SHA224.dotted_string: hashes.SHA224(),
233 OID_DSA_WITH_SHA256.dotted_string: hashes.SHA256()
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600234}
235
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600236
Paul Kehrerb2de9482014-12-11 14:54:48 -0600237@six.add_metaclass(abc.ABCMeta)
Paul Kehrere76cd272014-12-14 19:00:51 -0600238class Certificate(object):
Paul Kehrerb2de9482014-12-11 14:54:48 -0600239 @abc.abstractmethod
240 def fingerprint(self, algorithm):
241 """
242 Returns bytes using digest passed.
243 """
244
245 @abc.abstractproperty
246 def serial(self):
247 """
248 Returns certificate serial number
249 """
250
251 @abc.abstractproperty
252 def version(self):
253 """
254 Returns the certificate version
255 """
256
257 @abc.abstractmethod
258 def public_key(self):
259 """
260 Returns the public key
261 """
262
263 @abc.abstractproperty
264 def not_valid_before(self):
265 """
266 Not before time (represented as UTC datetime)
267 """
268
269 @abc.abstractproperty
270 def not_valid_after(self):
271 """
272 Not after time (represented as UTC datetime)
273 """
Paul Kehrer719d5362015-01-01 20:03:52 -0600274
275 @abc.abstractproperty
276 def issuer(self):
277 """
278 Returns the issuer name object.
279 """
280
281 @abc.abstractproperty
282 def subject(self):
283 """
284 Returns the subject name object.
285 """
Paul Kehrer56da2a52015-02-11 23:35:07 -0600286
287 @abc.abstractproperty
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600288 def signature_hash_algorithm(self):
Paul Kehrer56da2a52015-02-11 23:35:07 -0600289 """
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600290 Returns a HashAlgorithm corresponding to the type of the digest signed
291 in the certificate.
Paul Kehrer56da2a52015-02-11 23:35:07 -0600292 """