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/pubkey.h>
15#include <botan/x509_ext.h>
16#include <botan/internal/parsing.h>
20#if defined(BOTAN_HAS_HTTP_UTIL)
21 #include <botan/internal/http_util.h>
29void decode_optional_list(BER_Decoder& ber,
ASN1_Type tag, std::vector<X509_Certificate>& output) {
30 BER_Object obj = ber.get_next_object();
37 BER_Decoder list(obj);
39 while(list.more_items()) {
40 BER_Object certbits = list.get_next_object();
41 X509_Certificate cert(certbits.bits(), certbits.length());
42 output.push_back(std::move(cert));
49 m_issuer(issuer_cert), m_certid(m_issuer,
BigInt::from_bytes(subject_cert.serial_number())) {
51 throw Invalid_Argument(
"Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
56 m_issuer(issuer_cert), m_certid(m_issuer, subject_serial) {}
59 std::vector<uint8_t> output;
64 .
encode(
static_cast<size_t>(0))
85 m_response_bits(response_bits, response_bits + response_bits_len) {
88 size_t resp_status = 0;
101 response_bytes.
decode_and_check(
OID(
"1.3.6.1.5.5.7.48.1.1"),
"Unknown response type in OCSP response");
110 decode_optional_list(basicresponse,
ASN1_Type(0), m_certs);
112 size_t responsedata_version = 0;
129 const bool has_signer = !m_signer_name.
empty();
130 const bool has_key_hash = !m_key_hash.empty();
132 if(has_signer && has_key_hash) {
133 throw Decoding_Error(
"OCSP response includes both byName and byKey in responderID field");
135 if(!has_signer && !has_key_hash) {
136 throw Decoding_Error(
"OCSP response contains neither byName nor byKey in responderID field");
144 if(!m_signer_name.
empty()) {
145 return (candidate.
subject_dn() == m_signer_name);
148 if(!m_key_hash.empty()) {
156 if(m_dummy_response_status) {
157 return m_dummy_response_status.value();
160 if(m_signer_name.
empty() && m_key_hash.empty()) {
164 if(!is_issued_by(issuer)) {
185 using namespace std::placeholders;
188 if(is_issued_by(issuer_certificate)) {
189 return issuer_certificate;
193 auto match = std::find_if(m_certs.begin(), m_certs.end(), std::bind(&Response::is_issued_by,
this, _1));
194 if(match != m_certs.end()) {
199 if(trusted_ocsp_responders) {
200 if(!m_key_hash.empty()) {
207 if(!m_signer_name.
empty()) {
208 auto signing_cert = trusted_ocsp_responders->
find_cert(m_signer_name, {});
220 std::chrono::system_clock::time_point ref_time,
221 std::chrono::seconds max_age)
const {
222 if(m_dummy_response_status) {
223 return m_dummy_response_status.value();
226 for(
const auto& response : m_responses) {
227 if(response.certid().is_id_for(issuer, subject)) {
230 if(response.cert_status() == 1) {
234 if(response.this_update() > x509_ref_time) {
238 if(response.next_update().time_is_set()) {
239 if(x509_ref_time > response.next_update()) {
242 }
else if(max_age > std::chrono::seconds::zero() &&
243 ref_time - response.this_update().to_std_timepoint() > max_age) {
247 if(response.cert_status() == 0) {
258#if defined(BOTAN_HAS_HTTP_UTIL)
261 const BigInt& subject_serial,
262 std::string_view ocsp_responder,
263 std::chrono::milliseconds timeout) {
264 if(ocsp_responder.empty()) {
270 auto http =
HTTP::POST_sync(ocsp_responder,
"application/ocsp-request", req.BER_encode(), 1, timeout);
272 http.throw_unless_ok();
279Response online_check(
const X509_Certificate& issuer,
280 const X509_Certificate& subject,
281 std::chrono::milliseconds timeout) {
282 if(subject.issuer_dn() != issuer.subject_dn()) {
283 throw Invalid_Argument(
"Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
286 return online_check(issuer,
BigInt::from_bytes(subject.serial_number()), subject.ocsp_responder(), timeout);
BER_Decoder & decode(bool &out)
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
std::vector< uint8_t > get_next_octet_string()
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Type type_tag=ASN1_Type::Sequence, ASN1_Class class_tag=ASN1_Class::Universal)
BER_Decoder start_sequence()
BER_Decoder start_context_specific(uint32_t tag)
BER_Decoder & decode_optional(T &out, ASN1_Type type_tag, ASN1_Class class_tag, const T &default_value=T())
BER_Decoder & decode_and_check(const T &expected, std::string_view error_msg)
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)
static BigInt from_bytes(std::span< const uint8_t > bytes)
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
DER_Encoder & end_explicit()
DER_Encoder & start_explicit(uint16_t type_tag)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
std::string base64_encode() const
Request(const X509_Certificate &issuer_cert, const X509_Certificate &subject_cert)
std::vector< uint8_t > BER_encode() const
Response(Certificate_Status_Code status)
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
std::optional< X509_Certificate > find_signing_certificate(const X509_Certificate &issuer_certificate, const Certificate_Store *trusted_ocsp_responders=nullptr) const
Certificate_Status_Code verify_signature(const X509_Certificate &signing_certificate) const
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
const X509_DN & subject_dn() const
const std::vector< uint8_t > & subject_public_key_bitstring_sha1() const
const X509_DN & issuer_dn() const
std::unique_ptr< Public_Key > subject_public_key() const
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
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)
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)