Botan 3.13.0
Crypto and TLS for C&
Botan::OCSP::Response Class Referencefinal

#include <ocsp.h>

Public Member Functions

const std::vector< X509_Certificate > & certificates () const
std::optional< Certificate_Status_Codedummy_status () const
std::optional< X509_Certificatefind_signing_certificate (const X509_Certificate &issuer_certificate, const Certificate_Store *trusted_ocsp_responders=nullptr) const
const X509_Timeproduced_at () const
const std::vector< uint8_t > & raw_bits () const
BOTAN_FUTURE_EXPLICIT Response (Certificate_Status_Code status)
BOTAN_FUTURE_EXPLICIT Response (const std::vector< uint8_t > &response_bits)
 Response (const uint8_t response_bits[], size_t response_bits_len)
const std::vector< SingleResponse > & responses () const
const std::vector< uint8_t > & signer_key_hash () const
const X509_DNsigner_name () const
Response_Status_Code status () const
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
Certificate_Status_Code verify_signature (const X509_Certificate &signing_certificate) const
Certificate_Status_Code verify_signature (const X509_Certificate &signing_certificate, const Path_Validation_Restrictions &restrictions) const

Static Public Member Functions

static Response dummy_no_revocation_url_response ()
static Response dummy_server_not_available_response ()

Detailed Description

OCSP response.

Note this class is only usable as an OCSP client

Definition at line 172 of file ocsp.h.

Constructor & Destructor Documentation

◆ Response() [1/3]

Botan::OCSP::Response::Response ( Certificate_Status_Code status)

Create a fake OCSP response from a given status code.

Parameters
statusthe status code the check functions will return

TODO(Botan4) make this constructor private

Definition at line 372 of file ocsp.cpp.

372 :
373 m_status(Response_Status_Code::Successful), m_dummy_response_status(status) {}
Response_Status_Code status() const
Definition ocsp.h:240

References status().

Referenced by dummy_no_revocation_url_response(), dummy_server_not_available_response(), and Response().

◆ Response() [2/3]

BOTAN_FUTURE_EXPLICIT Botan::OCSP::Response::Response ( const std::vector< uint8_t > & response_bits)
inline

Parses an OCSP response.

Parameters
response_bitsresponse bits received

Definition at line 186 of file ocsp.h.

186 :
187 Response(response_bits.data(), response_bits.size()) {}
BOTAN_FUTURE_EXPLICIT Response(Certificate_Status_Code status)
Definition ocsp.cpp:372

References BOTAN_FUTURE_EXPLICIT, and Response().

◆ Response() [3/3]

Botan::OCSP::Response::Response ( const uint8_t response_bits[],
size_t response_bits_len )

Parses an OCSP response.

Parameters
response_bitsresponse bits received
response_bits_lenlength of response in bytes

Definition at line 375 of file ocsp.cpp.

