blob: 0c773daca3830824ce9f9005ae11db67a86ce231 [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 Kehrer85894662015-03-22 13:19:31 -050045 "2.5.29.19": "basicConstraints",
Paul Kehrer806bfb22015-02-02 17:05:24 -060046}
47
48
Paul Kehrere76cd272014-12-14 19:00:51 -060049class Version(Enum):
Paul Kehrer016e08a2014-11-26 09:41:18 -100050 v1 = 0
51 v3 = 2
52
53
Paul Kehrer016e08a2014-11-26 09:41:18 -100054def load_pem_x509_certificate(data, backend):
55 return backend.load_pem_x509_certificate(data)
56
57
Paul Kehrer016e08a2014-11-26 09:41:18 -100058def load_der_x509_certificate(data, backend):
59 return backend.load_der_x509_certificate(data)
Paul Kehrera68fd332014-11-27 07:08:40 -100060
61
Paul Kehrere76cd272014-12-14 19:00:51 -060062class InvalidVersion(Exception):
Paul Kehrerd5cccf72014-12-15 17:20:33 -060063 def __init__(self, msg, parsed_version):
64 super(InvalidVersion, self).__init__(msg)
65 self.parsed_version = parsed_version
Paul Kehrerb2de9482014-12-11 14:54:48 -060066
67
Paul Kehrer806bfb22015-02-02 17:05:24 -060068class NameAttribute(object):
Paul Kehrer912d3fb2015-01-29 11:19:22 -060069 def __init__(self, oid, value):
70 if not isinstance(oid, ObjectIdentifier):
Paul Kehrer858b9b72015-02-05 09:50:31 -060071 raise TypeError(
72 "oid argument must be an ObjectIdentifier instance."
73 )
Paul Kehrer912d3fb2015-01-29 11:19:22 -060074
75 self._oid = oid
76 self._value = value
77
78 oid = utils.read_only_property("_oid")
79 value = utils.read_only_property("_value")
80
81 def __eq__(self, other):
Paul Kehrer806bfb22015-02-02 17:05:24 -060082 if not isinstance(other, NameAttribute):
Paul Kehrer912d3fb2015-01-29 11:19:22 -060083 return NotImplemented
84
85 return (
86 self.oid == other.oid and
87 self.value == other.value
88 )
89
90 def __ne__(self, other):
91 return not self == other
92
Paul Kehrera498be82015-02-12 15:00:56 -060093 def __repr__(self):
94 return "<NameAttribute(oid={oid}, value={value!r})>".format(
95 oid=self.oid,
96 value=self.value
97 )
98
Paul Kehrer912d3fb2015-01-29 11:19:22 -060099
100class ObjectIdentifier(object):
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600101 def __init__(self, dotted_string):
102 self._dotted_string = dotted_string
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600103
104 def __eq__(self, other):
105 if not isinstance(other, ObjectIdentifier):
106 return NotImplemented
107
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600108 return self._dotted_string == other._dotted_string
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600109
110 def __ne__(self, other):
111 return not self == other
112
113 def __repr__(self):
114 return "<ObjectIdentifier(oid={0}, name={1})>".format(
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600115 self._dotted_string,
116 _OID_NAMES.get(self._dotted_string, "Unknown OID")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600117 )
118
Paul Kehrerd44f9a62015-02-04 14:47:34 -0600119 dotted_string = utils.read_only_property("_dotted_string")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600120
121
Paul Kehrer719d5362015-01-01 20:03:52 -0600122class Name(object):
123 def __init__(self, attributes):
124 self._attributes = attributes
125
Paul Kehrere901d642015-02-11 18:50:58 -0600126 def get_attributes_for_oid(self, oid):
Alex Gaynorf9574232015-02-19 13:56:50 -0800127 return [i for i in self if i.oid == oid]
Paul Kehrer719d5362015-01-01 20:03:52 -0600128
Paul Kehrer719d5362015-01-01 20:03:52 -0600129 def __eq__(self, other):
130 if not isinstance(other, Name):
131 return NotImplemented
132
Paul Kehrer53d8d492015-02-13 18:47:30 -0600133 return self._attributes == other._attributes
Paul Kehrer719d5362015-01-01 20:03:52 -0600134
135 def __ne__(self, other):
136 return not self == other
137
Paul Kehrer53d8d492015-02-13 18:47:30 -0600138 def __iter__(self):
Paul Kehrer8b21a4a2015-02-14 07:56:36 -0600139 return iter(self._attributes)
Paul Kehrer53d8d492015-02-13 18:47:30 -0600140
141 def __len__(self):
142 return len(self._attributes)
143
Paul Kehrer719d5362015-01-01 20:03:52 -0600144
Paul Kehrer8cf26422015-03-21 09:50:24 -0500145OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
146
147
Paul Kehrer8cf26422015-03-21 09:50:24 -0500148class Extension(object):
Paul Kehrer85894662015-03-22 13:19:31 -0500149 def __init__(self, oid, critical, value):
150 if not isinstance(oid, ObjectIdentifier):
151 raise TypeError(
152 "oid argument must be an ObjectIdentifier instance."
153 )
Paul Kehrer8cf26422015-03-21 09:50:24 -0500154
155 if not isinstance(critical, bool):
156 raise TypeError("critical must be a boolean value")
157
Paul Kehrer85894662015-03-22 13:19:31 -0500158 self._oid = oid
159 self._critical = critical
160 self._value = value
161
162 oid = utils.read_only_property("_oid")
163 critical = utils.read_only_property("_critical")
164 value = utils.read_only_property("_value")
165
166 def __repr__(self):
Paul Kehrer58b75692015-03-22 23:24:58 -0500167 return ("<Extension(oid={0.oid}, critical={0.critical}, "
168 "value={0.value})>").format(self)
Paul Kehrer85894662015-03-22 13:19:31 -0500169
170
171class BasicConstraints(object):
172 def __init__(self, ca, path_length):
173 if not isinstance(ca, bool):
174 raise TypeError("ca must be a boolean value")
175
Paul Kehrer611d3d32015-03-22 13:31:18 -0500176 if path_length is not None and not ca:
Paul Kehrer8cf26422015-03-21 09:50:24 -0500177 raise ValueError("path_length must be None when ca is False")
178
179 if path_length is not None and (not isinstance(path_length, int)
180 or path_length < 0):
181 raise TypeError(
182 "path_length must be a non-negative integer or None"
183 )
184
185 self._ca = ca
186 self._path_length = path_length
Paul Kehrer8cf26422015-03-21 09:50:24 -0500187
188 ca = utils.read_only_property("_ca")
189 path_length = utils.read_only_property("_path_length")
Paul Kehrer8cf26422015-03-21 09:50:24 -0500190
191 def __repr__(self):
Paul Kehrer58b75692015-03-22 23:24:58 -0500192 return ("<BasicConstraints(ca={0.ca}, "
193 "path_length={0.path_length})>").format(self)
Paul Kehrer8cf26422015-03-21 09:50:24 -0500194
195
Paul Kehrer806bfb22015-02-02 17:05:24 -0600196OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
197OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
198OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
199OID_STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
200OID_ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
201OID_ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
202OID_SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
203OID_SURNAME = ObjectIdentifier("2.5.4.4")
204OID_GIVEN_NAME = ObjectIdentifier("2.5.4.42")
205OID_TITLE = ObjectIdentifier("2.5.4.12")
206OID_GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
207OID_DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
208OID_PSEUDONYM = ObjectIdentifier("2.5.4.65")
209OID_DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
210OID_EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600211
Paul Kehrer1a7ba872015-02-19 18:09:05 -0600212OID_RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4")
213OID_RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5")
214OID_RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14")
215OID_RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11")
216OID_RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12")
217OID_RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13")
Paul Kehrer56da2a52015-02-11 23:35:07 -0600218OID_ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1")
219OID_ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2")
220OID_ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3")
221OID_ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4")
222OID_DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3")
223OID_DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1")
224OID_DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2")
225
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600226_SIG_OIDS_TO_HASH = {
Paul Kehrer1a7ba872015-02-19 18:09:05 -0600227 OID_RSA_WITH_MD5.dotted_string: hashes.MD5(),
228 OID_RSA_WITH_SHA1.dotted_string: hashes.SHA1(),
229 OID_RSA_WITH_SHA224.dotted_string: hashes.SHA224(),
230 OID_RSA_WITH_SHA256.dotted_string: hashes.SHA256(),
231 OID_RSA_WITH_SHA384.dotted_string: hashes.SHA384(),
232 OID_RSA_WITH_SHA512.dotted_string: hashes.SHA512(),
Paul Kehrer42a87cb2015-02-13 18:53:24 -0600233 OID_ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(),
234 OID_ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(),
235 OID_ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(),
236 OID_ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(),
237 OID_DSA_WITH_SHA1.dotted_string: hashes.SHA1(),
238 OID_DSA_WITH_SHA224.dotted_string: hashes.SHA224(),
239 OID_DSA_WITH_SHA256.dotted_string: hashes.SHA256()
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600240}
241
Paul Kehrer912d3fb2015-01-29 11:19:22 -0600242
Paul Kehrerb2de9482014-12-11 14:54:48 -0600243@six.add_metaclass(abc.ABCMeta)
Paul Kehrere76cd272014-12-14 19:00:51 -0600244class Certificate(object):
Paul Kehrerb2de9482014-12-11 14:54:48 -0600245 @abc.abstractmethod
246 def fingerprint(self, algorithm):
247 """
248 Returns bytes using digest passed.
249 """
250
251 @abc.abstractproperty
252 def serial(self):
253 """
254 Returns certificate serial number
255 """
256
257 @abc.abstractproperty
258 def version(self):
259 """
260 Returns the certificate version
261 """
262
263 @abc.abstractmethod
264 def public_key(self):
265 """
266 Returns the public key
267 """
268
269 @abc.abstractproperty
270 def not_valid_before(self):
271 """
272 Not before time (represented as UTC datetime)
273 """
274
275 @abc.abstractproperty
276 def not_valid_after(self):
277 """
278 Not after time (represented as UTC datetime)
279 """
Paul Kehrer719d5362015-01-01 20:03:52 -0600280
281 @abc.abstractproperty
282 def issuer(self):
283 """
284 Returns the issuer name object.
285 """
286
287 @abc.abstractproperty
288 def subject(self):
289 """
290 Returns the subject name object.
291 """
Paul Kehrer56da2a52015-02-11 23:35:07 -0600292
293 @abc.abstractproperty
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600294 def signature_hash_algorithm(self):
Paul Kehrer56da2a52015-02-11 23:35:07 -0600295 """
Paul Kehrer8802a5b2015-02-13 12:06:57 -0600296 Returns a HashAlgorithm corresponding to the type of the digest signed
297 in the certificate.
Paul Kehrer56da2a52015-02-11 23:35:07 -0600298 """