blob: aeaa6e6c064c18a089cdab1efc29c4230c48045a [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
210
211 def test_load_unauthorized(self):
212 resp = _load_data(
213 os.path.join("x509", "ocsp", "resp-unauthorized.der"),
214 ocsp.load_der_ocsp_response,
215 )
216 assert resp.response_status == ocsp.OCSPResponseStatus.UNAUTHORIZED
217 with pytest.raises(ValueError):
218 assert resp.signature_algorithm_oid
219 with pytest.raises(ValueError):
220 assert resp.signature
221 with pytest.raises(ValueError):
222 assert resp.tbs_response_bytes
223 with pytest.raises(ValueError):
224 assert resp.certificates
225 with pytest.raises(ValueError):
226 assert resp.responder_key_hash
227 with pytest.raises(ValueError):
228 assert resp.responder_name
229 with pytest.raises(ValueError):
230 assert resp.produced_at
231 with pytest.raises(ValueError):
232 assert resp.certificate_status
233 with pytest.raises(ValueError):
234 assert resp.revocation_time
235 with pytest.raises(ValueError):
236 assert resp.revocation_reason
237 with pytest.raises(ValueError):
238 assert resp.this_update
239 with pytest.raises(ValueError):
240 assert resp.next_update
241 with pytest.raises(ValueError):
242 assert resp.issuer_key_hash
243 with pytest.raises(ValueError):
244 assert resp.issuer_name_hash
245 with pytest.raises(ValueError):
246 assert resp.hash_algorithm
247 with pytest.raises(ValueError):
248 assert resp.serial_number
249
250 def test_load_revoked(self):
251 resp = _load_data(
252 os.path.join("x509", "ocsp", "resp-revoked.der"),
253 ocsp.load_der_ocsp_response,
254 )
255 assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED
256 assert resp.revocation_time == datetime.datetime(
257 2016, 9, 2, 21, 28, 48
258 )
259 assert resp.revocation_reason is None
260
261 def test_load_delegate_unknown_cert(self):
262 resp = _load_data(
263 os.path.join("x509", "ocsp", "resp-delegate-unknown-cert.der"),
264 ocsp.load_der_ocsp_response,
265 )
266 assert len(resp.certificates) == 1
267 assert isinstance(resp.certificates[0], x509.Certificate)
268 assert resp.certificate_status == ocsp.OCSPCertStatus.UNKNOWN
269
270 def test_load_responder_key_hash(self):
271 resp = _load_data(
272 os.path.join("x509", "ocsp", "resp-responder-key-hash.der"),
273 ocsp.load_der_ocsp_response,
274 )
275 assert resp.responder_name is None
276 assert resp.responder_key_hash == (
277 b'\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2'
278 )
279
280 def test_load_revoked_reason(self):
281 resp = _load_data(
282 os.path.join("x509", "ocsp", "resp-revoked-reason.der"),
283 ocsp.load_der_ocsp_response,
284 )
285 assert resp.revocation_reason is x509.ReasonFlags.superseded