Botan 2.19.5 Crypto and TLS for C&

ocsp.cpp
Go to the documentation of this file.
1/*
2* OCSP
3* (C) 2012,2013 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/ocsp.h>
9#include <botan/certstor.h>
10#include <botan/der_enc.h>
11#include <botan/ber_dec.h>
12#include <botan/x509_ext.h>
13#include <botan/oids.h>
14#include <botan/base64.h>
15#include <botan/pubkey.h>
16#include <botan/parsing.h>
17
18#if defined(BOTAN_HAS_HTTP_UTIL)
19 #include <botan/http_util.h>
20#endif
21
22 namespace Botan {
23
24 namespace OCSP {
25
26 namespace {
27
28// TODO: should this be in a header somewhere?
29 void decode_optional_list(BER_Decoder& ber,
30 ASN1_Tag tag,
31 std::vector<X509_Certificate>& output)
32 {
33 BER_Object obj = ber.get_next_object();
34
35 if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false)
36 {
37 ber.push_back(obj);
38 return;
39 }
40
41 BER_Decoder list(obj);
42
43 while(list.more_items())
44 {
45 BER_Object certbits = list.get_next_object();
46 X509_Certificate cert(certbits.bits(), certbits.length());
47 output.push_back(std::move(cert));
48 }
49 }
50
51}
52
53 Request::Request(const X509_Certificate& issuer_cert,
54 const X509_Certificate& subject_cert) :
55 m_issuer(issuer_cert),
56 m_certid(m_issuer, BigInt::decode(subject_cert.serial_number()))
57 {
58 if(subject_cert.issuer_dn() != issuer_cert.subject_dn())
59 throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
60 }
61
62 Request::Request(const X509_Certificate& issuer_cert,
63 const BigInt& subject_serial) :
64 m_issuer(issuer_cert),
65 m_certid(m_issuer, subject_serial)
66 {
67 }
68
69std::vector<uint8_t> Request::BER_encode() const
70 {
71 std::vector<uint8_t> output;
72 DER_Encoder(output).start_cons(SEQUENCE)
73 .start_cons(SEQUENCE)
74 .start_explicit(0)
75 .encode(static_cast<size_t>(0)) // version #
76 .end_explicit()
77 .start_cons(SEQUENCE)
78 .start_cons(SEQUENCE)
79 .encode(m_certid)
80 .end_cons()
81 .end_cons()
82 .end_cons()
83 .end_cons();
84
85 return output;
86 }
87
88std::string Request::base64_encode() const
89 {
90 return Botan::base64_encode(BER_encode());
91 }
92
93 Response::Response(Certificate_Status_Code status)
94 {
95 m_status = Response_Status_Code::Successful;
96 m_dummy_response_status = status;
97 }
98
99 Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
100 m_response_bits(response_bits, response_bits + response_bits_len)
101 {
102 m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID;
103
104 BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE);
105
106 size_t resp_status = 0;
107
108 response_outer.decode(resp_status, ENUMERATED, UNIVERSAL);
109
110 m_status = static_cast<Response_Status_Code>(resp_status);
111
112 if(m_status != Response_Status_Code::Successful)
113 { return; }
114
115 if(response_outer.more_items())
116 {
117 BER_Decoder response_bytes =
118 response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE);
119
120 response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
121 "Unknown response type in OCSP response");
122
123 BER_Decoder basicresponse =
124 BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE);
125
126 basicresponse.start_cons(SEQUENCE)
127 .raw_bytes(m_tbs_bits)
128 .end_cons()
129 .decode(m_sig_algo)
130 .decode(m_signature, BIT_STRING);
131 decode_optional_list(basicresponse, ASN1_Tag(0), m_certs);
132
133 size_t responsedata_version = 0;
134 Extensions extensions;
135
136 BER_Decoder(m_tbs_bits)
137 .decode_optional(responsedata_version, ASN1_Tag(0),
138 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
139
140 .decode_optional(m_signer_name, ASN1_Tag(1),
141 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
142
143 .decode_optional_string(m_key_hash, OCTET_STRING, 2,
144 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
145
146 .decode(m_produced_at)
147
148 .decode_list(m_responses)
149
150 .decode_optional(extensions, ASN1_Tag(1),
151 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
152 }
153
154 response_outer.end_cons();
155 }
156
157 Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
158 {
159 if (m_responses.empty())
160 return m_dummy_response_status;
161
162 try
163 {
164 std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());
165
166 const std::vector<std::string> sig_info =
167 split_on(m_sig_algo.get_oid().to_formatted_string(), '/');
168
169 if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
170 return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
171
172 std::string padding = sig_info[1];
173 const Signature_Format format = pub_key->default_x509_signature_format();
174
175 PK_Verifier verifier(*pub_key, padding, format);
176
177 if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
178 return Certificate_Status_Code::OCSP_SIGNATURE_OK;
179 else
180 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
181 }
182 catch(Exception&)
183 {
184 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
185 }
186 }
187
188 Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
189 const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
190 {
191 if (m_responses.empty())
192 return m_dummy_response_status;
193
194 std::shared_ptr<const X509_Certificate> signing_cert;
195
196 for(size_t i = 0; i != trusted_roots.size(); ++i)
197 {
198 if(m_signer_name.empty() && m_key_hash.empty())
199 return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
200
201 if(!m_signer_name.empty())
202 {
203 signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<uint8_t>());
204 if(signing_cert)
205 {
206 break;
207 }
208 }
209
210 if(m_key_hash.size() > 0)
211 {
212 signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash);
213 if(signing_cert)
214 {
215 break;
216 }
217 }
218 }
219
220 if(!signing_cert && ee_cert_path.size() > 1)
221 {
222 // End entity cert is not allowed to sign their own OCSP request :)
223 for(size_t i = 1; i < ee_cert_path.size(); ++i)
224 {
225 // Check all CA certificates in the (assumed validated) EE cert path
226 if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name)
227 {
228 signing_cert = ee_cert_path[i];
229 break;
230 }
231
232 if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash)
233 {
234 signing_cert = ee_cert_path[i];
235 break;
236 }
237 }
238 }
239
240 if(!signing_cert && m_certs.size() > 0)
241 {
242 for(size_t i = 0; i < m_certs.size(); ++i)
243 {
244 if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name)
245 {
246 signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
247 break;
248 }
249
250 if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash)
251 {
252 signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
253 break;
254 }
255 }
256
257 // RFC 6960 4.2.2.2
258 // OCSP signing delegation SHALL be designated by the inclusion of
259 // id-kp-OCSPSigning in an extended key usage certificate extension
260 // included in the OCSP response signer's certificate. This certificate
261 // MUST be issued directly by the CA that is identified in the request.
262 //
263 // The CA SHOULD use the same issuing key to issue a delegation
264 // certificate as that used to sign the certificate being checked for
265 // revocation. Systems relying on OCSP responses MUST recognize a
266 // delegation certificate as being issued by the CA that issued the
267 // certificate in question only if the delegation certificate and the
268 // certificate being checked for revocation were signed by the same key.
269 //
270 // I.e. it is safe to assume that the certificate's issuer also signed the
271 // responder's certificate.
272 //
273 // Note: The 'SHOULD' in the second paragraph above allows for backward
274 // compatibility to RFC 2560 that is "strongly discouraged". This
275 // implementation explicitly _does not_ implement this backward
276 // compatibility.
277 if(signing_cert)
278 {
279 const auto issuer =
280 Certificate_Store_In_Memory(ee_cert_path)
281 .find_cert(signing_cert->issuer_dn(), signing_cert->authority_key_id());
282
283 // User did not provide the certificate path to verify the delegation
284 if(!issuer)
285 {
286 return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
287 }
288
289 if(!issuer->is_CA_cert())
290 {
291 return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
292 }
293
294 // Sub-optimal fix for CVE-2022-43705 found in Botan 2.19.2 and older.
295 //
296 // This certificate validation is incomplete. Missing checks:
297 // * validity check against the reference time
298 // * revocation status check of the responder certificate
299 // * certificate extension validations
300 // * ... potentially more
301 //
302 // A more comprehensive validation will be introduced with Botan 3.0
303 try
304 {
305 const auto issuer_pubkey = issuer->load_subject_public_key();
306 const auto sig = signing_cert->verify_signature(*issuer_pubkey);
307
308 if(sig != Certificate_Status_Code::VERIFIED)
309 {
310 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
311 }
312
313 if(!signing_cert->has_ex_constraint(OID::from_string("PKIX.OCSPSigning")))
314 {
315 return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;
316 }
317 }
318 catch(const Exception& ex)
319 {
320 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
321 }
322 }
323 }
324
325 if(!signing_cert)
326 return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
327
328 if(!signing_cert->allowed_usage(CRL_SIGN) &&
329 !signing_cert->allowed_extended_usage("PKIX.OCSPSigning"))
330 {
331 return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;
332 }
333
334 return this->verify_signature(*signing_cert);
335 }
336
337 Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
338 const X509_Certificate& subject,
339 std::chrono::system_clock::time_point ref_time,
340 std::chrono::seconds max_age) const
341 {
342 if(m_responses.empty())
343 { return m_dummy_response_status; }
344
345 for(const auto& response : m_responses)
346 {
347 if(response.certid().is_id_for(issuer, subject))
348 {
349 X509_Time x509_ref_time(ref_time);
350
351 if(response.cert_status() == 1)
352 { return Certificate_Status_Code::CERT_IS_REVOKED; }
353
354 if(response.this_update() > x509_ref_time)
355 { return Certificate_Status_Code::OCSP_NOT_YET_VALID; }
356
357 if(response.next_update().time_is_set())
358 {
359 if(x509_ref_time > response.next_update())
360 { return Certificate_Status_Code::OCSP_HAS_EXPIRED; }
361 }
362 else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age)
363 { return Certificate_Status_Code::OCSP_IS_TOO_OLD; }
364
365 if(response.cert_status() == 0)
366 { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; }
367 else
368 { return Certificate_Status_Code::OCSP_BAD_STATUS; }
369 }
370 }
371
372 return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
373 }
374
375#if defined(BOTAN_HAS_HTTP_UTIL)
376
377 Response online_check(const X509_Certificate& issuer,
378 const BigInt& subject_serial,
379 const std::string& ocsp_responder,
380 Certificate_Store* trusted_roots,
381 std::chrono::milliseconds timeout)
382 {
383 if(ocsp_responder.empty())
384 throw Invalid_Argument("No OCSP responder specified");
385
386 OCSP::Request req(issuer, subject_serial);
387
388 auto http = HTTP::POST_sync(ocsp_responder,
389 "application/ocsp-request",
390 req.BER_encode(),
391 1,
392 timeout);
393
394 http.throw_unless_ok();
395
396 // Check the MIME type?
397
398 OCSP::Response response(http.body());
399
400 std::vector<Certificate_Store*> trusted_roots_vec;
401 trusted_roots_vec.push_back(trusted_roots);
402
403 if(trusted_roots)
404 response.check_signature(trusted_roots_vec);
405
406 return response;
407 }
408
409
410Response online_check(const X509_Certificate& issuer,
411 const X509_Certificate& subject,
412 Certificate_Store* trusted_roots,
413 std::chrono::milliseconds timeout)
414 {
415 if(subject.issuer_dn() != issuer.subject_dn())
416 throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
417
418 return online_check(issuer,
419 BigInt::decode(subject.serial_number()),
420 subject.ocsp_responder(),
421 trusted_roots,
422 timeout);
423 }
424
425#endif
426
427}
428
429}
Botan::ASN1_Time
Definition: asn1_obj.h:328
Botan::AlgorithmIdentifier::get_oid
const OID & get_oid() const
Definition: asn1_obj.h:445
Botan::BER_Decoder
Definition: ber_dec.h:22
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Botan::BER_Decoder::decode_list
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Tag type_tag=SEQUENCE, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.h:398
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
Botan::BER_Decoder::more_items
bool more_items() const
Definition: ber_dec.cpp:198
Botan::BER_Decoder::decode_optional_string
BER_Decoder & decode_optional_string(std::vector< uint8_t, Alloc > &out, ASN1_Tag real_type, uint16_t type_no, ASN1_Tag class_tag=CONTEXT_SPECIFIC)
Definition: ber_dec.h:293
Botan::BER_Decoder::decode_and_check
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:277
Botan::BER_Decoder::raw_bytes
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
Definition: ber_dec.h:156
Botan::BER_Decoder::get_next_octet_string
std::vector< uint8_t > get_next_octet_string()
Definition: ber_dec.h:191
Botan::BER_Decoder::decode_optional
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:337
Botan::BER_Decoder::end_cons
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
Botan::BigInt
Definition: bigint.h:25
Botan::BigInt::decode
static BigInt decode(const uint8_t buf[], size_t length)
Definition: bigint.h:817
Botan::Certificate_Store_In_Memory
Definition: certstor.h:85
Botan::Certificate_Store_In_Memory::find_cert
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor.cpp:65
Botan::Certificate_Store
Definition: certstor.h:20
Botan::DER_Encoder
Definition: der_enc.h:23
Botan::DER_Encoder::end_explicit
DER_Encoder & end_explicit()
Definition: der_enc.cpp:220
Botan::DER_Encoder::start_explicit
DER_Encoder & start_explicit(uint16_t type_tag)
Definition: der_enc.cpp:206
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
Botan::Exception
Definition: exceptn.h:86
Botan::Extensions
Definition: pkix_types.h:436
Botan::Invalid_Argument
Definition: exceptn.h:137
Botan::OCSP::Request
Definition: ocsp.h:72
Botan::OCSP::Request::base64_encode
std::string base64_encode() const
Definition: ocsp.cpp:88
Botan::OCSP::Request::Request
Request(const X509_Certificate &issuer_cert, const X509_Certificate &subject_cert)
Definition: ocsp.cpp:53
Botan::OCSP::Request::BER_encode
std::vector< uint8_t > BER_encode() const
Definition: ocsp.cpp:69
Botan::OCSP::Response
Definition: ocsp.h:132
Botan::OCSP::Response::status_for
Certificate_Status_Code status_for(const X509_Certificate &issuer, const X509_Certificate &subject, std::chrono::system_clock::time_point ref_time=std::chrono::system_clock::now(), std::chrono::seconds max_age=std::chrono::seconds::zero()) const
Definition: ocsp.cpp:337
Botan::OCSP::Response::status
Response_Status_Code status() const
Definition: ocsp.h:183
Botan::OCSP::Response::check_signature
Certificate_Status_Code check_signature(const std::vector< Certificate_Store * > &trust_roots, const std::vector< std::shared_ptr< const X509_Certificate > > &cert_path={}) const
Definition: ocsp.cpp:188
Botan::OCSP::Response::Response
Response()=default
Botan::OCSP::Response::verify_signature
Certificate_Status_Code verify_signature(const X509_Certificate &issuer) const
Definition: ocsp.cpp:157
Botan::OID
Definition: asn1_obj.h:194
Botan::OID::to_formatted_string
std::string to_formatted_string() const
Definition: asn1_oid.cpp:111
Botan::OID::from_string
static OID from_string(const std::string &str)
Definition: asn1_oid.cpp:62
Botan::PK_Verifier
Definition: pubkey.h:299
Botan::PK_Verifier::verify_message
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition: pubkey.cpp:331
Botan::X509_Certificate
Definition: x509cert.h:38
Botan::X509_Certificate::serial_number
const std::vector< uint8_t > & serial_number() const
Definition: x509cert.cpp:461
Botan::X509_Certificate::subject_dn
const X509_DN & subject_dn() const
Definition: x509cert.cpp:477
Botan::X509_Certificate::issuer_dn
const X509_DN & issuer_dn() const
Definition: x509cert.cpp:472
Botan::X509_Certificate::ocsp_responder
std::string ocsp_responder() const
Definition: x509cert.cpp:614
Botan::X509_Certificate::subject_public_key
Public_Key * subject_public_key() const
Definition: x509cert.cpp:715
Botan::X509_DN::empty
bool empty() const
Definition: pkix_types.h:70
Botan::ASN1::put_in_sequence
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition: asn1_obj.cpp:195
Botan::HTTP::POST_sync
Response POST_sync(const std::string &url, const std::string &content_type, const std::vector< uint8_t > &body, size_t allowable_redirects, std::chrono::milliseconds timeout)
Definition: http_util.cpp:256
Botan::OCSP::Response_Status_Code
Response_Status_Code
Definition: ocsp.h:117
Botan::OCSP::Response_Status_Code::Successful
@ Successful
Botan::PEM_Code::decode
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Botan
Definition: alg_id.cpp:13
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
Botan::base64_encode
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:185
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:25
Botan::CONSTRUCTED
@ CONSTRUCTED
Definition: asn1_obj.h:30
Botan::BIT_STRING
@ BIT_STRING
Definition: asn1_obj.h:37
Botan::SEQUENCE
@ SEQUENCE
Definition: asn1_obj.h:42
Botan::CONTEXT_SPECIFIC
@ CONTEXT_SPECIFIC
Definition: asn1_obj.h:28
Botan::ENUMERATED
@ ENUMERATED
Definition: asn1_obj.h:41
Botan::OCTET_STRING
@ OCTET_STRING
Definition: asn1_obj.h:38
Botan::UNIVERSAL
@ UNIVERSAL
Definition: asn1_obj.h:26
Botan::Signature_Format
Signature_Format
Definition: pk_keys.h:23
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: pkix_enums.h:17
Botan::Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE
@ OCSP_RESPONSE_MISSING_KEYUSAGE
Botan::Certificate_Status_Code::OCSP_BAD_STATUS
@ OCSP_BAD_STATUS
Botan::Certificate_Status_Code::VERIFIED
@ VERIFIED
Botan::Certificate_Status_Code::OCSP_CERT_NOT_LISTED
@ OCSP_CERT_NOT_LISTED
Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID
@ OCSP_RESPONSE_INVALID
Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED
@ OCSP_HAS_EXPIRED
Botan::Certificate_Status_Code::CERT_IS_REVOKED
@ CERT_IS_REVOKED
Botan::Certificate_Status_Code::OCSP_SIGNATURE_ERROR
@ OCSP_SIGNATURE_ERROR
Botan::Certificate_Status_Code::OCSP_IS_TOO_OLD
@ OCSP_IS_TOO_OLD
Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD
@ OCSP_RESPONSE_GOOD
Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK
@ OCSP_SIGNATURE_OK
Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID
@ OCSP_NOT_YET_VALID
Botan::Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND
@ OCSP_ISSUER_NOT_FOUND
Botan::CRL_SIGN
@ CRL_SIGN
Definition: pkix_enums.h:114