375 :
376 m_response_bits(response_bits, response_bits + response_bits_len) {
377 /*
378 * RFC 6960 Section 4.2.1
379 *
380 * OCSPResponse ::= SEQUENCE {
381 * responseStatus OCSPResponseStatus,
382 * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
383 *
384 * OCSPResponseStatus ::= ENUMERATED { ... }
385 *
386 * ResponseBytes ::= SEQUENCE {
387 * responseType OBJECT IDENTIFIER,
388 * response OCTET STRING }
389 */
390 BER_Decoder outer_decoder(m_response_bits, BER_Decoder::Limits::DER());
391 BER_Decoder response_outer = outer_decoder.start_sequence();
392
393 size_t resp_status = 0;
394
395 response_outer.decode(resp_status, ASN1_Type::Enumerated, ASN1_Class::Universal);
396
397 /*
398 RFC 6960 4.2.1
399
400 OCSPResponseStatus ::= ENUMERATED {
401 successful (0), -- Response has valid confirmations
402 malformedRequest (1), -- Illegal confirmation request
403 internalError (2), -- Internal error in issuer
404 tryLater (3), -- Try again later
405 -- (4) is not used
406 sigRequired (5), -- Must sign the request
407 unauthorized (6) -- Request unauthorized
408 }
409 */
410 if(resp_status == 4 || resp_status >= 7) {
411 throw Decoding_Error("Unknown OCSPResponseStatus code");
412 }
413
414 m_status = static_cast<Response_Status_Code>(resp_status);
415
416 /*
417 * RFC 6960 4.2.1: "If the value of responseStatus is one of the error
418 * conditions, the responseBytes field is not set."
419 */
420 const bool successful = (m_status == Response_Status_Code::Successful);
421 const bool has_response_bytes = response_outer.more_items();
422
423 if(successful && !has_response_bytes) {
424 throw Decoding_Error("OCSP response with successful status is missing responseBytes");
425 }
426 if(!successful && has_response_bytes) {
427 throw Decoding_Error("OCSP response with non-successful status includes responseBytes");
428 }
429
430 if(successful) {
431 BER_Decoder response_bytes_ctx = response_outer.start_context_specific(0);
432 BER_Decoder response_bytes = response_bytes_ctx.start_sequence();
433
434 response_bytes.decode_and_check(OID::from_string("PKIX.OCSP.BasicResponse"),
435 "Unknown response type in OCSP response");
436
437 /*
438 * RFC 6960 Section 4.2.1
439 *
440 * BasicOCSPResponse ::= SEQUENCE {
441 * tbsResponseData ResponseData,
442 * signatureAlgorithm AlgorithmIdentifier,
443 * signature BIT STRING,
444 * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
445 */
446 BER_Decoder basic_response_decoder(response_bytes.get_next_octet_string(), BER_Decoder::Limits::DER());
447 BER_Decoder basicresponse = basic_response_decoder.start_sequence();
448
449 basicresponse.start_sequence()
450 .raw_bytes(m_tbs_bits)
451 .end_cons()
452 .decode(m_sig_algo)
453 .decode_octet_aligned_bitstring(m_signature);
454 decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
455
456 basicresponse.verify_end();
457 basic_response_decoder.verify_end();
458
459 /*
460 * RFC 6960 Section 4.2.1
461 *
462 * ResponseData ::= SEQUENCE {
463 * version [0] EXPLICIT Version DEFAULT v1,
464 * responderID ResponderID,
465 * producedAt GeneralizedTime,
466 * responses SEQUENCE OF SingleResponse,
467 * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
468 *
469 * ResponderID ::= CHOICE {
470 * byName [1] Name,
471 * byKey [2] KeyHash }
472 */
473 size_t responsedata_version = 0;
474 Extensions extensions;
475
476 BER_Decoder tbs_decoder(m_tbs_bits, BER_Decoder::Limits::DER());
477 tbs_decoder
478 .decode_optional(responsedata_version, ASN1_Type(0), ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
479
480 .decode_optional(m_signer_name, ASN1_Type(1), ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
481
482 .decode_optional_string(
484
485 .decode(m_produced_at)
486
487 .decode_list(m_responses);
488
489 check_generalized_time(m_produced_at, "producedAt");
490
491 if(tbs_decoder.more_items()) {
492 const BER_Object next = tbs_decoder.get_next_object();
494 BER_Decoder ext_decoder(next, BER_Decoder::Limits::DER());
495 extensions.decode_from(ext_decoder, Extension_Context::OCSP_Response);
496 ext_decoder.verify_end();
497 } else {
498 throw Decoding_Error("Unexpected tag in OCSP ResponseData");
499 }
500 }
501 tbs_decoder.verify_end();
502
503 const bool has_signer = !m_signer_name.empty();
504 const bool has_key_hash = !m_key_hash.empty();
505
506 if(has_signer && has_key_hash) {
507 throw Decoding_Error("OCSP response includes both byName and byKey in responderID field");
508 }
509 if(!has_signer && !has_key_hash) {
510 throw Decoding_Error("OCSP response contains neither byName nor byKey in responderID field");
511 }
512 if(has_key_hash && m_key_hash.size() != 20) {
513 // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
514 throw Decoding_Error("OCSP response contains a byKey with invalid length");
515 }
516
517 response_bytes.verify_end();
518 response_bytes_ctx.verify_end();
519
520 // We don't currently recognize any extensions here so if any are critical we should reject
521 m_has_unknown_critical_ext = !extensions.critical_extensions().empty();
522 }
523
524 response_outer.verify_end();
525 outer_decoder.verify_end();
526
527 if(m_has_unknown_critical_ext == false) {
528 // Check all of the SingleResponse extensions
529 for(const auto& sr : m_responses) {
530 if(sr.has_unknown_critical_extension()) {
531 m_has_unknown_critical_ext = true;
532 break;
533 }
534 }
535 }
536}
static Limits DER()
Definition ber_dec.h:42
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:80
Response_Status_Code
Definition ocsp.h:158
ASN1_Type
Definition asn1_obj.h:47

References Botan::Constructed, Botan::ContextSpecific, Botan::Extensions::critical_extensions(), Botan::BER_Decoder::decode(), Botan::BER_Decoder::decode_and_check(), Botan::Extensions::decode_from(), Botan::BER_Decoder::decode_list(), Botan::BER_Decoder::decode_octet_aligned_bitstring(), Botan::BER_Decoder::decode_optional(), Botan::BER_Decoder::decode_optional_string(), Botan::BER_Decoder::Limits::DER(), Botan::BER_Decoder::end_cons(), Botan::Enumerated, Botan::OID::from_string(), Botan::BER_Decoder::get_next_object(), Botan::BER_Decoder::get_next_octet_string(), Botan::BER_Object::is_a(), Botan::BER_Decoder::more_items(), Botan::OCSP_Response, Botan::OctetString, Botan::BER_Decoder::raw_bytes(), Botan::BER_Decoder::start_context_specific(), Botan::BER_Decoder::start_sequence(), Botan::OCSP::Successful, Botan::Universal, and Botan::BER_Decoder::verify_end().

Member Function Documentation

◆ certificates()

const std::vector< X509_Certificate > & Botan::OCSP::Response::certificates ( ) const
inline
Returns
the certificate chain, if provided in response

Definition at line 284 of file ocsp.h.

284{ return m_certs; }

◆ dummy_no_revocation_url_response()

Response Botan::OCSP::Response::dummy_no_revocation_url_response ( )
inlinestatic

Return a fake OCSP response indicating there was no usable OCSP URL This is not normally useful for applications

Definition at line 304 of file ocsp.h.

References Botan::OCSP_NO_REVOCATION_URL, and Response().

◆ dummy_server_not_available_response()

Response Botan::OCSP::Response::dummy_server_not_available_response ( )
inlinestatic

Return a fake OCSP response indicating the server was not available This is not normally useful for applications

Definition at line 296 of file ocsp.h.

References Botan::OCSP_SERVER_NOT_AVAILABLE, and Response().

◆ dummy_status()

std::optional< Certificate_Status_Code > Botan::OCSP::Response::dummy_status ( ) const
inline

Return the dummy response if this is a 'fake' OCSP response otherwise std::nullopt This is not normally useful for applications

Definition at line 312 of file ocsp.h.

312{ return m_dummy_response_status; }

◆ find_signing_certificate()

std::optional< X509_Certificate > Botan::OCSP::Response::find_signing_certificate ( const X509_Certificate & issuer_certificate,
const Certificate_Store * trusted_ocsp_responders = nullptr ) const

Find the certificate that signed this OCSP response from all possible candidates and taking the attached certificates into account.

Parameters
issuer_certificateis the issuer of the certificate in question
trusted_ocsp_respondersoptionally, a certificate store containing additionally trusted responder certificates
Returns
the certificate that signed this response or std::nullopt if not found

Definition at line 601 of file ocsp.cpp.

602 {
603 using namespace std::placeholders;
604
605 // Check whether the CA issuing the certificate in question also signed this
606 if(is_issued_by(issuer_certificate)) {
607 return issuer_certificate;
608 }
609
610 // Then try to find a delegated responder certificate in the stapled certs
611 for(const auto& cert : m_certs) {
612 if(this->is_issued_by(cert)) {
613 return cert;
614 }
615 }
616
617 // Last resort: check the additionally provides trusted OCSP responders
618 if(trusted_ocsp_responders != nullptr) {
619 if(!m_key_hash.empty()) {
620 auto signing_cert = trusted_ocsp_responders->find_cert_by_pubkey_sha1(m_key_hash);
621 if(signing_cert) {
622 return signing_cert;
623 }
624 }
625
626 if(!m_signer_name.empty()) {
627 auto signing_cert = trusted_ocsp_responders->find_cert(m_signer_name, {});
628 if(signing_cert) {
629 return signing_cert;
630 }
631 }
632 }
633
634 return std::nullopt;
635}

References Botan::Certificate_Store::find_cert(), and Botan::Certificate_Store::find_cert_by_pubkey_sha1().

◆ produced_at()

const X509_Time & Botan::OCSP::Response::produced_at ( ) const
inline
Returns
the time this OCSP response was supposedly produced at

Definition at line 245 of file ocsp.h.

245{ return m_produced_at; }

◆ raw_bits()

const std::vector< uint8_t > & Botan::OCSP::Response::raw_bits ( ) const
inline

Definition at line 257 of file ocsp.h.

257{ return m_response_bits; }

◆ responses()

const std::vector< SingleResponse > & Botan::OCSP::Response::responses ( ) const
inline
Returns
the SingleResponses included in this response (empty for a 'fake' or non-successful response)

Definition at line 290 of file ocsp.h.

290{ return m_responses; }

◆ signer_key_hash()

const std::vector< uint8_t > & Botan::OCSP::Response::signer_key_hash ( ) const
inline
Returns
key hash, if provided in response (may be empty)

Definition at line 255 of file ocsp.h.

255{ return m_key_hash; }

◆ signer_name()

const X509_DN & Botan::OCSP::Response::signer_name ( ) const
inline
Returns
DN of signer, if provided in response (may be empty)

Definition at line 250 of file ocsp.h.

250{ return m_signer_name; }

◆ status()

Response_Status_Code Botan::OCSP::Response::status ( ) const
inline
Returns
the status of the response

Definition at line 240 of file ocsp.h.

240{ return m_status; }

Referenced by Response().

◆ status_for()

Certificate_Status_Code Botan::OCSP::Response::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

Searches the OCSP response for issuer and subject certificate.

Parameters
issuerissuer certificate
subjectsubject certificate
ref_timethe reference time
max_agethe maximum age the response should be considered valid if next_update is not set
Returns
OCSP status code, possible values: CERT_IS_REVOKED, OCSP_NOT_YET_VALID, OCSP_HAS_EXPIRED, OCSP_IS_TOO_OLD, OCSP_RESPONSE_GOOD, OCSP_BAD_STATUS, OCSP_CERT_NOT_LISTED

Definition at line 637 of file ocsp.cpp.

640 {
641 if(m_dummy_response_status) {
642 return m_dummy_response_status.value();
643 }
644
645 for(const auto& response : m_responses) {
646 if(response.certid().is_id_for(issuer, subject)) {
647 const X509_Time x509_ref_time(ref_time);
648
649 /*
650 * We check certificate status prior to checking expiration, since otherwise it's
651 * possible to take an OCSP response indicating revocation, wait for it to expire,
652 * and then staple it. If such a response was reported as "expired" rather than
653 * "revoked" it's easy to dismiss as a clock issue or other misconfiguration.
654 */
655
656 if(response.cert_status() == 1) {
658 }
659
660 try {
661 if(response.this_update() > x509_ref_time) {
663 }
664
665 if(response.next_update().time_is_set()) {
666 if(x509_ref_time > response.next_update()) {
668 }
669 } else if(max_age > std::chrono::seconds::zero() &&
670 ref_time - response.this_update().to_std_timepoint() > max_age) {
672 }
673 } catch(Exception&) {
674 // This can occur if eg the OCSP time is not representable by the system clock
676 }
677
678 if(response.cert_status() == 0) {
680 } else {
682 }
683 }
684 }
685
687}
ASN1_Time X509_Time
Definition asn1_obj.h:27

References Botan::CERT_IS_REVOKED, Botan::OCSP_BAD_STATUS, Botan::OCSP_CERT_NOT_LISTED, Botan::OCSP_HAS_EXPIRED, Botan::OCSP_IS_TOO_OLD, Botan::OCSP_NOT_YET_VALID, Botan::OCSP_RESPONSE_GOOD, and Botan::OCSP_RESPONSE_INVALID.

◆ verify_signature() [1/2]

Certificate_Status_Code Botan::OCSP::Response::verify_signature ( const X509_Certificate & signing_certificate) const

Check signature of the OCSP response.

Note: It is the responsibility of the caller to verify that signing certificate is trustworthy and authorized to do so.

Parameters
signing_certificatethe certificate that signed this response (
See also
Response::find_signing_certificate).
Returns
status code indicating the validity of the signature

Definition at line 550 of file ocsp.cpp.

550 {
551 const Path_Validation_Restrictions restrictions;
552
553 return this->verify_signature(issuer, restrictions);
554}
Certificate_Status_Code verify_signature(const X509_Certificate &signing_certificate) const
Definition ocsp.cpp:550

References verify_signature().

Referenced by verify_signature().

◆ verify_signature() [2/2]

Certificate_Status_Code Botan::OCSP::Response::verify_signature ( const X509_Certificate & signing_certificate,
const Path_Validation_Restrictions & restrictions ) const

Check signature of the OCSP response.

Note: It is the responsibility of the caller to verify that signing certificate is trustworthy and authorized to do so.

Parameters
signing_certificatethe certificate that signed this response (
See also
Response::find_signing_certificate)
Parameters
restrictionson the signature validation
Returns
status code indicating the validity of the signature

Definition at line 556 of file ocsp.cpp.

557 {
558 if(m_dummy_response_status) {
559 return m_dummy_response_status.value();
560 }
561
562 if(m_signer_name.empty() && m_key_hash.empty()) {
564 }
565
566 if(!is_issued_by(issuer)) {
568 }
569
570 try {
571 auto pub_key = issuer.subject_public_key();
572
573 PK_Verifier verifier(*pub_key, m_sig_algo);
574 verifier.update(ASN1::der_sequence_header(m_tbs_bits.size()));
575 verifier.update(m_tbs_bits);
576 const bool valid_signature = verifier.check_signature(m_signature);
577
578 if(valid_signature == false) {
580 }
581
582 if(m_has_unknown_critical_ext) {
584 }
585
586 const auto& trusted_hashes = restrictions.trusted_hashes();
587 if(!trusted_hashes.empty() && !trusted_hashes.contains(verifier.hash_function())) {
589 }
590
591 if(pub_key->estimated_strength() < restrictions.minimum_key_strength()) {
593 }
594
596 } catch(Exception&) {
598 }
599}
std::vector< uint8_t > der_sequence_header(size_t contents_len)
Definition der_enc.cpp:71

References Botan::PK_Verifier::check_signature(), Botan::ASN1::der_sequence_header(), Botan::PK_Verifier::hash_function(), Botan::Path_Validation_Restrictions::minimum_key_strength(), Botan::OCSP_ISSUER_NOT_FOUND, Botan::OCSP_RESPONSE_INVALID, Botan::OCSP_SIGNATURE_ERROR, Botan::OCSP_SIGNATURE_OK, Botan::SIGNATURE_METHOD_TOO_WEAK, Botan::X509_Certificate::subject_public_key(), Botan::Path_Validation_Restrictions::trusted_hashes(), Botan::UNKNOWN_CRITICAL_EXTENSION, Botan::UNTRUSTED_HASH, and Botan::PK_Verifier::update().


The documentation for this class was generated from the following files: