0
# Certificate Verification
1
2
Certificate trust store management and verification operations with support for certificate chains, CRL checking, and custom verification policies.
3
4
## Capabilities
5
6
### Certificate Trust Stores
7
8
Manage collections of trusted certificates and certificate revocation lists for verification operations.
9
10
```python { .api }
11
class X509Store:
12
def __init__(self):
13
"""Create new empty certificate store"""
14
15
def add_cert(self, cert: X509):
16
"""
17
Add trusted certificate to store.
18
19
Parameters:
20
- cert: X509 certificate to trust
21
"""
22
23
def add_crl(self, crl):
24
"""
25
Add certificate revocation list.
26
27
Parameters:
28
- crl: Certificate revocation list object
29
"""
30
31
def set_flags(self, flags: int):
32
"""
33
Set verification behavior flags.
34
35
Parameters:
36
- flags: Combination of X509StoreFlags constants
37
"""
38
39
def set_time(self, vfy_time):
40
"""
41
Set verification time for time-sensitive checks.
42
43
Parameters:
44
- vfy_time: datetime object for verification time
45
"""
46
47
def load_locations(self, cafile, capath=None):
48
"""
49
Load CA certificates from file or directory.
50
51
Parameters:
52
- cafile: Path to CA certificate file (PEM format)
53
- capath: Path to directory containing CA certificates
54
"""
55
```
56
57
### Certificate Verification Context
58
59
Perform actual certificate verification against trust stores with detailed error reporting.
60
61
```python { .api }
62
class X509StoreContext:
63
def __init__(self, store: X509Store, certificate: X509, chain=None):
64
"""
65
Create verification context.
66
67
Parameters:
68
- store: Trust store containing CA certificates
69
- certificate: Certificate to verify
70
- chain: Optional list of intermediate certificates
71
"""
72
73
def set_store(self, store: X509Store):
74
"""
75
Change the trust store.
76
77
Parameters:
78
- store: New trust store to use
79
"""
80
81
def verify_certificate(self):
82
"""
83
Verify certificate against store.
84
85
Raises:
86
X509StoreContextError: If verification fails
87
"""
88
89
def get_verified_chain(self) -> list:
90
"""
91
Get complete verified certificate chain.
92
93
Returns:
94
List of X509 certificates from end-entity to root
95
"""
96
```
97
98
### Verification Flags
99
100
Control certificate verification behavior with detailed policy options.
101
102
```python { .api }
103
class X509StoreFlags:
104
CRL_CHECK: int
105
CRL_CHECK_ALL: int
106
IGNORE_CRITICAL: int
107
X509_STRICT: int
108
ALLOW_PROXY_CERTS: int
109
POLICY_CHECK: int
110
EXPLICIT_POLICY: int
111
INHIBIT_MAP: int
112
CHECK_SS_SIGNATURE: int
113
PARTIAL_CHAIN: int
114
```
115
116
### Verification Exceptions
117
118
Detailed error reporting for certificate verification failures.
119
120
```python { .api }
121
class X509StoreContextError(Exception):
122
"""Exception raised when certificate verification fails"""
123
124
certificate: X509 # Certificate that caused the error
125
errors: list # List of detailed error information
126
```
127
128
### Verification Result Codes
129
130
Standard X.509 verification result codes for detailed error analysis.
131
132
```python { .api }
133
# Note: X509VerificationCodes is defined in the SSL module
134
from OpenSSL.SSL import X509VerificationCodes
135
136
class X509VerificationCodes:
137
OK: int
138
ERR_UNABLE_TO_GET_ISSUER_CERT: int
139
ERR_UNABLE_TO_GET_CRL: int
140
ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: int
141
ERR_CERT_SIGNATURE_FAILURE: int
142
ERR_CRL_SIGNATURE_FAILURE: int
143
ERR_CERT_NOT_YET_VALID: int
144
ERR_CERT_HAS_EXPIRED: int
145
ERR_CRL_NOT_YET_VALID: int
146
ERR_CRL_HAS_EXPIRED: int
147
ERR_DEPTH_ZERO_SELF_SIGNED_CERT: int
148
ERR_SELF_SIGNED_CERT_IN_CHAIN: int
149
ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: int
150
ERR_CERT_CHAIN_TOO_LONG: int
151
ERR_CERT_REVOKED: int
152
```
153
154
## Usage Examples
155
156
### Basic Certificate Verification
157
158
```python
159
from OpenSSL import crypto
160
161
# Load certificates
162
with open('ca.crt', 'rb') as f:
163
ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
164
165
with open('server.crt', 'rb') as f:
166
server_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
167
168
# Create trust store and add CA
169
store = crypto.X509Store()
170
store.add_cert(ca_cert)
171
172
# Create verification context
173
context = crypto.X509StoreContext(store, server_cert)
174
175
try:
176
# Verify certificate
177
context.verify_certificate()
178
print("Certificate verification successful")
179
180
# Get verified chain
181
chain = context.get_verified_chain()
182
print(f"Verified chain length: {len(chain)}")
183
184
except crypto.X509StoreContextError as e:
185
print(f"Verification failed: {e}")
186
print(f"Failed certificate: {e.certificate.get_subject().CN}")
187
```
188
189
### Verification with Intermediate Certificates
190
191
```python
192
from OpenSSL import crypto
193
194
# Load certificate chain
195
with open('ca.crt', 'rb') as f:
196
ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
197
198
with open('intermediate.crt', 'rb') as f:
199
intermediate_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
200
201
with open('server.crt', 'rb') as f:
202
server_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
203
204
# Create trust store with root CA
205
store = crypto.X509Store()
206
store.add_cert(ca_cert)
207
208
# Verify with intermediate certificate in chain
209
context = crypto.X509StoreContext(store, server_cert, [intermediate_cert])
210
211
try:
212
context.verify_certificate()
213
print("Chain verification successful")
214
215
# Print full chain
216
chain = context.get_verified_chain()
217
for i, cert in enumerate(chain):
218
print(f"Chain[{i}]: {cert.get_subject().CN}")
219
220
except crypto.X509StoreContextError as e:
221
print(f"Chain verification failed: {e}")
222
```
223
224
### Advanced Verification with Flags
225
226
```python
227
from OpenSSL import crypto
228
import datetime
229
230
# Create store with custom flags
231
store = crypto.X509Store()
232
233
# Enable strict checking and CRL validation
234
flags = (crypto.X509StoreFlags.X509_STRICT |
235
crypto.X509StoreFlags.CRL_CHECK_ALL)
236
store.set_flags(flags)
237
238
# Set specific verification time
239
verification_time = datetime.datetime(2023, 6, 1)
240
store.set_time(verification_time)
241
242
# Load CA certificates from directory
243
store.load_locations(None, '/etc/ssl/certs')
244
245
# Add specific trusted certificate
246
with open('trusted.crt', 'rb') as f:
247
trusted_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
248
store.add_cert(trusted_cert)
249
250
# Verify certificate with strict policies
251
with open('test.crt', 'rb') as f:
252
test_cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
253
254
context = crypto.X509StoreContext(store, test_cert)
255
256
try:
257
context.verify_certificate()
258
print("Strict verification passed")
259
260
except crypto.X509StoreContextError as e:
261
print(f"Strict verification failed: {e}")
262
```
263
264
### Custom Verification Callback
265
266
```python
267
from OpenSSL import SSL, crypto
268
269
def verify_callback(conn, cert, errno, depth, ok):
270
"""
271
Custom certificate verification callback.
272
273
Parameters:
274
- conn: SSL connection object
275
- cert: Certificate being verified
276
- errno: Error number (0 if OK)
277
- depth: Chain depth (0 for end-entity)
278
- ok: OpenSSL's verification result
279
280
Returns:
281
True to accept, False to reject
282
"""
283
subject = cert.get_subject()
284
285
print(f"Verifying: {subject.CN} at depth {depth}")
286
287
if errno == 0:
288
print(" Certificate OK")
289
return True
290
291
# Custom logic for specific errors
292
if errno == crypto.X509VerificationCodes.ERR_CERT_HAS_EXPIRED:
293
print(" Certificate expired - checking grace period")
294
# Could implement grace period logic here
295
return False
296
297
if errno == crypto.X509VerificationCodes.ERR_SELF_SIGNED_CERT_IN_CHAIN:
298
print(" Self-signed certificate in chain")
299
# Could allow self-signed for development
300
return False
301
302
print(f" Verification error: {errno}")
303
return False
304
305
# Use callback in SSL context
306
context = SSL.Context(SSL.TLS_CLIENT_METHOD)
307
context.set_verify(SSL.VERIFY_PEER, verify_callback)
308
context.set_default_verify_paths()
309
```
310
311
### Loading System Certificate Stores
312
313
```python
314
from OpenSSL import crypto
315
import os
316
317
# Create store and load system CA certificates
318
store = crypto.X509Store()
319
320
# Method 1: Load default locations
321
store.load_locations('/etc/ssl/certs/ca-certificates.crt')
322
323
# Method 2: Load from CA bundle
324
ca_bundle_paths = [
325
'/etc/ssl/certs/ca-certificates.crt', # Debian/Ubuntu
326
'/etc/ssl/ca-bundle.pem', # Red Hat/CentOS
327
'/etc/ssl/certs/ca-bundle.crt', # SUSE
328
'/usr/local/share/ca-certificates/', # Local additions
329
]
330
331
for path in ca_bundle_paths:
332
if os.path.exists(path):
333
try:
334
store.load_locations(path)
335
print(f"Loaded CA certificates from {path}")
336
break
337
except Exception as e:
338
print(f"Failed to load from {path}: {e}")
339
340
# Add custom enterprise CA
341
try:
342
with open('/usr/local/share/ca-certificates/enterprise-ca.crt', 'rb') as f:
343
enterprise_ca = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
344
store.add_cert(enterprise_ca)
345
print("Added enterprise CA certificate")
346
except FileNotFoundError:
347
print("No enterprise CA found")
348
```
349
350
### Verification Error Handling
351
352
```python
353
from OpenSSL import crypto
354
355
def detailed_verification(store, cert, chain=None):
356
"""Perform certificate verification with detailed error reporting"""
357
358
context = crypto.X509StoreContext(store, cert, chain)
359
360
try:
361
context.verify_certificate()
362
print("✓ Certificate verification successful")
363
364
# Show verification details
365
verified_chain = context.get_verified_chain()
366
print(f"✓ Verified chain length: {len(verified_chain)}")
367
368
for i, cert in enumerate(verified_chain):
369
subject = cert.get_subject()
370
print(f" [{i}] {subject.CN}")
371
372
return True
373
374
except crypto.X509StoreContextError as e:
375
print("✗ Certificate verification failed")
376
print(f" Error: {e}")
377
378
if hasattr(e, 'certificate'):
379
failed_cert = e.certificate
380
print(f" Failed certificate: {failed_cert.get_subject().CN}")
381
382
# Provide helpful error messages
383
error_messages = {
384
crypto.X509VerificationCodes.ERR_CERT_HAS_EXPIRED:
385
"Certificate has expired - check validity dates",
386
crypto.X509VerificationCodes.ERR_CERT_NOT_YET_VALID:
387
"Certificate is not yet valid - check system time",
388
crypto.X509VerificationCodes.ERR_SELF_SIGNED_CERT_IN_CHAIN:
389
"Self-signed certificate in chain - add to trust store",
390
crypto.X509VerificationCodes.ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
391
"Missing issuer certificate - add intermediate certificates",
392
}
393
394
# Check specific error codes in the errors list
395
if hasattr(e, 'errors'):
396
for error in e.errors:
397
if error in error_messages:
398
print(f" Suggestion: {error_messages[error]}")
399
400
return False
401
402
# Usage example
403
store = crypto.X509Store()
404
# ... configure store ...
405
406
with open('certificate.crt', 'rb') as f:
407
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
408
409
detailed_verification(store, cert)
410
```