Botan 3.12.0
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
10#include <botan/base64.h>
11#include <botan/ber_dec.h>
12#include <botan/certstor.h>
13#include <botan/der_enc.h>
14#include <botan/hash.h>
15#include <botan/pubkey.h>
16#include <botan/x509_ext.h>
17#include <botan/x509path.h>
18
19#if defined(BOTAN_HAS_HTTP_UTIL)
20 #include <botan/internal/http_util.h>
21#endif
22
23namespace Botan::OCSP {
24
25CertID::CertID(const X509_Certificate& issuer, const BigInt& subject_serial) : m_subject_serial(subject_serial) {
26 /*
27 In practice it seems some responders, including, notably,
28 ocsp.verisign.com, will reject anything but SHA-1 here
29 */
30 auto hash = HashFunction::create_or_throw("SHA-1");
31
33 m_issuer_key_hash = hash->process<std::vector<uint8_t>>(issuer.subject_public_key_bitstring());
34 m_issuer_dn_hash = hash->process<std::vector<uint8_t>>(issuer.raw_subject_dn());
35}
36
37bool CertID::is_id_for(const X509_Certificate& issuer, const X509_Certificate& subject) const {
38 try {
39 if(BigInt::from_bytes(subject.serial_number()) != m_subject_serial) {
40 return false;
41 }
42
43 const std::string hash_algo = m_hash_id.oid().to_formatted_string();
44
45 if(hash_algo != "SHA-1" && hash_algo != "SHA-256") {
46 return false;
47 }
48
49 auto hash = HashFunction::create_or_throw(hash_algo);
50
51 /*
52 RFC 6960 4.1.1
53 issuerNameHash is the hash of the issuer's distinguished name (DN).
54 The hash shall be calculated over the DER encoding of the issuer's name
55 field in the certificate being checked.
56 */
57 if(m_issuer_dn_hash != hash->process<std::vector<uint8_t>>(subject.raw_issuer_dn())) {
58 return false;
59 }
60
61 if(m_issuer_key_hash != hash->process<std::vector<uint8_t>>(issuer.subject_public_key_bitstring())) {
62 return false;
63 }
64 } catch(...) {
65 return false;
66 }
67
68 return true;
69}
70
73 .encode(m_hash_id)
74 .encode(m_issuer_dn_hash, ASN1_Type::OctetString)
75 .encode(m_issuer_key_hash, ASN1_Type::OctetString)
76 .encode(m_subject_serial)
77 .end_cons();
78}
79
81 /*
82 * RFC 6960 Section 4.1.1
83 *
84 * CertID ::= SEQUENCE {
85 * hashAlgorithm AlgorithmIdentifier,
86 * issuerNameHash OCTET STRING,
87 * issuerKeyHash OCTET STRING,
88 * serialNumber CertificateSerialNumber }
89 */
90 from.start_sequence()
91 .decode(m_hash_id)
92 .decode(m_issuer_dn_hash, ASN1_Type::OctetString)
93 .decode(m_issuer_key_hash, ASN1_Type::OctetString)
94 .decode(m_subject_serial)
95 .end_cons();
96}
97
99 throw Not_Implemented("SingleResponse::encode_into");
100}
101
103 /*
104 * RFC 6960 Section 4.2.1
105 *
106 * SingleResponse ::= SEQUENCE {
107 * certID CertID,
108 * certStatus CertStatus,
109 * thisUpdate GeneralizedTime,
110 * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
111 * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
112 *
113 * CertStatus ::= CHOICE {
114 * good [0] IMPLICIT NULL,
115 * revoked [1] IMPLICIT RevokedInfo,
116 * unknown [2] IMPLICIT UnknownInfo }
117 *
118 * RevokedInfo ::= SEQUENCE {
119 * revocationTime GeneralizedTime,
120 * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
121 */
123 Extensions extensions;
124
125 from.start_sequence()
126 .decode(m_certid)
128 .decode(m_thisupdate)
131 .end_cons();
132
133 const auto cert_status_class = cert_status.get_class();
134 if(cert_status_class != ASN1_Class::ContextSpecific &&
135 cert_status_class != (ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
136 throw Decoding_Error("OCSP::SingleResponse: certStatus has unexpected class tag");
137 }
138
139 // TODO: should verify the cert_status body and decode RevokedInfo
140 m_cert_status = static_cast<uint32_t>(cert_status.type());
141 if(m_cert_status > 2) {
142 throw Decoding_Error("Unknown OCSP CertStatus tag");
143 }
144
145 // We don't currently recognize any extensions here so if any are critical we should reject
146 m_has_unknown_critical_ext = !extensions.critical_extensions().empty();
147}
148
149namespace {
150
151// TODO: should this be in a header somewhere?
152void decode_optional_list(BER_Decoder& ber, ASN1_Type tag, std::vector<X509_Certificate>& output) {
153 const BER_Object obj = ber.get_next_object();
154
156 ber.push_back(obj);
157 return;
158 }
159
161 auto seq = list.start_sequence();
162 while(seq.more_items()) {
163 output.push_back([&] {
164 X509_Certificate cert;
165 cert.decode_from(seq);
166 return cert;
167 }());
168 }
169 seq.end_cons();
170}
171
172} // namespace
173
174Request::Request(const X509_Certificate& issuer_cert, const X509_Certificate& subject_cert) :
175 m_issuer(issuer_cert), m_certid(m_issuer, BigInt::from_bytes(subject_cert.serial_number())) {
176 if(subject_cert.issuer_dn() != issuer_cert.subject_dn()) {
177 throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
178 }
179}
180
181Request::Request(const X509_Certificate& issuer_cert, const BigInt& subject_serial) :
182 m_issuer(issuer_cert), m_certid(m_issuer, subject_serial) {}
183
184std::vector<uint8_t> Request::BER_encode() const {
185 /*
186 * RFC 6960 Section 4.1.1
187 *
188 * OCSPRequest ::= SEQUENCE {
189 * tbsRequest TBSRequest,
190 * optionalSignature [0] EXPLICIT Signature OPTIONAL }
191 *
192 * TBSRequest ::= SEQUENCE {
193 * version [0] EXPLICIT Version DEFAULT v1,
194 * requestList SEQUENCE OF Request }
195 *
196 * Request ::= SEQUENCE {
197 * reqCert CertID }
198 */
199 std::vector<uint8_t> output;
200 DER_Encoder(output)
204 .encode(static_cast<size_t>(0)) // version #
205 .end_explicit()
208 .encode(m_certid)
209 .end_cons()
210 .end_cons()
211 .end_cons()
212 .end_cons();
213
214 return output;
215}
216
217std::string Request::base64_encode() const {
219}
220
223
224Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
225 m_response_bits(response_bits, response_bits + response_bits_len) {
226 /*
227 * RFC 6960 Section 4.2.1
228 *
229 * OCSPResponse ::= SEQUENCE {
230 * responseStatus OCSPResponseStatus,
231 * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
232 *
233 * OCSPResponseStatus ::= ENUMERATED { ... }
234 *
235 * ResponseBytes ::= SEQUENCE {
236 * responseType OBJECT IDENTIFIER,
237 * response OCTET STRING }
238 */
239 BER_Decoder outer_decoder(m_response_bits, BER_Decoder::Limits::DER());
240 BER_Decoder response_outer = outer_decoder.start_sequence();
241
242 size_t resp_status = 0;
243
244 response_outer.decode(resp_status, ASN1_Type::Enumerated, ASN1_Class::Universal);
245
246 /*
247 RFC 6960 4.2.1
248
249 OCSPResponseStatus ::= ENUMERATED {
250 successful (0), -- Response has valid confirmations
251 malformedRequest (1), -- Illegal confirmation request
252 internalError (2), -- Internal error in issuer
253 tryLater (3), -- Try again later
254 -- (4) is not used
255 sigRequired (5), -- Must sign the request
256 unauthorized (6) -- Request unauthorized
257 }
258 */
259 if(resp_status >= 7) {
260 throw Decoding_Error("Unknown OCSPResponseStatus code");
261 }
262
263 m_status = static_cast<Response_Status_Code>(resp_status);
264
265 if(m_status != Response_Status_Code::Successful) {
266 return;
267 }
268
269 if(response_outer.more_items()) {
270 BER_Decoder response_bytes_ctx = response_outer.start_context_specific(0);
271 BER_Decoder response_bytes = response_bytes_ctx.start_sequence();
272
273 response_bytes.decode_and_check(OID({1, 3, 6, 1, 5, 5, 7, 48, 1, 1}), "Unknown response type in OCSP response");
274
275 /*
276 * RFC 6960 Section 4.2.1
277 *
278 * BasicOCSPResponse ::= SEQUENCE {
279 * tbsResponseData ResponseData,
280 * signatureAlgorithm AlgorithmIdentifier,
281 * signature BIT STRING,
282 * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
283 */
284 BER_Decoder basic_response_decoder(response_bytes.get_next_octet_string(), BER_Decoder::Limits::DER());
285 BER_Decoder basicresponse = basic_response_decoder.start_sequence();
286
287 basicresponse.start_sequence()
288 .raw_bytes(m_tbs_bits)
289 .end_cons()
290 .decode(m_sig_algo)
291 .decode(m_signature, ASN1_Type::BitString);
292 decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
293
294 basicresponse.verify_end();
295 basic_response_decoder.verify_end();
296
297 /*
298 * RFC 6960 Section 4.2.1
299 *
300 * ResponseData ::= SEQUENCE {
301 * version [0] EXPLICIT Version DEFAULT v1,
302 * responderID ResponderID,
303 * producedAt GeneralizedTime,
304 * responses SEQUENCE OF SingleResponse,
305 * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
306 *
307 * ResponderID ::= CHOICE {
308 * byName [1] Name,
309 * byKey [2] KeyHash }
310 */
311 size_t responsedata_version = 0;
312 Extensions extensions;
313
316
318
321
322 .decode(m_produced_at)
323
324 .decode_list(m_responses)
325
327
328 .verify_end();
329
330 const bool has_signer = !m_signer_name.empty();
331 const bool has_key_hash = !m_key_hash.empty();
332
333 if(has_signer && has_key_hash) {
334 throw Decoding_Error("OCSP response includes both byName and byKey in responderID field");
335 }
336 if(!has_signer && !has_key_hash) {
337 throw Decoding_Error("OCSP response contains neither byName nor byKey in responderID field");
338 }
339 if(has_key_hash && m_key_hash.size() != 20) {
340 // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
341 throw Decoding_Error("OCSP response contains a byKey with invalid length");
342 }
343
344 response_bytes.verify_end();
345 response_bytes_ctx.verify_end();
346
347 // We don't currently recognize any extensions here so if any are critical we should reject
348 m_has_unknown_critical_ext = !extensions.critical_extensions().empty();
349 }
350
351 response_outer.verify_end();
352 outer_decoder.verify_end();
353
354 if(m_has_unknown_critical_ext == false) {
355 // Check all of the SingleResponse extensions
356 for(const auto& sr : m_responses) {
357 if(sr.has_unknown_critical_extension()) {
358 m_has_unknown_critical_ext = true;
359 break;
360 }
361 }
362 }
363}
364
365bool Response::is_issued_by(const X509_Certificate& candidate) const {
366 if(!m_signer_name.empty()) {
367 return (candidate.subject_dn() == m_signer_name);
368 }
369
370 if(!m_key_hash.empty()) {
371 return (candidate.subject_public_key_bitstring_sha1() == m_key_hash);
372 }
373
374 return false;
375}
376
378 const Path_Validation_Restrictions restrictions;
379
380 return this->verify_signature(issuer, restrictions);
381}
382
384 const Path_Validation_Restrictions& restrictions) const {
385 if(m_dummy_response_status) {
386 return m_dummy_response_status.value();
387 }
388
389 if(m_signer_name.empty() && m_key_hash.empty()) {
391 }
392
393 if(!is_issued_by(issuer)) {
395 }
396
397 try {
398 auto pub_key = issuer.subject_public_key();
399
400 PK_Verifier verifier(*pub_key, m_sig_algo);
401
402 const bool valid_signature = verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature);
403
404 if(valid_signature == false) {
406 }
407
408 if(m_has_unknown_critical_ext) {
410 }
411
412 const auto& trusted_hashes = restrictions.trusted_hashes();
413 if(!trusted_hashes.empty() && !trusted_hashes.contains(verifier.hash_function())) {
415 }
416
417 if(pub_key->estimated_strength() < restrictions.minimum_key_strength()) {
419 }
420
422 } catch(Exception&) {
424 }
425}
426
427std::optional<X509_Certificate> Response::find_signing_certificate(
428 const X509_Certificate& issuer_certificate, const Certificate_Store* trusted_ocsp_responders) const {
429 using namespace std::placeholders;
430
431 // Check whether the CA issuing the certificate in question also signed this
432 if(is_issued_by(issuer_certificate)) {
433 return issuer_certificate;
434 }
435
436 // Then try to find a delegated responder certificate in the stapled certs
437 for(const auto& cert : m_certs) {
438 if(this->is_issued_by(cert)) {
439 return cert;
440 }
441 }
442
443 // Last resort: check the additionally provides trusted OCSP responders
444 if(trusted_ocsp_responders != nullptr) {
445 if(!m_key_hash.empty()) {
446 auto signing_cert = trusted_ocsp_responders->find_cert_by_pubkey_sha1(m_key_hash);
447 if(signing_cert) {
448 return signing_cert;
449 }
450 }
451
452 if(!m_signer_name.empty()) {
453 auto signing_cert = trusted_ocsp_responders->find_cert(m_signer_name, {});
454 if(signing_cert) {
455 return signing_cert;
456 }
457 }
458 }
459
460 return std::nullopt;
461}
462
464 const X509_Certificate& subject,
465 std::chrono::system_clock::time_point ref_time,
466 std::chrono::seconds max_age) const {
467 if(m_dummy_response_status) {
468 return m_dummy_response_status.value();
469 }
470
471 for(const auto& response : m_responses) {
472 if(response.certid().is_id_for(issuer, subject)) {
473 const X509_Time x509_ref_time(ref_time);
474
475 /*
476 * We check certificate status prior to checking expiration, since otherwise it's
477 * possible to take an OCSP response indicating revocation, wait for it to expire,
478 * and then staple it. If such a response was reported as "expired" rather than
479 * "revoked" it's easy to dismiss as a clock issue or other misconfiguration.
480 */
481
482 if(response.cert_status() == 1) {
484 }
485
486 try {
487 if(response.this_update() > x509_ref_time) {
489 }
490
491 if(response.next_update().time_is_set()) {
492 if(x509_ref_time > response.next_update()) {
494 }
495 } else if(max_age > std::chrono::seconds::zero() &&
496 ref_time - response.this_update().to_std_timepoint() > max_age) {
498 }
499 } catch(Exception&) {
500 // This can occur if eg the OCSP time is not representable by the system clock
502 }
503
504 if(response.cert_status() == 0) {
506 } else {
508 }
509 }
510 }
511
513}
514
515#if defined(BOTAN_HAS_HTTP_UTIL)
516
517Response online_check(const X509_Certificate& issuer,
518 const BigInt& subject_serial,
519 std::string_view ocsp_responder,
520 std::chrono::milliseconds timeout) {
521 if(ocsp_responder.empty()) {
522 throw Invalid_Argument("No OCSP responder specified");
523 }
524
525 const OCSP::Request req(issuer, subject_serial);
526
527 auto http = HTTP::POST_sync(ocsp_responder, "application/ocsp-request", req.BER_encode(), 1, timeout);
528
529 http.throw_unless_ok();
530
531 // Check the MIME type?
532
533 return OCSP::Response(http.body());
534}
535
536Response online_check(const X509_Certificate& issuer,
537 const X509_Certificate& subject,
538 std::chrono::milliseconds timeout) {
539 if(subject.issuer_dn() != issuer.subject_dn()) {
540 throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
541 }
542
543 return online_check(issuer, BigInt::from_bytes(subject.serial_number()), subject.ocsp_responder(), timeout);
544}
545
546#endif
547
548} // namespace Botan::OCSP
static Limits DER()
Definition ber_dec.h:35
void push_back(const BER_Object &obj)
Definition ber_dec.cpp:500
BER_Object get_next_object()
Definition ber_dec.cpp:426
BER_Decoder & decode(bool &out)
Definition ber_dec.h:220
bool more_items() const
Definition ber_dec.cpp:371
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
Definition ber_dec.h:203
std::vector< uint8_t > get_next_octet_string()
Definition ber_dec.h:232
BER_Decoder & verify_end()
Definition ber_dec.cpp:381
BER_Decoder & end_cons()
Definition ber_dec.cpp:524
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Type type_tag=ASN1_Type::Sequence, ASN1_Class class_tag=ASN1_Class::Universal)
Definition ber_dec.h:430
BER_Decoder start_sequence()
Definition ber_dec.h:160
BER_Decoder start_context_specific(uint32_t tag)
Definition ber_dec.h:164
BER_Decoder & decode_optional(T &out, ASN1_Type type_tag, ASN1_Class class_tag, const T &default_value=T())
Definition ber_dec.h:285
BER_Decoder & decode_and_check(const T &expected, std::string_view error_msg)
Definition ber_dec.h:314
BER_Decoder & decode_optional_string(std::vector< uint8_t, Alloc > &out, ASN1_Type real_type, uint32_t expected_tag, ASN1_Class class_tag=ASN1_Class::ContextSpecific)
Definition ber_dec.h:329
BER_Decoder & get_next(BER_Object &ber)
Definition ber_dec.h:106
bool is_a(ASN1_Type type_tag, ASN1_Class class_tag) const
Definition asn1_obj.cpp:66
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:83
virtual std::optional< X509_Certificate > find_cert_by_pubkey_sha1(const std::vector< uint8_t > &key_hash) const =0
virtual std::optional< X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const
Definition certstor.cpp:38
DER_Encoder & end_explicit()
Definition der_enc.cpp:195
DER_Encoder & start_explicit(uint16_t type_tag)
Definition der_enc.cpp:188
DER_Encoder & start_sequence()
Definition der_enc.h:67
DER_Encoder & end_cons()
Definition der_enc.cpp:173
DER_Encoder & encode(bool b)
Definition der_enc.cpp:245
std::vector< OID > critical_extensions() const
Definition x509_ext.cpp:109
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:308
void decode_from(BER_Decoder &from) override
Definition ocsp.cpp:80
void encode_into(DER_Encoder &to) const override
Definition ocsp.cpp:71
bool is_id_for(const X509_Certificate &issuer, const X509_Certificate &subject) const
Definition ocsp.cpp:37
std::string base64_encode() const
Definition ocsp.cpp:217
Request(const X509_Certificate &issuer_cert, const X509_Certificate &subject_cert)
Definition ocsp.cpp:174
std::vector< uint8_t > BER_encode() const
Definition ocsp.cpp:184
BOTAN_FUTURE_EXPLICIT Response(Certificate_Status_Code status)
Definition ocsp.cpp:221
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:463
Response_Status_Code status() const
Definition ocsp.h:201
std::optional< X509_Certificate > find_signing_certificate(const X509_Certificate &issuer_certificate, const Certificate_Store *trusted_ocsp_responders=nullptr) const
Definition ocsp.cpp:427
Certificate_Status_Code verify_signature(const X509_Certificate &signing_certificate) const
Definition ocsp.cpp:377
void decode_from(BER_Decoder &from) override
Definition ocsp.cpp:102
size_t cert_status() const
Definition ocsp.h:52
void encode_into(DER_Encoder &to) const override
Definition ocsp.cpp:98
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition pubkey.cpp:411
std::string hash_function() const
Definition pubkey.cpp:400
const std::set< std::string > & trusted_hashes() const
Definition x509path.h:119
const std::vector< uint8_t > & serial_number() const
Definition x509cert.cpp:406
const X509_DN & subject_dn() const
Definition x509cert.cpp:418
const std::vector< uint8_t > & raw_subject_dn() const
Definition x509cert.cpp:426
const std::vector< uint8_t > & subject_public_key_bitstring_sha1() const
Definition x509cert.cpp:390
const X509_DN & issuer_dn() const
Definition x509cert.cpp:414
const std::vector< uint8_t > & raw_issuer_dn() const
Definition x509cert.cpp:422
const std::vector< uint8_t > & subject_public_key_bitstring() const
Definition x509cert.cpp:386
std::unique_ptr< Public_Key > subject_public_key() const
Definition x509cert.cpp:659
bool empty() const
Definition pkix_types.h:88
void decode_from(BER_Decoder &from) override
Definition x509_obj.cpp:93
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition asn1_obj.cpp:177
Response POST_sync(std::string_view url, std::string_view content_type, const std::vector< uint8_t > &body, size_t allowable_redirects, std::chrono::milliseconds timeout)
Response_Status_Code
Definition ocsp.h:121
ASN1_Time X509_Time
Definition asn1_obj.h:23
ASN1_Type
Definition asn1_obj.h:43
Certificate_Status_Code
Definition pkix_enums.h:20
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition base64.cpp:159