blob: b6494024290551456a4ebfc1e025ee3ff4fc6107 [file] [log] [blame]
Paul Kehrer732cf642018-08-15 18:04:28 -05001# 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 Kehrer002fa752018-08-30 10:41:32 -04007import base64
Paul Kehrera07de312018-10-02 07:54:31 +08008import datetime
Paul Kehrer732cf642018-08-15 18:04:28 -05009import os
10
11import pytest
12
Paul Kehrer002fa752018-08-30 10:41:32 -040013from cryptography import x509
Paul Kehrer732cf642018-08-15 18:04:28 -050014from cryptography.exceptions import UnsupportedAlgorithm
15from cryptography.hazmat.primitives import hashes, serialization
Lucia Lic6ba99d2021-11-08 22:06:11 +080016from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448
Paul Kehrera07de312018-10-02 07:54:31 +080017from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
Paul Kehrer732cf642018-08-15 18:04:28 -050018from cryptography.x509 import ocsp
19
Paul Kehrer002fa752018-08-30 10:41:32 -040020from .test_x509 import _load_cert
Paul Kehrere617c5a2018-10-29 05:36:34 +080021from ..hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1
Paul Kehrer732cf642018-08-15 18:04:28 -050022from ..utils import load_vectors_from_file
23
24
25def _load_data(filename, loader):
26 return load_vectors_from_file(
Lucia Lic6ba99d2021-11-08 22:06:11 +080027 filename=filename, loader=lambda data: loader(data.read()), mode="rb"
Paul Kehrer732cf642018-08-15 18:04:28 -050028 )
29
30
Paul Kehrer002fa752018-08-30 10:41:32 -040031def _cert_and_issuer():
32 from cryptography.hazmat.backends.openssl.backend import backend
Lucia Lic6ba99d2021-11-08 22:06:11 +080033
Paul Kehrer002fa752018-08-30 10:41:32 -040034 cert = _load_cert(
35 os.path.join("x509", "cryptography.io.pem"),
36 x509.load_pem_x509_certificate,
Lucia Lic6ba99d2021-11-08 22:06:11 +080037 backend,
Paul Kehrer002fa752018-08-30 10:41:32 -040038 )
39 issuer = _load_cert(
40 os.path.join("x509", "rapidssl_sha256_ca_g3.pem"),
41 x509.load_pem_x509_certificate,
Lucia Lic6ba99d2021-11-08 22:06:11 +080042 backend,
Paul Kehrer002fa752018-08-30 10:41:32 -040043 )
44 return cert, issuer
45
46
Lucia Lic6ba99d2021-11-08 22:06:11 +080047def _generate_root(private_key=None, algorithm=hashes.SHA256()):
Paul Kehrere617c5a2018-10-29 05:36:34 +080048 from cryptography.hazmat.backends.openssl.backend import backend
49
Lucia Lic6ba99d2021-11-08 22:06:11 +080050 if private_key is None:
51 private_key = EC_KEY_SECP256R1.private_key(backend)
Paul Kehrere617c5a2018-10-29 05:36:34 +080052
Lucia Lic6ba99d2021-11-08 22:06:11 +080053 subject = x509.Name(
54 [
55 x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u"US"),
56 x509.NameAttribute(x509.NameOID.COMMON_NAME, u"Cryptography CA"),
57 ]
Paul Kehrere617c5a2018-10-29 05:36:34 +080058 )
59
Lucia Lic6ba99d2021-11-08 22:06:11 +080060 builder = (
61 x509.CertificateBuilder()
62 .serial_number(123456789)
63 .issuer_name(subject)
64 .subject_name(subject)
65 .public_key(private_key.public_key())
66 .not_valid_before(datetime.datetime.now())
67 .not_valid_after(
68 datetime.datetime.now() + datetime.timedelta(days=3650)
69 )
70 )
71
72 cert = builder.sign(private_key, algorithm, backend)
Paul Kehrere617c5a2018-10-29 05:36:34 +080073 return cert, private_key
74
75
Paul Kehrer732cf642018-08-15 18:04:28 -050076class TestOCSPRequest(object):
77 def test_bad_request(self):
78 with pytest.raises(ValueError):
79 ocsp.load_der_ocsp_request(b"invalid")
80
Paul Kehrer0f629bb2018-08-31 10:47:56 -040081 def test_load_request(self):
Paul Kehrer732cf642018-08-15 18:04:28 -050082 req = _load_data(
83 os.path.join("x509", "ocsp", "req-sha1.der"),
84 ocsp.load_der_ocsp_request,
85 )
Lucia Lic6ba99d2021-11-08 22:06:11 +080086 assert req.issuer_name_hash == (
87 b"8\xcaF\x8c\x07D\x8d\xf4\x81\x96" b"\xc7mmLpQ\x9e`\xa7\xbd"
88 )
89 assert req.issuer_key_hash == (
90 b"yu\xbb\x84:\xcb,\xdez\t\xbe1" b"\x1bC\xbc\x1c*MSX"
91 )
Paul Kehrer0f629bb2018-08-31 10:47:56 -040092 assert isinstance(req.hash_algorithm, hashes.SHA1)
93 assert req.serial_number == int(
Paul Kehrer732cf642018-08-15 18:04:28 -050094 "98D9E5C0B4C373552DF77C5D0F1EB5128E4945F9", 16
95 )
Paul Kehrer09403102018-09-09 21:57:21 -050096 assert len(req.extensions) == 0
97
98 def test_load_request_with_extensions(self):
99 req = _load_data(
100 os.path.join("x509", "ocsp", "req-ext-nonce.der"),
101 ocsp.load_der_ocsp_request,
102 )
103 assert len(req.extensions) == 1
104 ext = req.extensions[0]
105 assert ext.critical is False
106 assert ext.value == x509.OCSPNonce(
107 b"\x04\x10{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd"
108 )
Paul Kehrer732cf642018-08-15 18:04:28 -0500109
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400110 def test_load_request_two_requests(self):
111 with pytest.raises(NotImplementedError):
112 _load_data(
113 os.path.join("x509", "ocsp", "req-multi-sha1.der"),
114 ocsp.load_der_ocsp_request,
115 )
Paul Kehrer732cf642018-08-15 18:04:28 -0500116
117 def test_invalid_hash_algorithm(self):
118 req = _load_data(
119 os.path.join("x509", "ocsp", "req-invalid-hash-alg.der"),
120 ocsp.load_der_ocsp_request,
121 )
122 with pytest.raises(UnsupportedAlgorithm):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400123 req.hash_algorithm
Paul Kehrer732cf642018-08-15 18:04:28 -0500124
125 def test_serialize_request(self):
126 req_bytes = load_vectors_from_file(
127 filename=os.path.join("x509", "ocsp", "req-sha1.der"),
128 loader=lambda data: data.read(),
Lucia Lic6ba99d2021-11-08 22:06:11 +0800129 mode="rb",
Paul Kehrer732cf642018-08-15 18:04:28 -0500130 )
131 req = ocsp.load_der_ocsp_request(req_bytes)
132 assert req.public_bytes(serialization.Encoding.DER) == req_bytes
133
134 def test_invalid_serialize_encoding(self):
135 req = _load_data(
136 os.path.join("x509", "ocsp", "req-sha1.der"),
137 ocsp.load_der_ocsp_request,
138 )
139 with pytest.raises(ValueError):
140 req.public_bytes("invalid")
141 with pytest.raises(ValueError):
142 req.public_bytes(serialization.Encoding.PEM)
Paul Kehrer002fa752018-08-30 10:41:32 -0400143
144
145class TestOCSPRequestBuilder(object):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400146 def test_add_two_certs(self):
147 cert, issuer = _cert_and_issuer()
148 builder = ocsp.OCSPRequestBuilder()
149 builder = builder.add_certificate(cert, issuer, hashes.SHA1())
150 with pytest.raises(ValueError):
151 builder.add_certificate(cert, issuer, hashes.SHA1())
152
Paul Kehrer002fa752018-08-30 10:41:32 -0400153 def test_create_ocsp_request_no_req(self):
154 builder = ocsp.OCSPRequestBuilder()
155 with pytest.raises(ValueError):
156 builder.build()
157
158 def test_create_ocsp_request_invalid_alg(self):
159 cert, issuer = _cert_and_issuer()
160 builder = ocsp.OCSPRequestBuilder()
161 with pytest.raises(ValueError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400162 builder.add_certificate(cert, issuer, hashes.MD5())
Paul Kehrer002fa752018-08-30 10:41:32 -0400163
Paul Kehrer0c075802018-10-07 10:10:09 +0800164 def test_add_extension_twice(self):
165 builder = ocsp.OCSPRequestBuilder()
166 builder = builder.add_extension(x509.OCSPNonce(b"123"), False)
167 with pytest.raises(ValueError):
168 builder.add_extension(x509.OCSPNonce(b"123"), False)
169
170 def test_add_invalid_extension(self):
171 builder = ocsp.OCSPRequestBuilder()
172 with pytest.raises(TypeError):
173 builder.add_extension("notanext", False)
174
Paul Kehrer002fa752018-08-30 10:41:32 -0400175 def test_create_ocsp_request_invalid_cert(self):
176 cert, issuer = _cert_and_issuer()
177 builder = ocsp.OCSPRequestBuilder()
178 with pytest.raises(TypeError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400179 builder.add_certificate(b"notacert", issuer, hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400180
181 with pytest.raises(TypeError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400182 builder.add_certificate(cert, b"notacert", hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400183
184 def test_create_ocsp_request(self):
185 cert, issuer = _cert_and_issuer()
186 builder = ocsp.OCSPRequestBuilder()
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400187 builder = builder.add_certificate(cert, issuer, hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400188 req = builder.build()
189 serialized = req.public_bytes(serialization.Encoding.DER)
190 assert serialized == base64.b64decode(
191 b"MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz"
192 b"/NNGCDS7zkZ/oHxb8+IIy1kCAj8g"
193 )
Paul Kehrera07de312018-10-02 07:54:31 +0800194
Paul Kehrer0c075802018-10-07 10:10:09 +0800195 @pytest.mark.parametrize(
196 ("ext", "critical"),
197 [
198 [x509.OCSPNonce(b"0000"), False],
199 [x509.OCSPNonce(b"\x00\x01\x02"), True],
Lucia Lic6ba99d2021-11-08 22:06:11 +0800200 ],
Paul Kehrer0c075802018-10-07 10:10:09 +0800201 )
202 def test_create_ocsp_request_with_extension(self, ext, critical):
203 cert, issuer = _cert_and_issuer()
204 builder = ocsp.OCSPRequestBuilder()
205 builder = builder.add_certificate(
206 cert, issuer, hashes.SHA1()
Lucia Lic6ba99d2021-11-08 22:06:11 +0800207 ).add_extension(ext, critical)
Paul Kehrer0c075802018-10-07 10:10:09 +0800208 req = builder.build()
209 assert len(req.extensions) == 1
210 assert req.extensions[0].value == ext
211 assert req.extensions[0].oid == ext.oid
212 assert req.extensions[0].critical is critical
213
Paul Kehrera07de312018-10-02 07:54:31 +0800214
Paul Kehrere617c5a2018-10-29 05:36:34 +0800215class TestOCSPResponseBuilder(object):
216 def test_add_response_twice(self):
217 cert, issuer = _cert_and_issuer()
218 time = datetime.datetime.now()
219 builder = ocsp.OCSPResponseBuilder()
220 builder = builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800221 cert,
222 issuer,
223 hashes.SHA256(),
224 ocsp.OCSPCertStatus.GOOD,
225 time,
226 time,
227 None,
228 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800229 )
230 with pytest.raises(ValueError):
231 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800232 cert,
233 issuer,
234 hashes.SHA256(),
235 ocsp.OCSPCertStatus.GOOD,
236 time,
237 time,
238 None,
239 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800240 )
241
242 def test_invalid_add_response(self):
243 cert, issuer = _cert_and_issuer()
244 time = datetime.datetime.utcnow()
245 reason = x509.ReasonFlags.cessation_of_operation
246 builder = ocsp.OCSPResponseBuilder()
247 with pytest.raises(TypeError):
248 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800249 "bad",
250 issuer,
251 hashes.SHA256(),
252 ocsp.OCSPCertStatus.GOOD,
253 time,
254 time,
255 None,
256 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800257 )
258 with pytest.raises(TypeError):
259 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800260 cert,
261 "bad",
262 hashes.SHA256(),
263 ocsp.OCSPCertStatus.GOOD,
264 time,
265 time,
266 None,
267 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800268 )
269 with pytest.raises(ValueError):
270 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800271 cert,
272 issuer,
273 "notahash",
274 ocsp.OCSPCertStatus.GOOD,
275 time,
276 time,
277 None,
278 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800279 )
280 with pytest.raises(TypeError):
281 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800282 cert,
283 issuer,
284 hashes.SHA256(),
285 ocsp.OCSPCertStatus.GOOD,
286 "bad",
287 time,
288 None,
289 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800290 )
291 with pytest.raises(TypeError):
292 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800293 cert,
294 issuer,
295 hashes.SHA256(),
296 ocsp.OCSPCertStatus.GOOD,
297 time,
298 "bad",
299 None,
300 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800301 )
302
303 with pytest.raises(TypeError):
304 builder.add_response(
305 cert, issuer, hashes.SHA256(), 0, time, time, None, None
306 )
307 with pytest.raises(ValueError):
308 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800309 cert,
310 issuer,
311 hashes.SHA256(),
312 ocsp.OCSPCertStatus.GOOD,
313 time,
314 time,
315 time,
316 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800317 )
318 with pytest.raises(ValueError):
319 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800320 cert,
321 issuer,
322 hashes.SHA256(),
323 ocsp.OCSPCertStatus.GOOD,
324 time,
325 time,
326 None,
327 reason,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800328 )
329 with pytest.raises(TypeError):
330 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800331 cert,
332 issuer,
333 hashes.SHA256(),
334 ocsp.OCSPCertStatus.REVOKED,
335 time,
336 time,
337 None,
338 reason,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800339 )
340 with pytest.raises(TypeError):
341 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800342 cert,
343 issuer,
344 hashes.SHA256(),
345 ocsp.OCSPCertStatus.REVOKED,
346 time,
347 time,
348 time,
349 0,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800350 )
351 with pytest.raises(ValueError):
352 builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800353 cert,
354 issuer,
355 hashes.SHA256(),
356 ocsp.OCSPCertStatus.REVOKED,
357 time,
358 time,
359 time - datetime.timedelta(days=36500),
360 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800361 )
362
363 def test_invalid_certificates(self):
364 builder = ocsp.OCSPResponseBuilder()
365 with pytest.raises(ValueError):
366 builder.certificates([])
367 with pytest.raises(TypeError):
Lucia Lic6ba99d2021-11-08 22:06:11 +0800368 builder.certificates(["notacert"])
Paul Kehrere617c5a2018-10-29 05:36:34 +0800369 with pytest.raises(TypeError):
Lucia Lic6ba99d2021-11-08 22:06:11 +0800370 builder.certificates("invalid")
Paul Kehrere617c5a2018-10-29 05:36:34 +0800371
372 _, issuer = _cert_and_issuer()
373 builder = builder.certificates([issuer])
374 with pytest.raises(ValueError):
375 builder.certificates([issuer])
376
377 def test_invalid_responder_id(self):
378 builder = ocsp.OCSPResponseBuilder()
379 cert, _ = _cert_and_issuer()
380 with pytest.raises(TypeError):
Lucia Lic6ba99d2021-11-08 22:06:11 +0800381 builder.responder_id(ocsp.OCSPResponderEncoding.HASH, "invalid")
Paul Kehrere617c5a2018-10-29 05:36:34 +0800382 with pytest.raises(TypeError):
Lucia Lic6ba99d2021-11-08 22:06:11 +0800383 builder.responder_id("notanenum", cert)
Paul Kehrere617c5a2018-10-29 05:36:34 +0800384
385 builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME, cert)
386 with pytest.raises(ValueError):
387 builder.responder_id(ocsp.OCSPResponderEncoding.NAME, cert)
388
389 def test_invalid_extension(self):
390 builder = ocsp.OCSPResponseBuilder()
391 with pytest.raises(TypeError):
392 builder.add_extension("notanextension", True)
393
394 def test_sign_no_response(self):
395 builder = ocsp.OCSPResponseBuilder()
396 root_cert, private_key = _generate_root()
397 builder = builder.responder_id(
398 ocsp.OCSPResponderEncoding.NAME, root_cert
399 )
400 with pytest.raises(ValueError):
401 builder.sign(private_key, hashes.SHA256())
402
403 def test_sign_no_responder_id(self):
404 builder = ocsp.OCSPResponseBuilder()
405 cert, issuer = _cert_and_issuer()
406 _, private_key = _generate_root()
407 current_time = datetime.datetime.utcnow().replace(microsecond=0)
408 this_update = current_time - datetime.timedelta(days=1)
409 next_update = this_update + datetime.timedelta(days=7)
410 builder = builder.add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800411 cert,
412 issuer,
413 hashes.SHA1(),
414 ocsp.OCSPCertStatus.GOOD,
415 this_update,
416 next_update,
417 None,
418 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800419 )
420 with pytest.raises(ValueError):
421 builder.sign(private_key, hashes.SHA256())
422
423 def test_sign_invalid_hash_algorithm(self):
424 builder = ocsp.OCSPResponseBuilder()
425 cert, issuer = _cert_and_issuer()
426 root_cert, private_key = _generate_root()
427 current_time = datetime.datetime.utcnow().replace(microsecond=0)
428 this_update = current_time - datetime.timedelta(days=1)
429 next_update = this_update + datetime.timedelta(days=7)
430 builder = builder.responder_id(
431 ocsp.OCSPResponderEncoding.NAME, root_cert
432 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800433 cert,
434 issuer,
435 hashes.SHA1(),
436 ocsp.OCSPCertStatus.GOOD,
437 this_update,
438 next_update,
439 None,
440 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800441 )
442 with pytest.raises(TypeError):
Lucia Lic6ba99d2021-11-08 22:06:11 +0800443 builder.sign(private_key, "notahash")
Paul Kehrere617c5a2018-10-29 05:36:34 +0800444
445 def test_sign_good_cert(self):
446 builder = ocsp.OCSPResponseBuilder()
447 cert, issuer = _cert_and_issuer()
448 root_cert, private_key = _generate_root()
449 current_time = datetime.datetime.utcnow().replace(microsecond=0)
450 this_update = current_time - datetime.timedelta(days=1)
451 next_update = this_update + datetime.timedelta(days=7)
452 builder = builder.responder_id(
453 ocsp.OCSPResponderEncoding.NAME, root_cert
454 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800455 cert,
456 issuer,
457 hashes.SHA1(),
458 ocsp.OCSPCertStatus.GOOD,
459 this_update,
460 next_update,
461 None,
462 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800463 )
464 resp = builder.sign(private_key, hashes.SHA256())
465 assert resp.responder_name == root_cert.subject
466 assert resp.responder_key_hash is None
467 assert (current_time - resp.produced_at).total_seconds() < 10
Lucia Lic6ba99d2021-11-08 22:06:11 +0800468 assert (
469 resp.signature_algorithm_oid
470 == x509.SignatureAlgorithmOID.ECDSA_WITH_SHA256
471 )
Paul Kehrere617c5a2018-10-29 05:36:34 +0800472 assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD
473 assert resp.revocation_time is None
474 assert resp.revocation_reason is None
475 assert resp.this_update == this_update
476 assert resp.next_update == next_update
477 private_key.public_key().verify(
478 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
479 )
480
481 def test_sign_revoked_cert(self):
482 builder = ocsp.OCSPResponseBuilder()
483 cert, issuer = _cert_and_issuer()
484 root_cert, private_key = _generate_root()
485 current_time = datetime.datetime.utcnow().replace(microsecond=0)
486 this_update = current_time - datetime.timedelta(days=1)
487 next_update = this_update + datetime.timedelta(days=7)
488 revoked_date = this_update - datetime.timedelta(days=300)
489 builder = builder.responder_id(
490 ocsp.OCSPResponderEncoding.NAME, root_cert
491 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800492 cert,
493 issuer,
494 hashes.SHA1(),
495 ocsp.OCSPCertStatus.REVOKED,
496 this_update,
497 next_update,
498 revoked_date,
499 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800500 )
501 resp = builder.sign(private_key, hashes.SHA256())
502 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
503 assert resp.revocation_time == revoked_date
504 assert resp.revocation_reason is None
505 assert resp.this_update == this_update
506 assert resp.next_update == next_update
507 private_key.public_key().verify(
508 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
509 )
510
511 def test_sign_with_appended_certs(self):
512 builder = ocsp.OCSPResponseBuilder()
513 cert, issuer = _cert_and_issuer()
514 root_cert, private_key = _generate_root()
515 current_time = datetime.datetime.utcnow().replace(microsecond=0)
516 this_update = current_time - datetime.timedelta(days=1)
517 next_update = this_update + datetime.timedelta(days=7)
Lucia Lic6ba99d2021-11-08 22:06:11 +0800518 builder = (
519 builder.responder_id(ocsp.OCSPResponderEncoding.NAME, root_cert)
520 .add_response(
521 cert,
522 issuer,
523 hashes.SHA1(),
524 ocsp.OCSPCertStatus.GOOD,
525 this_update,
526 next_update,
527 None,
528 None,
529 )
530 .certificates([root_cert])
Paul Kehrere617c5a2018-10-29 05:36:34 +0800531 )
532 resp = builder.sign(private_key, hashes.SHA256())
533 assert resp.certificates == [root_cert]
534
535 def test_sign_revoked_no_next_update(self):
536 builder = ocsp.OCSPResponseBuilder()
537 cert, issuer = _cert_and_issuer()
538 root_cert, private_key = _generate_root()
539 current_time = datetime.datetime.utcnow().replace(microsecond=0)
540 this_update = current_time - datetime.timedelta(days=1)
541 revoked_date = this_update - datetime.timedelta(days=300)
542 builder = builder.responder_id(
543 ocsp.OCSPResponderEncoding.NAME, root_cert
544 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800545 cert,
546 issuer,
547 hashes.SHA1(),
548 ocsp.OCSPCertStatus.REVOKED,
549 this_update,
550 None,
551 revoked_date,
552 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800553 )
554 resp = builder.sign(private_key, hashes.SHA256())
555 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
556 assert resp.revocation_time == revoked_date
557 assert resp.revocation_reason is None
558 assert resp.this_update == this_update
559 assert resp.next_update is None
560 private_key.public_key().verify(
561 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
562 )
563
564 def test_sign_revoked_with_reason(self):
565 builder = ocsp.OCSPResponseBuilder()
566 cert, issuer = _cert_and_issuer()
567 root_cert, private_key = _generate_root()
568 current_time = datetime.datetime.utcnow().replace(microsecond=0)
569 this_update = current_time - datetime.timedelta(days=1)
570 next_update = this_update + datetime.timedelta(days=7)
571 revoked_date = this_update - datetime.timedelta(days=300)
572 builder = builder.responder_id(
573 ocsp.OCSPResponderEncoding.NAME, root_cert
574 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800575 cert,
576 issuer,
577 hashes.SHA1(),
578 ocsp.OCSPCertStatus.REVOKED,
579 this_update,
580 next_update,
581 revoked_date,
582 x509.ReasonFlags.key_compromise,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800583 )
584 resp = builder.sign(private_key, hashes.SHA256())
585 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
586 assert resp.revocation_time == revoked_date
587 assert resp.revocation_reason is x509.ReasonFlags.key_compromise
588 assert resp.this_update == this_update
589 assert resp.next_update == next_update
590 private_key.public_key().verify(
591 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
592 )
593
594 def test_sign_responder_id_key_hash(self):
595 builder = ocsp.OCSPResponseBuilder()
596 cert, issuer = _cert_and_issuer()
597 root_cert, private_key = _generate_root()
598 current_time = datetime.datetime.utcnow().replace(microsecond=0)
599 this_update = current_time - datetime.timedelta(days=1)
600 next_update = this_update + datetime.timedelta(days=7)
601 builder = builder.responder_id(
602 ocsp.OCSPResponderEncoding.HASH, root_cert
603 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800604 cert,
605 issuer,
606 hashes.SHA1(),
607 ocsp.OCSPCertStatus.GOOD,
608 this_update,
609 next_update,
610 None,
611 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800612 )
613 resp = builder.sign(private_key, hashes.SHA256())
614 assert resp.responder_name is None
615 assert resp.responder_key_hash == (
Lucia Lic6ba99d2021-11-08 22:06:11 +0800616 b"\x8ca\x94\xe0\x948\xed\x89\xd8\xd4N\x89p\t\xd6\xf9^_\xec}"
Paul Kehrere617c5a2018-10-29 05:36:34 +0800617 )
618 private_key.public_key().verify(
619 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
620 )
621
622 def test_invalid_sign_responder_cert_does_not_match_private_key(self):
623 builder = ocsp.OCSPResponseBuilder()
624 cert, issuer = _cert_and_issuer()
625 root_cert, private_key = _generate_root()
626 current_time = datetime.datetime.utcnow().replace(microsecond=0)
627 this_update = current_time - datetime.timedelta(days=1)
628 next_update = this_update + datetime.timedelta(days=7)
629 builder = builder.responder_id(
630 ocsp.OCSPResponderEncoding.HASH, root_cert
631 ).add_response(
Lucia Lic6ba99d2021-11-08 22:06:11 +0800632 cert,
633 issuer,
634 hashes.SHA1(),
635 ocsp.OCSPCertStatus.GOOD,
636 this_update,
637 next_update,
638 None,
639 None,
Paul Kehrere617c5a2018-10-29 05:36:34 +0800640 )
641 from cryptography.hazmat.backends.openssl.backend import backend
Lucia Lic6ba99d2021-11-08 22:06:11 +0800642
Paul Kehrere617c5a2018-10-29 05:36:34 +0800643 diff_key = ec.generate_private_key(ec.SECP256R1(), backend)
644 with pytest.raises(ValueError):
645 builder.sign(diff_key, hashes.SHA256())
646
647 def test_sign_with_extension(self):
648 builder = ocsp.OCSPResponseBuilder()
649 cert, issuer = _cert_and_issuer()
650 root_cert, private_key = _generate_root()
651 current_time = datetime.datetime.utcnow().replace(microsecond=0)
652 this_update = current_time - datetime.timedelta(days=1)
653 next_update = this_update + datetime.timedelta(days=7)
Lucia Lic6ba99d2021-11-08 22:06:11 +0800654 builder = (
655 builder.responder_id(ocsp.OCSPResponderEncoding.HASH, root_cert)
656 .add_response(
657 cert,
658 issuer,
659 hashes.SHA1(),
660 ocsp.OCSPCertStatus.GOOD,
661 this_update,
662 next_update,
663 None,
664 None,
665 )
666 .add_extension(x509.OCSPNonce(b"012345"), False)
Paul Kehrere617c5a2018-10-29 05:36:34 +0800667 )
668 resp = builder.sign(private_key, hashes.SHA256())
669 assert len(resp.extensions) == 1
670 assert resp.extensions[0].value == x509.OCSPNonce(b"012345")
671 assert resp.extensions[0].critical is False
672 private_key.public_key().verify(
673 resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256())
674 )
675
676 @pytest.mark.parametrize(
677 ("status", "der"),
678 [
679 (ocsp.OCSPResponseStatus.MALFORMED_REQUEST, b"0\x03\n\x01\x01"),
680 (ocsp.OCSPResponseStatus.INTERNAL_ERROR, b"0\x03\n\x01\x02"),
681 (ocsp.OCSPResponseStatus.TRY_LATER, b"0\x03\n\x01\x03"),
682 (ocsp.OCSPResponseStatus.SIG_REQUIRED, b"0\x03\n\x01\x05"),
683 (ocsp.OCSPResponseStatus.UNAUTHORIZED, b"0\x03\n\x01\x06"),
Lucia Lic6ba99d2021-11-08 22:06:11 +0800684 ],
Paul Kehrere617c5a2018-10-29 05:36:34 +0800685 )
686 def test_build_non_successful_statuses(self, status, der):
687 resp = ocsp.OCSPResponseBuilder.build_unsuccessful(status)
688 assert resp.response_status is status
689 assert resp.public_bytes(serialization.Encoding.DER) == der
690
691 def test_invalid_build_not_a_status(self):
692 with pytest.raises(TypeError):
693 ocsp.OCSPResponseBuilder.build_unsuccessful("notastatus")
694
695 def test_invalid_build_successful_status(self):
696 with pytest.raises(ValueError):
697 ocsp.OCSPResponseBuilder.build_unsuccessful(
698 ocsp.OCSPResponseStatus.SUCCESSFUL
699 )
700
701
Lucia Lic6ba99d2021-11-08 22:06:11 +0800702class TestSignedCertificateTimestampsExtension(object):
703 def test_init(self):
704 with pytest.raises(TypeError):
705 x509.SignedCertificateTimestamps([object()])
706
707 def test_repr(self):
708 assert repr(x509.SignedCertificateTimestamps([])) == (
709 "<SignedCertificateTimestamps([])>"
710 )
711
712 @pytest.mark.supported(
713 only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT),
714 skip_message="Requires CT support",
715 )
716 def test_eq(self, backend):
717 sct1 = (
718 _load_data(
719 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
720 ocsp.load_der_ocsp_response,
721 )
722 .single_extensions.get_extension_for_class(
723 x509.SignedCertificateTimestamps
724 )
725 .value
726 )
727 sct2 = (
728 _load_data(
729 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
730 ocsp.load_der_ocsp_response,
731 )
732 .single_extensions.get_extension_for_class(
733 x509.SignedCertificateTimestamps
734 )
735 .value
736 )
737 assert sct1 == sct2
738
739 @pytest.mark.supported(
740 only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT),
741 skip_message="Requires CT support",
742 )
743 def test_ne(self, backend):
744 sct1 = (
745 _load_data(
746 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
747 ocsp.load_der_ocsp_response,
748 )
749 .single_extensions.get_extension_for_class(
750 x509.SignedCertificateTimestamps
751 )
752 .value
753 )
754 sct2 = x509.SignedCertificateTimestamps([])
755 assert sct1 != sct2
756 assert sct1 != object()
757
758 @pytest.mark.supported(
759 only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT),
760 skip_message="Requires CT support",
761 )
762 def test_hash(self, backend):
763 sct1 = (
764 _load_data(
765 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
766 ocsp.load_der_ocsp_response,
767 )
768 .single_extensions.get_extension_for_class(
769 x509.SignedCertificateTimestamps
770 )
771 .value
772 )
773 sct2 = (
774 _load_data(
775 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
776 ocsp.load_der_ocsp_response,
777 )
778 .single_extensions.get_extension_for_class(
779 x509.SignedCertificateTimestamps
780 )
781 .value
782 )
783 sct3 = x509.SignedCertificateTimestamps([])
784 assert hash(sct1) == hash(sct2)
785 assert hash(sct1) != hash(sct3)
786
787
Paul Kehrera07de312018-10-02 07:54:31 +0800788class TestOCSPResponse(object):
789 def test_bad_response(self):
790 with pytest.raises(ValueError):
791 ocsp.load_der_ocsp_response(b"invalid")
792
793 def test_load_response(self):
794 resp = _load_data(
795 os.path.join("x509", "ocsp", "resp-sha256.der"),
796 ocsp.load_der_ocsp_response,
797 )
798 from cryptography.hazmat.backends.openssl.backend import backend
Lucia Lic6ba99d2021-11-08 22:06:11 +0800799
Paul Kehrera07de312018-10-02 07:54:31 +0800800 issuer = _load_cert(
801 os.path.join("x509", "letsencryptx3.pem"),
802 x509.load_pem_x509_certificate,
Lucia Lic6ba99d2021-11-08 22:06:11 +0800803 backend,
Paul Kehrera07de312018-10-02 07:54:31 +0800804 )
805 assert resp.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL
Lucia Lic6ba99d2021-11-08 22:06:11 +0800806 assert (
807 resp.signature_algorithm_oid
808 == x509.SignatureAlgorithmOID.RSA_WITH_SHA256
809 )
Paul Kehrer60f264b2019-01-10 15:37:03 -0800810 assert isinstance(resp.signature_hash_algorithm, hashes.SHA256)
Paul Kehrera07de312018-10-02 07:54:31 +0800811 assert resp.signature == base64.b64decode(
812 b"I9KUlyLV/2LbNCVu1BQphxdNlU/jBzXsPYVscPjW5E93pCrSO84GkIWoOJtqsnt"
813 b"78DLcQPnF3W24NXGzSGKlSWfXIsyoXCxnBm0mIbD5ZMnKyXEnqSR33Z9He/A+ML"
814 b"A8gbrDUipGNPosesenkKUnOtFIzEGv29hV5E6AMP2ORPVsVlTAZegPJFbbVIWc0"
815 b"rZGFCXKxijDxtUtgWzBhpBAI50JbPHi+IVuaOe4aDJLYgZ0BIBNa6bDI+rScyoy"
816 b"5U0DToV7SZn6CoJ3U19X7BHdYn6TLX0xi43eXuzBGzdHnSzmsc7r/DvkAKJm3vb"
817 b"dVECXqe/gFlXJUBcZ25jhs70MUA=="
818 )
819 assert resp.tbs_response_bytes == base64.b64decode(
820 b"MIHWoUwwSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzA"
821 b"hBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzGA8yMDE4MDgzMDExMT"
822 b"UwMFowdTBzMEswCQYFKw4DAhoFAAQUfuZq53Kas/z4oiBkbBahLWBxCF0EFKhKa"
823 b"mMEfd265tE5t6ZFZe/zqOyhAhIDHHh6fckClQB7xfIiCztSevCAABgPMjAxODA4"
824 b"MzAxMTAwMDBaoBEYDzIwMTgwOTA2MTEwMDAwWg=="
825 )
826 issuer.public_key().verify(
827 resp.signature,
828 resp.tbs_response_bytes,
829 PKCS1v15(),
Lucia Lic6ba99d2021-11-08 22:06:11 +0800830 resp.signature_hash_algorithm,
Paul Kehrera07de312018-10-02 07:54:31 +0800831 )
832 assert resp.certificates == []
833 assert resp.responder_key_hash is None
834 assert resp.responder_name == issuer.subject
835 assert resp.produced_at == datetime.datetime(2018, 8, 30, 11, 15)
836 assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD
837 assert resp.revocation_time is None
838 assert resp.revocation_reason is None
839 assert resp.this_update == datetime.datetime(2018, 8, 30, 11, 0)
840 assert resp.next_update == datetime.datetime(2018, 9, 6, 11, 0)
841 assert resp.issuer_key_hash == (
Lucia Lic6ba99d2021-11-08 22:06:11 +0800842 b"\xa8Jjc\x04}\xdd\xba\xe6\xd19\xb7\xa6Ee\xef\xf3\xa8\xec\xa1"
Paul Kehrera07de312018-10-02 07:54:31 +0800843 )
844 assert resp.issuer_name_hash == (
Lucia Lic6ba99d2021-11-08 22:06:11 +0800845 b"~\xe6j\xe7r\x9a\xb3\xfc\xf8\xa2 dl\x16\xa1-`q\x08]"
Paul Kehrera07de312018-10-02 07:54:31 +0800846 )
847 assert isinstance(resp.hash_algorithm, hashes.SHA1)
848 assert resp.serial_number == 271024907440004808294641238224534273948400
Paul Kehrerb8db6682018-10-07 03:44:30 +0800849 assert len(resp.extensions) == 0
Paul Kehrera07de312018-10-02 07:54:31 +0800850
Lucia Lic6ba99d2021-11-08 22:06:11 +0800851 def test_load_multi_valued_response(self):
852 with pytest.raises(ValueError):
853 _load_data(
854 os.path.join("x509", "ocsp", "ocsp-army.deps.mil-resp.der"),
855 ocsp.load_der_ocsp_response,
856 )
857
Paul Kehrera07de312018-10-02 07:54:31 +0800858 def test_load_unauthorized(self):
859 resp = _load_data(
860 os.path.join("x509", "ocsp", "resp-unauthorized.der"),
861 ocsp.load_der_ocsp_response,
862 )
863 assert resp.response_status == ocsp.OCSPResponseStatus.UNAUTHORIZED
864 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800865 resp.signature_algorithm_oid
Paul Kehrera07de312018-10-02 07:54:31 +0800866 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800867 resp.signature_hash_algorithm
Paul Kehrera07de312018-10-02 07:54:31 +0800868 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800869 resp.signature
Paul Kehrera07de312018-10-02 07:54:31 +0800870 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800871 resp.tbs_response_bytes
Paul Kehrera07de312018-10-02 07:54:31 +0800872 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800873 resp.certificates
Paul Kehrera07de312018-10-02 07:54:31 +0800874 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800875 resp.responder_key_hash
Paul Kehrera07de312018-10-02 07:54:31 +0800876 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800877 resp.responder_name
Paul Kehrera07de312018-10-02 07:54:31 +0800878 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800879 resp.produced_at
Paul Kehrera07de312018-10-02 07:54:31 +0800880 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800881 resp.certificate_status
Paul Kehrera07de312018-10-02 07:54:31 +0800882 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800883 resp.revocation_time
Paul Kehrera07de312018-10-02 07:54:31 +0800884 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800885 resp.revocation_reason
Paul Kehrera07de312018-10-02 07:54:31 +0800886 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800887 resp.this_update
Paul Kehrera07de312018-10-02 07:54:31 +0800888 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800889 resp.next_update
Paul Kehrera07de312018-10-02 07:54:31 +0800890 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800891 resp.issuer_key_hash
Paul Kehrera07de312018-10-02 07:54:31 +0800892 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800893 resp.issuer_name_hash
Paul Kehrera07de312018-10-02 07:54:31 +0800894 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800895 resp.hash_algorithm
Paul Kehrerb8db6682018-10-07 03:44:30 +0800896 with pytest.raises(ValueError):
Paul Kehrer60f264b2019-01-10 15:37:03 -0800897 resp.serial_number
898 with pytest.raises(ValueError):
899 resp.extensions
Paul Kehrera07de312018-10-02 07:54:31 +0800900
901 def test_load_revoked(self):
902 resp = _load_data(
903 os.path.join("x509", "ocsp", "resp-revoked.der"),
904 ocsp.load_der_ocsp_response,
905 )
906 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
907 assert resp.revocation_time == datetime.datetime(
908 2016, 9, 2, 21, 28, 48
909 )
910 assert resp.revocation_reason is None
911
912 def test_load_delegate_unknown_cert(self):
913 resp = _load_data(
914 os.path.join("x509", "ocsp", "resp-delegate-unknown-cert.der"),
915 ocsp.load_der_ocsp_response,
916 )
917 assert len(resp.certificates) == 1
918 assert isinstance(resp.certificates[0], x509.Certificate)
919 assert resp.certificate_status == ocsp.OCSPCertStatus.UNKNOWN
920
Paul Kehrer60f264b2019-01-10 15:37:03 -0800921 def test_load_invalid_signature_oid(self):
922 resp = _load_data(
923 os.path.join("x509", "ocsp", "resp-invalid-signature-oid.der"),
924 ocsp.load_der_ocsp_response,
925 )
926 assert resp.signature_algorithm_oid == x509.ObjectIdentifier(
927 "1.2.840.113549.1.1.2"
928 )
929 with pytest.raises(UnsupportedAlgorithm):
930 resp.signature_hash_algorithm
931
Paul Kehrera07de312018-10-02 07:54:31 +0800932 def test_load_responder_key_hash(self):
933 resp = _load_data(
934 os.path.join("x509", "ocsp", "resp-responder-key-hash.der"),
935 ocsp.load_der_ocsp_response,
936 )
937 assert resp.responder_name is None
938 assert resp.responder_key_hash == (
Lucia Lic6ba99d2021-11-08 22:06:11 +0800939 b"\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2"
Paul Kehrera07de312018-10-02 07:54:31 +0800940 )
941
942 def test_load_revoked_reason(self):
943 resp = _load_data(
944 os.path.join("x509", "ocsp", "resp-revoked-reason.der"),
945 ocsp.load_der_ocsp_response,
946 )
947 assert resp.revocation_reason is x509.ReasonFlags.superseded
Paul Kehrerb8db6682018-10-07 03:44:30 +0800948
Paul Kehrera9b4f862018-10-24 08:58:07 +0800949 def test_load_revoked_no_next_update(self):
950 resp = _load_data(
951 os.path.join("x509", "ocsp", "resp-revoked-no-next-update.der"),
952 ocsp.load_der_ocsp_response,
953 )
954 assert resp.serial_number == 16160
955 assert resp.next_update is None
956
Paul Kehrerb8db6682018-10-07 03:44:30 +0800957 def test_response_extensions(self):
958 resp = _load_data(
959 os.path.join("x509", "ocsp", "resp-revoked-reason.der"),
960 ocsp.load_der_ocsp_response,
961 )
962 assert len(resp.extensions) == 1
963 ext = resp.extensions[0]
964 assert ext.critical is False
965 assert ext.value == x509.OCSPNonce(
966 b'\x04\x105\x957\x9fa\x03\x83\x87\x89rW\x8f\xae\x99\xf7"'
967 )
Paul Kehrer788b8592018-10-07 11:07:14 +0800968
969 def test_serialize_reponse(self):
970 resp_bytes = load_vectors_from_file(
971 filename=os.path.join("x509", "ocsp", "resp-revoked.der"),
972 loader=lambda data: data.read(),
Lucia Lic6ba99d2021-11-08 22:06:11 +0800973 mode="rb",
Paul Kehrer788b8592018-10-07 11:07:14 +0800974 )
975 resp = ocsp.load_der_ocsp_response(resp_bytes)
976 assert resp.public_bytes(serialization.Encoding.DER) == resp_bytes
977
978 def test_invalid_serialize_encoding(self):
979 resp = _load_data(
980 os.path.join("x509", "ocsp", "resp-revoked.der"),
981 ocsp.load_der_ocsp_response,
982 )
983 with pytest.raises(ValueError):
984 resp.public_bytes("invalid")
985 with pytest.raises(ValueError):
986 resp.public_bytes(serialization.Encoding.PEM)
Lucia Lic6ba99d2021-11-08 22:06:11 +0800987
988 @pytest.mark.supported(
989 only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT),
990 skip_message="Requires CT support",
991 )
992 def test_single_extensions_sct(self, backend):
993 resp = _load_data(
994 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
995 ocsp.load_der_ocsp_response,
996 )
997 assert len(resp.single_extensions) == 1
998 ext = resp.single_extensions[0]
999 assert ext.oid == x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5")
1000 assert len(ext.value) == 4
1001 log_ids = [base64.b64encode(sct.log_id) for sct in ext.value]
1002 assert log_ids == [
1003 b"RJRlLrDuzq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2gag=",
1004 b"b1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RM=",
1005 b"u9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YU=",
1006 b"7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=",
1007 ]
1008
1009 @pytest.mark.supported(
1010 only_if=lambda backend: (
1011 not backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER
1012 ),
1013 skip_message="Requires OpenSSL < 1.1.0f",
1014 )
1015 def test_skips_single_extensions_scts_if_unsupported(self, backend):
1016 resp = _load_data(
1017 os.path.join("x509", "ocsp", "resp-sct-extension.der"),
1018 ocsp.load_der_ocsp_response,
1019 )
1020 with pytest.raises(x509.ExtensionNotFound):
1021 resp.single_extensions.get_extension_for_class(
1022 x509.SignedCertificateTimestamps
1023 )
1024
1025 ext = resp.single_extensions.get_extension_for_oid(
1026 x509.ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1027 )
1028 assert isinstance(ext.value, x509.UnrecognizedExtension)
1029
1030 def test_single_extensions(self, backend):
1031 resp = _load_data(
1032 os.path.join("x509", "ocsp", "resp-single-extension-reason.der"),
1033 ocsp.load_der_ocsp_response,
1034 )
1035 assert len(resp.single_extensions) == 1
1036 ext = resp.single_extensions[0]
1037 assert ext.oid == x509.CRLReason.oid
1038 assert ext.value == x509.CRLReason(x509.ReasonFlags.unspecified)
1039
1040
1041class TestOCSPEdDSA(object):
1042 @pytest.mark.supported(
1043 only_if=lambda backend: backend.ed25519_supported(),
1044 skip_message="Requires OpenSSL with Ed25519 support / OCSP",
1045 )
1046 def test_invalid_algorithm(self, backend):
1047 builder = ocsp.OCSPResponseBuilder()
1048 cert, issuer = _cert_and_issuer()
1049 private_key = ed25519.Ed25519PrivateKey.generate()
1050 root_cert, _ = _generate_root(private_key, None)
1051 current_time = datetime.datetime.utcnow().replace(microsecond=0)
1052 this_update = current_time - datetime.timedelta(days=1)
1053 next_update = this_update + datetime.timedelta(days=7)
1054 revoked_date = this_update - datetime.timedelta(days=300)
1055 builder = builder.responder_id(
1056 ocsp.OCSPResponderEncoding.NAME, root_cert
1057 ).add_response(
1058 cert,
1059 issuer,
1060 hashes.SHA1(),
1061 ocsp.OCSPCertStatus.REVOKED,
1062 this_update,
1063 next_update,
1064 revoked_date,
1065 x509.ReasonFlags.key_compromise,
1066 )
1067 with pytest.raises(ValueError):
1068 builder.sign(private_key, hashes.SHA256())
1069
1070 @pytest.mark.supported(
1071 only_if=lambda backend: backend.ed25519_supported(),
1072 skip_message="Requires OpenSSL with Ed25519 support / OCSP",
1073 )
1074 def test_sign_ed25519(self, backend):
1075 builder = ocsp.OCSPResponseBuilder()
1076 cert, issuer = _cert_and_issuer()
1077 private_key = ed25519.Ed25519PrivateKey.generate()
1078 root_cert, _ = _generate_root(private_key, None)
1079 current_time = datetime.datetime.utcnow().replace(microsecond=0)
1080 this_update = current_time - datetime.timedelta(days=1)
1081 next_update = this_update + datetime.timedelta(days=7)
1082 revoked_date = this_update - datetime.timedelta(days=300)
1083 builder = builder.responder_id(
1084 ocsp.OCSPResponderEncoding.NAME, root_cert
1085 ).add_response(
1086 cert,
1087 issuer,
1088 hashes.SHA1(),
1089 ocsp.OCSPCertStatus.REVOKED,
1090 this_update,
1091 next_update,
1092 revoked_date,
1093 x509.ReasonFlags.key_compromise,
1094 )
1095 resp = builder.sign(private_key, None)
1096 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
1097 assert resp.revocation_time == revoked_date
1098 assert resp.revocation_reason is x509.ReasonFlags.key_compromise
1099 assert resp.this_update == this_update
1100 assert resp.next_update == next_update
1101 assert resp.signature_hash_algorithm is None
1102 assert (
1103 resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED25519
1104 )
1105 private_key.public_key().verify(
1106 resp.signature, resp.tbs_response_bytes
1107 )
1108
1109 @pytest.mark.supported(
1110 only_if=lambda backend: backend.ed448_supported(),
1111 skip_message="Requires OpenSSL with Ed448 support / OCSP",
1112 )
1113 def test_sign_ed448(self, backend):
1114 builder = ocsp.OCSPResponseBuilder()
1115 cert, issuer = _cert_and_issuer()
1116 private_key = ed448.Ed448PrivateKey.generate()
1117 root_cert, _ = _generate_root(private_key, None)
1118 current_time = datetime.datetime.utcnow().replace(microsecond=0)
1119 this_update = current_time - datetime.timedelta(days=1)
1120 next_update = this_update + datetime.timedelta(days=7)
1121 revoked_date = this_update - datetime.timedelta(days=300)
1122 builder = builder.responder_id(
1123 ocsp.OCSPResponderEncoding.NAME, root_cert
1124 ).add_response(
1125 cert,
1126 issuer,
1127 hashes.SHA1(),
1128 ocsp.OCSPCertStatus.REVOKED,
1129 this_update,
1130 next_update,
1131 revoked_date,
1132 x509.ReasonFlags.key_compromise,
1133 )
1134 resp = builder.sign(private_key, None)
1135 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
1136 assert resp.revocation_time == revoked_date
1137 assert resp.revocation_reason is x509.ReasonFlags.key_compromise
1138 assert resp.this_update == this_update
1139 assert resp.next_update == next_update
1140 assert resp.signature_hash_algorithm is None
1141 assert resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED448
1142 private_key.public_key().verify(
1143 resp.signature, resp.tbs_response_bytes
1144 )