forked from pyca/cryptography
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_verification.py
206 lines (169 loc) · 6.72 KB
/
test_verification.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
import datetime
import os
from functools import lru_cache
from ipaddress import IPv4Address
import pytest
from cryptography import x509
from cryptography.x509.general_name import DNSName, IPAddress
from cryptography.x509.verification import (
PolicyBuilder,
Store,
VerificationError,
)
from tests.x509.test_x509 import _load_cert
@lru_cache(maxsize=1)
def dummy_store() -> Store:
cert = _load_cert(
os.path.join("x509", "cryptography.io.pem"),
x509.load_pem_x509_certificate,
)
return Store([cert])
class TestPolicyBuilder:
def test_time_already_set(self):
with pytest.raises(ValueError):
PolicyBuilder().time(datetime.datetime.now()).time(
datetime.datetime.now()
)
def test_store_already_set(self):
with pytest.raises(ValueError):
PolicyBuilder().store(dummy_store()).store(dummy_store())
def test_max_chain_depth_already_set(self):
with pytest.raises(ValueError):
PolicyBuilder().max_chain_depth(8).max_chain_depth(9)
def test_ipaddress_subject(self):
policy = (
PolicyBuilder()
.store(dummy_store())
.build_server_verifier(IPAddress(IPv4Address("0.0.0.0")))
)
assert policy.subject == IPAddress(IPv4Address("0.0.0.0"))
def test_dnsname_subject(self):
policy = (
PolicyBuilder()
.store(dummy_store())
.build_server_verifier(DNSName("cryptography.io"))
)
assert policy.subject == DNSName("cryptography.io")
def test_subject_bad_types(self):
# Subject must be a supported GeneralName type
with pytest.raises(TypeError):
PolicyBuilder().store(dummy_store()).build_server_verifier(
"cryptography.io" # type: ignore[arg-type]
)
with pytest.raises(TypeError):
PolicyBuilder().store(dummy_store()).build_server_verifier(
"0.0.0.0" # type: ignore[arg-type]
)
with pytest.raises(TypeError):
PolicyBuilder().store(dummy_store()).build_server_verifier(
IPv4Address("0.0.0.0") # type: ignore[arg-type]
)
with pytest.raises(TypeError):
PolicyBuilder().store(dummy_store()).build_server_verifier(None) # type: ignore[arg-type]
def test_builder_pattern(self):
now = datetime.datetime.now().replace(microsecond=0)
store = dummy_store()
max_chain_depth = 16
builder = PolicyBuilder()
builder = builder.time(now)
builder = builder.store(store)
builder = builder.max_chain_depth(max_chain_depth)
verifier = builder.build_server_verifier(DNSName("cryptography.io"))
assert verifier.subject == DNSName("cryptography.io")
assert verifier.validation_time == now
assert verifier.store == store
assert verifier.max_chain_depth == max_chain_depth
def test_build_server_verifier_missing_store(self):
with pytest.raises(
ValueError, match="A server verifier must have a trust store"
):
PolicyBuilder().build_server_verifier(DNSName("cryptography.io"))
class TestStore:
def test_store_rejects_empty_list(self):
with pytest.raises(ValueError):
Store([])
def test_store_rejects_non_certificates(self):
with pytest.raises(TypeError):
Store(["not a cert"]) # type: ignore[list-item]
class TestClientVerifier:
def test_build_client_verifier_missing_store(self):
with pytest.raises(
ValueError, match="A client verifier must have a trust store"
):
PolicyBuilder().build_client_verifier()
def test_verify(self):
# expires 2018-11-16 01:15:03 UTC
leaf = _load_cert(
os.path.join("x509", "cryptography.io.pem"),
x509.load_pem_x509_certificate,
)
store = Store([leaf])
validation_time = datetime.datetime.fromisoformat(
"2018-11-16T00:00:00+00:00"
)
builder = PolicyBuilder().store(store)
builder = builder.time(validation_time).max_chain_depth(16)
verifier = builder.build_client_verifier()
assert verifier.validation_time == validation_time.replace(tzinfo=None)
assert verifier.max_chain_depth == 16
assert verifier.store is store
verified_client = verifier.verify(leaf, [])
assert verified_client.chain == [leaf]
assert verified_client.subjects is not None
assert x509.DNSName("www.cryptography.io") in verified_client.subjects
assert x509.DNSName("cryptography.io") in verified_client.subjects
assert len(verified_client.subjects) == 2
def test_verify_fails_renders_oid(self):
leaf = _load_cert(
os.path.join("x509", "custom", "ekucrit-testuser-cert.pem"),
x509.load_pem_x509_certificate,
)
store = Store([leaf])
validation_time = datetime.datetime.fromisoformat(
"2024-06-26T00:00:00+00:00"
)
builder = PolicyBuilder().store(store)
builder = builder.time(validation_time)
verifier = builder.build_client_verifier()
pattern = (
r"invalid extension: 2\.5\.29\.37: "
r"Certificate extension has incorrect criticality"
)
with pytest.raises(
VerificationError,
match=pattern,
):
verifier.verify(leaf, [])
class TestServerVerifier:
@pytest.mark.parametrize(
("validation_time", "valid"),
[
# 03:15:02 UTC+2, or 1 second before expiry in UTC
("2018-11-16T03:15:02+02:00", True),
# 00:15:04 UTC-1, or 1 second after expiry in UTC
("2018-11-16T00:15:04-01:00", False),
],
)
def test_verify_tz_aware(self, validation_time, valid):
# expires 2018-11-16 01:15:03 UTC
leaf = _load_cert(
os.path.join("x509", "cryptography.io.pem"),
x509.load_pem_x509_certificate,
)
store = Store([leaf])
builder = PolicyBuilder().store(store)
builder = builder.time(
datetime.datetime.fromisoformat(validation_time)
)
verifier = builder.build_server_verifier(DNSName("cryptography.io"))
if valid:
assert verifier.verify(leaf, []) == [leaf]
else:
with pytest.raises(
x509.verification.VerificationError,
match="cert is not valid at validation time",
):
verifier.verify(leaf, [])