blob: 0d98ac291c5e6f79421767424092d7a642fb0b2b [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
Paul Kehrera07de312018-10-02 07:54:31 +080016from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
Paul Kehrer732cf642018-08-15 18:04:28 -050017from cryptography.x509 import ocsp
18
Paul Kehrer002fa752018-08-30 10:41:32 -040019from .test_x509 import _load_cert
Paul Kehrer732cf642018-08-15 18:04:28 -050020from ..utils import load_vectors_from_file
21
22
23def _load_data(filename, loader):
24 return load_vectors_from_file(
25 filename=filename,
26 loader=lambda data: loader(data.read()),
27 mode="rb"
28 )
29
30
Paul Kehrer002fa752018-08-30 10:41:32 -040031def _cert_and_issuer():
32 from cryptography.hazmat.backends.openssl.backend import backend
33 cert = _load_cert(
34 os.path.join("x509", "cryptography.io.pem"),
35 x509.load_pem_x509_certificate,
36 backend
37 )
38 issuer = _load_cert(
39 os.path.join("x509", "rapidssl_sha256_ca_g3.pem"),
40 x509.load_pem_x509_certificate,
41 backend
42 )
43 return cert, issuer
44
45
Paul Kehrer732cf642018-08-15 18:04:28 -050046class TestOCSPRequest(object):
47 def test_bad_request(self):
48 with pytest.raises(ValueError):
49 ocsp.load_der_ocsp_request(b"invalid")
50
Paul Kehrer0f629bb2018-08-31 10:47:56 -040051 def test_load_request(self):
Paul Kehrer732cf642018-08-15 18:04:28 -050052 req = _load_data(
53 os.path.join("x509", "ocsp", "req-sha1.der"),
54 ocsp.load_der_ocsp_request,
55 )
Paul Kehrer0f629bb2018-08-31 10:47:56 -040056 assert req.issuer_name_hash == (b"8\xcaF\x8c\x07D\x8d\xf4\x81\x96"
57 b"\xc7mmLpQ\x9e`\xa7\xbd")
58 assert req.issuer_key_hash == (b"yu\xbb\x84:\xcb,\xdez\t\xbe1"
59 b"\x1bC\xbc\x1c*MSX")
60 assert isinstance(req.hash_algorithm, hashes.SHA1)
61 assert req.serial_number == int(
Paul Kehrer732cf642018-08-15 18:04:28 -050062 "98D9E5C0B4C373552DF77C5D0F1EB5128E4945F9", 16
63 )
Paul Kehrer09403102018-09-09 21:57:21 -050064 assert len(req.extensions) == 0
65
66 def test_load_request_with_extensions(self):
67 req = _load_data(
68 os.path.join("x509", "ocsp", "req-ext-nonce.der"),
69 ocsp.load_der_ocsp_request,
70 )
71 assert len(req.extensions) == 1
72 ext = req.extensions[0]
73 assert ext.critical is False
74 assert ext.value == x509.OCSPNonce(
75 b"\x04\x10{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd"
76 )
Paul Kehrer732cf642018-08-15 18:04:28 -050077
Paul Kehrer0f629bb2018-08-31 10:47:56 -040078 def test_load_request_two_requests(self):
79 with pytest.raises(NotImplementedError):
80 _load_data(
81 os.path.join("x509", "ocsp", "req-multi-sha1.der"),
82 ocsp.load_der_ocsp_request,
83 )
Paul Kehrer732cf642018-08-15 18:04:28 -050084
85 def test_invalid_hash_algorithm(self):
86 req = _load_data(
87 os.path.join("x509", "ocsp", "req-invalid-hash-alg.der"),
88 ocsp.load_der_ocsp_request,
89 )
90 with pytest.raises(UnsupportedAlgorithm):
Paul Kehrer0f629bb2018-08-31 10:47:56 -040091 req.hash_algorithm
Paul Kehrer732cf642018-08-15 18:04:28 -050092
93 def test_serialize_request(self):
94 req_bytes = load_vectors_from_file(
95 filename=os.path.join("x509", "ocsp", "req-sha1.der"),
96 loader=lambda data: data.read(),
97 mode="rb"
98 )
99 req = ocsp.load_der_ocsp_request(req_bytes)
100 assert req.public_bytes(serialization.Encoding.DER) == req_bytes
101
102 def test_invalid_serialize_encoding(self):
103 req = _load_data(
104 os.path.join("x509", "ocsp", "req-sha1.der"),
105 ocsp.load_der_ocsp_request,
106 )
107 with pytest.raises(ValueError):
108 req.public_bytes("invalid")
109 with pytest.raises(ValueError):
110 req.public_bytes(serialization.Encoding.PEM)
Paul Kehrer002fa752018-08-30 10:41:32 -0400111
112
113class TestOCSPRequestBuilder(object):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400114 def test_add_two_certs(self):
115 cert, issuer = _cert_and_issuer()
116 builder = ocsp.OCSPRequestBuilder()
117 builder = builder.add_certificate(cert, issuer, hashes.SHA1())
118 with pytest.raises(ValueError):
119 builder.add_certificate(cert, issuer, hashes.SHA1())
120
Paul Kehrer002fa752018-08-30 10:41:32 -0400121 def test_create_ocsp_request_no_req(self):
122 builder = ocsp.OCSPRequestBuilder()
123 with pytest.raises(ValueError):
124 builder.build()
125
126 def test_create_ocsp_request_invalid_alg(self):
127 cert, issuer = _cert_and_issuer()
128 builder = ocsp.OCSPRequestBuilder()
129 with pytest.raises(ValueError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400130 builder.add_certificate(cert, issuer, hashes.MD5())
Paul Kehrer002fa752018-08-30 10:41:32 -0400131
132 def test_create_ocsp_request_invalid_cert(self):
133 cert, issuer = _cert_and_issuer()
134 builder = ocsp.OCSPRequestBuilder()
135 with pytest.raises(TypeError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400136 builder.add_certificate(b"notacert", issuer, hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400137
138 with pytest.raises(TypeError):
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400139 builder.add_certificate(cert, b"notacert", hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400140
141 def test_create_ocsp_request(self):
142 cert, issuer = _cert_and_issuer()
143 builder = ocsp.OCSPRequestBuilder()
Paul Kehrer0f629bb2018-08-31 10:47:56 -0400144 builder = builder.add_certificate(cert, issuer, hashes.SHA1())
Paul Kehrer002fa752018-08-30 10:41:32 -0400145 req = builder.build()
146 serialized = req.public_bytes(serialization.Encoding.DER)
147 assert serialized == base64.b64decode(
148 b"MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz"
149 b"/NNGCDS7zkZ/oHxb8+IIy1kCAj8g"
150 )
Paul Kehrera07de312018-10-02 07:54:31 +0800151
152
153class TestOCSPResponse(object):
154 def test_bad_response(self):
155 with pytest.raises(ValueError):
156 ocsp.load_der_ocsp_response(b"invalid")
157
158 def test_load_response(self):
159 resp = _load_data(
160 os.path.join("x509", "ocsp", "resp-sha256.der"),
161 ocsp.load_der_ocsp_response,
162 )
163 from cryptography.hazmat.backends.openssl.backend import backend
164 issuer = _load_cert(
165 os.path.join("x509", "letsencryptx3.pem"),
166 x509.load_pem_x509_certificate,
167 backend
168 )
169 assert resp.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL
170 assert (resp.signature_algorithm_oid ==
171 x509.SignatureAlgorithmOID.RSA_WITH_SHA256)
172 assert resp.signature == base64.b64decode(
173 b"I9KUlyLV/2LbNCVu1BQphxdNlU/jBzXsPYVscPjW5E93pCrSO84GkIWoOJtqsnt"
174 b"78DLcQPnF3W24NXGzSGKlSWfXIsyoXCxnBm0mIbD5ZMnKyXEnqSR33Z9He/A+ML"
175 b"A8gbrDUipGNPosesenkKUnOtFIzEGv29hV5E6AMP2ORPVsVlTAZegPJFbbVIWc0"
176 b"rZGFCXKxijDxtUtgWzBhpBAI50JbPHi+IVuaOe4aDJLYgZ0BIBNa6bDI+rScyoy"
177 b"5U0DToV7SZn6CoJ3U19X7BHdYn6TLX0xi43eXuzBGzdHnSzmsc7r/DvkAKJm3vb"
178 b"dVECXqe/gFlXJUBcZ25jhs70MUA=="
179 )
180 assert resp.tbs_response_bytes == base64.b64decode(
181 b"MIHWoUwwSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzA"
182 b"hBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzGA8yMDE4MDgzMDExMT"
183 b"UwMFowdTBzMEswCQYFKw4DAhoFAAQUfuZq53Kas/z4oiBkbBahLWBxCF0EFKhKa"
184 b"mMEfd265tE5t6ZFZe/zqOyhAhIDHHh6fckClQB7xfIiCztSevCAABgPMjAxODA4"
185 b"MzAxMTAwMDBaoBEYDzIwMTgwOTA2MTEwMDAwWg=="
186 )
187 issuer.public_key().verify(
188 resp.signature,
189 resp.tbs_response_bytes,
190 PKCS1v15(),
191 hashes.SHA256()
192 )
193 assert resp.certificates == []
194 assert resp.responder_key_hash is None
195 assert resp.responder_name == issuer.subject
196 assert resp.produced_at == datetime.datetime(2018, 8, 30, 11, 15)
197 assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD
198 assert resp.revocation_time is None
199 assert resp.revocation_reason is None
200 assert resp.this_update == datetime.datetime(2018, 8, 30, 11, 0)
201 assert resp.next_update == datetime.datetime(2018, 9, 6, 11, 0)
202 assert resp.issuer_key_hash == (
203 b'\xa8Jjc\x04}\xdd\xba\xe6\xd19\xb7\xa6Ee\xef\xf3\xa8\xec\xa1'
204 )
205 assert resp.issuer_name_hash == (
206 b'~\xe6j\xe7r\x9a\xb3\xfc\xf8\xa2 dl\x16\xa1-`q\x08]'
207 )
208 assert isinstance(resp.hash_algorithm, hashes.SHA1)
209 assert resp.serial_number == 271024907440004808294641238224534273948400
Paul Kehrerb8db6682018-10-07 03:44:30 +0800210 assert len(resp.extensions) == 0
Paul Kehrera07de312018-10-02 07:54:31 +0800211
212 def test_load_unauthorized(self):
213 resp = _load_data(
214 os.path.join("x509", "ocsp", "resp-unauthorized.der"),
215 ocsp.load_der_ocsp_response,
216 )
217 assert resp.response_status == ocsp.OCSPResponseStatus.UNAUTHORIZED
218 with pytest.raises(ValueError):
219 assert resp.signature_algorithm_oid
220 with pytest.raises(ValueError):
221 assert resp.signature
222 with pytest.raises(ValueError):
223 assert resp.tbs_response_bytes
224 with pytest.raises(ValueError):
225 assert resp.certificates
226 with pytest.raises(ValueError):
227 assert resp.responder_key_hash
228 with pytest.raises(ValueError):
229 assert resp.responder_name
230 with pytest.raises(ValueError):
231 assert resp.produced_at
232 with pytest.raises(ValueError):
233 assert resp.certificate_status
234 with pytest.raises(ValueError):
235 assert resp.revocation_time
236 with pytest.raises(ValueError):
237 assert resp.revocation_reason
238 with pytest.raises(ValueError):
239 assert resp.this_update
240 with pytest.raises(ValueError):
241 assert resp.next_update
242 with pytest.raises(ValueError):
243 assert resp.issuer_key_hash
244 with pytest.raises(ValueError):
245 assert resp.issuer_name_hash
246 with pytest.raises(ValueError):
247 assert resp.hash_algorithm
248 with pytest.raises(ValueError):
249 assert resp.serial_number
Paul Kehrerb8db6682018-10-07 03:44:30 +0800250 with pytest.raises(ValueError):
251 assert resp.extensions
Paul Kehrera07de312018-10-02 07:54:31 +0800252
253 def test_load_revoked(self):
254 resp = _load_data(
255 os.path.join("x509", "ocsp", "resp-revoked.der"),
256 ocsp.load_der_ocsp_response,
257 )
258 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
259 assert resp.revocation_time == datetime.datetime(
260 2016, 9, 2, 21, 28, 48
261 )
262 assert resp.revocation_reason is None
263
264 def test_load_delegate_unknown_cert(self):
265 resp = _load_data(
266 os.path.join("x509", "ocsp", "resp-delegate-unknown-cert.der"),
267 ocsp.load_der_ocsp_response,
268 )
269 assert len(resp.certificates) == 1
270 assert isinstance(resp.certificates[0], x509.Certificate)
271 assert resp.certificate_status == ocsp.OCSPCertStatus.UNKNOWN
272
273 def test_load_responder_key_hash(self):
274 resp = _load_data(
275 os.path.join("x509", "ocsp", "resp-responder-key-hash.der"),
276 ocsp.load_der_ocsp_response,
277 )
278 assert resp.responder_name is None
279 assert resp.responder_key_hash == (
280 b'\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2'
281 )
282
283 def test_load_revoked_reason(self):
284 resp = _load_data(
285 os.path.join("x509", "ocsp", "resp-revoked-reason.der"),
286 ocsp.load_der_ocsp_response,
287 )
288 assert resp.revocation_reason is x509.ReasonFlags.superseded
Paul Kehrerb8db6682018-10-07 03:44:30 +0800289
290 def test_response_extensions(self):
291 resp = _load_data(
292 os.path.join("x509", "ocsp", "resp-revoked-reason.der"),
293 ocsp.load_der_ocsp_response,
294 )
295 assert len(resp.extensions) == 1
296 ext = resp.extensions[0]
297 assert ext.critical is False
298 assert ext.value == x509.OCSPNonce(
299 b'\x04\x105\x957\x9fa\x03\x83\x87\x89rW\x8f\xae\x99\xf7"'
300 )