• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.21
/src/lib/x509/ocsp.cpp
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/pubkey.h>
15
#include <botan/x509_ext.h>
16
#include <botan/internal/parsing.h>
17

18
#include <functional>
19

20
#if defined(BOTAN_HAS_HTTP_UTIL)
21
   #include <botan/internal/http_util.h>
22
#endif
23

24
namespace Botan::OCSP {
25

26
namespace {
27

28
// TODO: should this be in a header somewhere?
29
void decode_optional_list(BER_Decoder& ber, ASN1_Type tag, std::vector<X509_Certificate>& output) {
997✔
30
   BER_Object obj = ber.get_next_object();
997✔
31

32
   if(obj.is_a(tag, ASN1_Class::ContextSpecific | ASN1_Class::Constructed) == false) {
997✔
33
      ber.push_back(obj);
22✔
34
      return;
22✔
35
   }
36

37
   BER_Decoder list(obj);
975✔
38

39
   while(list.more_items()) {
1,690✔
40
      BER_Object certbits = list.get_next_object();
979✔
41
      X509_Certificate cert(certbits.bits(), certbits.length());
979✔
42
      output.push_back(std::move(cert));
715✔
43
   }
1,694✔
44
}
1,708✔
45

46
}
47

48
Request::Request(const X509_Certificate& issuer_cert, const X509_Certificate& subject_cert) :
2✔
49
      m_issuer(issuer_cert), m_certid(m_issuer, BigInt::decode(subject_cert.serial_number())) {
4✔
50
   if(subject_cert.issuer_dn() != issuer_cert.subject_dn())
2✔
51
      throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
1✔
52
}
3✔
53

54
Request::Request(const X509_Certificate& issuer_cert, const BigInt& subject_serial) :
2✔
55
      m_issuer(issuer_cert), m_certid(m_issuer, subject_serial) {}
2✔
56

57
std::vector<uint8_t> Request::BER_encode() const {
3✔
58
   std::vector<uint8_t> output;
3✔
59
   DER_Encoder(output)
6✔
60
      .start_sequence()
3✔
61
      .start_sequence()
3✔
62
      .start_explicit(0)
3✔
63
      .encode(static_cast<size_t>(0))  // version #
3✔
64
      .end_explicit()
3✔
65
      .start_sequence()
6✔
66
      .start_sequence()
3✔
67
      .encode(m_certid)
3✔
68
      .end_cons()
3✔
69
      .end_cons()
3✔
70
      .end_cons()
3✔
71
      .end_cons();
3✔
72

73
   return output;
3✔
74
}
×
75

76
std::string Request::base64_encode() const { return Botan::base64_encode(BER_encode()); }
4✔
77

78
Response::Response(Certificate_Status_Code status) :
6✔
79
      m_status(Response_Status_Code::Successful), m_dummy_response_status(status) {}
6✔
80

81
Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
2,903✔
82
      m_response_bits(response_bits, response_bits + response_bits_len) {
2,903✔
83
   BER_Decoder response_outer = BER_Decoder(m_response_bits).start_sequence();
5,701✔
84

85
   size_t resp_status = 0;
2,798✔
86

87
   response_outer.decode(resp_status, ASN1_Type::Enumerated, ASN1_Class::Universal);
2,798✔
88

89
   m_status = static_cast<Response_Status_Code>(resp_status);
1,513✔
90

91
   if(m_status != Response_Status_Code::Successful) {
1,513✔
92
      return;
5✔
93
   }
94

95
   if(response_outer.more_items()) {
1,508✔
96
      BER_Decoder response_bytes = response_outer.start_context_specific(0).start_sequence();
1,500✔
97

98
      response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), "Unknown response type in OCSP response");
1,265✔
99

100
      BER_Decoder basicresponse = BER_Decoder(response_bytes.get_next_octet_string()).start_sequence();
2,246✔
101

102
      basicresponse.start_sequence()
1,009✔
103
         .raw_bytes(m_tbs_bits)
1,003✔
104
         .end_cons()
1,003✔
105
         .decode(m_sig_algo)
1,003✔
106
         .decode(m_signature, ASN1_Type::BitString);
997✔
107
      decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
997✔
108

109
      size_t responsedata_version = 0;
733✔
110
      Extensions extensions;
733✔
111

112
      BER_Decoder(m_tbs_bits)
1,392✔
113
         .decode_optional(responsedata_version, ASN1_Type(0), ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
733✔
114

115
         .decode_optional(m_signer_name, ASN1_Type(1), ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
1,455✔
116

117
         .decode_optional_string(
720✔
118
            m_key_hash, ASN1_Type::OctetString, 2, ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
119

120
         .decode(m_produced_at)
719✔
121

122
         .decode_list(m_responses)
138✔
123

124
         .decode_optional(extensions, ASN1_Type(1), ASN1_Class::ContextSpecific | ASN1_Class::Constructed);
798✔
125

126
      const bool has_signer = !m_signer_name.empty();
74✔
127
      const bool has_key_hash = !m_key_hash.empty();
74✔
128

129
      if(has_signer && has_key_hash)
74✔
130
         throw Decoding_Error("OCSP response includes both byName and byKey in responderID field");
×
131
      if(!has_signer && !has_key_hash)
74✔
132
         throw Decoding_Error("OCSP response contains neither byName nor byKey in responderID field");
×
133
   }
2,194✔
134

135
   response_outer.end_cons();
82✔
136
}
19,320✔
137

138
bool Response::is_issued_by(const X509_Certificate& candidate) const {
76✔
139
   if(!m_signer_name.empty()) {
76✔
140
      return (candidate.subject_dn() == m_signer_name);
74✔
141
   }
142

143
   if(!m_key_hash.empty()) {
2✔
144
      return (candidate.subject_public_key_bitstring_sha1() == m_key_hash);
1✔
145
   }
146

147
   return false;
148
}
149

150
Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const {
1✔
151
   if(m_dummy_response_status)
1✔
152
      return m_dummy_response_status.value();
×
153

154
   if(m_signer_name.empty() && m_key_hash.empty())
1✔
155
      return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
156

157
   if(!is_issued_by(issuer))
1✔
158
      return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
159

160
   try {
1✔
161
      auto pub_key = issuer.subject_public_key();
1✔
162

163
      PK_Verifier verifier(*pub_key, m_sig_algo);
1✔
164

165
      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
2✔
166
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
167
      else
168
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
×
169
   } catch(Exception&) { return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; }
2✔
170
}
171

172
std::optional<X509_Certificate> Response::find_signing_certificate(
51✔
173
   const X509_Certificate& issuer_certificate, const Certificate_Store* trusted_ocsp_responders) const {
174
   using namespace std::placeholders;
51✔
175

176
   // Check whether the CA issuing the certificate in question also signed this
177
   if(is_issued_by(issuer_certificate)) {
51✔
178
      return issuer_certificate;
19✔
179
   }
180

181
   // Then try to find a delegated responder certificate in the stapled certs
182
   auto match = std::find_if(m_certs.begin(), m_certs.end(), std::bind(&Response::is_issued_by, this, _1));
32✔
183
   if(match != m_certs.end()) {
32✔
184
      return *match;
75✔
185
   }
186

187
   // Last resort: check the additionally provides trusted OCSP responders
188
   if(trusted_ocsp_responders) {
8✔
189
      if(!m_key_hash.empty()) {
4✔
190
         auto signing_cert = trusted_ocsp_responders->find_cert_by_pubkey_sha1(m_key_hash);
×
191
         if(signing_cert)
×
192
            return signing_cert;
×
193
      }
×
194

195
      if(!m_signer_name.empty()) {
4✔
196
         auto signing_cert = trusted_ocsp_responders->find_cert(m_signer_name, {});
4✔
197
         if(signing_cert)
4✔
198
            return signing_cert;
2✔
199
      }
4✔
200
   }
201

202
   return std::nullopt;
6✔
203
}
204

205
Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
37✔
206
                                             const X509_Certificate& subject,
207
                                             std::chrono::system_clock::time_point ref_time,
208
                                             std::chrono::seconds max_age) const {
209
   if(m_dummy_response_status) {
37✔
210
      return m_dummy_response_status.value();
×
211
   }
212

213
   for(const auto& response : m_responses) {
37✔
214
      if(response.certid().is_id_for(issuer, subject)) {
37✔
215
         X509_Time x509_ref_time(ref_time);
37✔
216

217
         if(response.cert_status() == 1) {
37✔
218
            return Certificate_Status_Code::CERT_IS_REVOKED;
219
         }
220

221
         if(response.this_update() > x509_ref_time) {
37✔
222
            return Certificate_Status_Code::OCSP_NOT_YET_VALID;
223
         }
224

225
         if(response.next_update().time_is_set()) {
27✔
226
            if(x509_ref_time > response.next_update()) {
19✔
227
               return Certificate_Status_Code::OCSP_HAS_EXPIRED;
228
            }
229
         } else if(max_age > std::chrono::seconds::zero() &&
12✔
230
                   ref_time - response.this_update().to_std_timepoint() > max_age) {
16✔
231
            return Certificate_Status_Code::OCSP_IS_TOO_OLD;
232
         }
233

234
         if(response.cert_status() == 0) {
19✔
235
            return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
236
         } else {
237
            return Certificate_Status_Code::OCSP_BAD_STATUS;
×
238
         }
239
      }
37✔
240
   }
241

242
   return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
243
}
244

245
#if defined(BOTAN_HAS_HTTP_UTIL)
246

247
Response online_check(const X509_Certificate& issuer,
×
248
                      const BigInt& subject_serial,
249
                      std::string_view ocsp_responder,
250
                      std::chrono::milliseconds timeout) {
251
   if(ocsp_responder.empty())
×
252
      throw Invalid_Argument("No OCSP responder specified");
×
253

254
   OCSP::Request req(issuer, subject_serial);
×
255

256
   auto http = HTTP::POST_sync(ocsp_responder, "application/ocsp-request", req.BER_encode(), 1, timeout);
×
257

258
   http.throw_unless_ok();
×
259

260
   // Check the MIME type?
261

262
   return OCSP::Response(http.body());
×
263
}
×
264

265
Response online_check(const X509_Certificate& issuer,
×
266
                      const X509_Certificate& subject,
267
                      std::chrono::milliseconds timeout) {
268
   if(subject.issuer_dn() != issuer.subject_dn())
×
269
      throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
×
270

271
   return online_check(issuer, BigInt::decode(subject.serial_number()), subject.ocsp_responder(), timeout);
×
272
}
273

274
#endif
275

276
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc