Coverage Report

Created: 2022-09-23 06:05

/src/botan/src/lib/x509/ocsp.cpp
Line
Count
Source (jump to first uncovered line)
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/internal/parsing.h>
17
18
#if defined(BOTAN_HAS_HTTP_UTIL)
19
  #include <botan/internal/http_util.h>
20
#endif
21
22
namespace Botan::OCSP {
23
24
namespace {
25
26
// TODO: should this be in a header somewhere?
27
void decode_optional_list(BER_Decoder& ber,
28
                          ASN1_Type tag,
29
                          std::vector<X509_Certificate>& output)
30
4.24k
   {
31
4.24k
   BER_Object obj = ber.get_next_object();
32
33
4.24k
   if(obj.is_a(tag, ASN1_Class::ContextSpecific | ASN1_Class::Constructed) == false)
34
1.69k
      {
35
1.69k
      ber.push_back(obj);
36
1.69k
      return;
37
1.69k
      }
38
39
2.54k
   BER_Decoder list(obj);
40
41
7.58k
   while(list.more_items())
42
5.04k
      {
43
5.04k
      BER_Object certbits = list.get_next_object();
44
5.04k
      X509_Certificate cert(certbits.bits(), certbits.length());
45
5.04k
      output.push_back(std::move(cert));
46
5.04k
      }
47
2.54k
   }
48
49
}
50
51
Request::Request(const X509_Certificate& issuer_cert,
52
                 const X509_Certificate& subject_cert) :
53
   m_issuer(issuer_cert),
54
   m_certid(m_issuer, BigInt::decode(subject_cert.serial_number()))
55
0
   {
56
0
   if(subject_cert.issuer_dn() != issuer_cert.subject_dn())
57
0
      throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
58
0
   }
59
60
Request::Request(const X509_Certificate& issuer_cert,
61
                 const BigInt& subject_serial) :
62
   m_issuer(issuer_cert),
63
   m_certid(m_issuer, subject_serial)
64
0
   {
65
0
   }
66
67
std::vector<uint8_t> Request::BER_encode() const
68
0
   {
69
0
   std::vector<uint8_t> output;
70
0
   DER_Encoder(output).start_sequence()
71
0
        .start_sequence()
72
0
          .start_explicit(0)
73
0
            .encode(static_cast<size_t>(0)) // version #
74
0
          .end_explicit()
75
0
            .start_sequence()
76
0
              .start_sequence()
77
0
                .encode(m_certid)
78
0
              .end_cons()
79
0
            .end_cons()
80
0
          .end_cons()
81
0
      .end_cons();
82
83
0
   return output;
84
0
   }
85
86
std::string Request::base64_encode() const
87
0
   {
88
0
   return Botan::base64_encode(BER_encode());
89
0
   }
90
91
Response::Response(Certificate_Status_Code status)
92
0
   {
93
0
   m_status = Response_Status_Code::Successful;
94
0
   m_dummy_response_status = status;
95
0
   }
96
97
Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
98
   m_response_bits(response_bits, response_bits + response_bits_len)
99
5.66k
   {
100
5.66k
   m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID;
101
102
5.66k
   BER_Decoder response_outer = BER_Decoder(m_response_bits).start_sequence();
103
104
5.66k
   size_t resp_status = 0;
105
106
5.66k
   response_outer.decode(resp_status, ASN1_Type::Enumerated, ASN1_Class::Universal);
107
108
5.66k
   m_status = static_cast<Response_Status_Code>(resp_status);
109
110
5.66k
   if(m_status != Response_Status_Code::Successful)
111
72
      { return; }
112
113
5.59k
   if(response_outer.more_items())
114
4.54k
      {
115
4.54k
      BER_Decoder response_bytes =
116
4.54k
         response_outer.start_context_specific(0).start_sequence();
117
118
4.54k
      response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
119
4.54k
                                      "Unknown response type in OCSP response");
120
121
4.54k
      BER_Decoder basicresponse =
122
4.54k
         BER_Decoder(response_bytes.get_next_octet_string()).start_sequence();
123
124
4.54k
      basicresponse.start_sequence()
125
4.54k
           .raw_bytes(m_tbs_bits)
126
4.54k
         .end_cons()
127
4.54k
         .decode(m_sig_algo)
128
4.54k
         .decode(m_signature, ASN1_Type::BitString);
129
4.54k
      decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
130
131
4.54k
      size_t responsedata_version = 0;
132
4.54k
      Extensions extensions;
133
134
4.54k
      BER_Decoder(m_tbs_bits)
135
4.54k
         .decode_optional(responsedata_version, ASN1_Type(0),
136
4.54k
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
137
138
4.54k
         .decode_optional(m_signer_name, ASN1_Type(1),
139
4.54k
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
140
141
4.54k
         .decode_optional_string(m_key_hash, ASN1_Type::OctetString, 2,
142
4.54k
                                 ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
143
144
4.54k
         .decode(m_produced_at)
145
146
4.54k
         .decode_list(m_responses)
147
148
4.54k
         .decode_optional(extensions, ASN1_Type(1),
149
4.54k
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed);
150
4.54k
      }
151
152
5.59k
   response_outer.end_cons();
153
5.59k
   }
154
155
Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
156
0
   {
157
0
   if (m_responses.empty())
158
0
      return m_dummy_response_status;
159
160
0
   try
161
0
      {
162
0
      std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());
163
164
0
      const std::vector<std::string> sig_info =
165
0
         split_on(m_sig_algo.get_oid().to_formatted_string(), '/');
166
167
0
      if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
168
0
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
169
170
0
      std::string padding = sig_info[1];
171
0
      const Signature_Format format = pub_key->default_x509_signature_format();
172
173
0
      PK_Verifier verifier(*pub_key, padding, format);
174
175
0
      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
176
0
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
177
0
      else
178
0
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
179
0
      }
180
0
   catch(Exception&)
181
0
      {
182
0
      return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
183
0
      }
184
0
   }
185
186
Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
187
                                                  const std::vector<X509_Certificate>& ee_cert_path) const
188
0
   {
189
0
   if (m_responses.empty())
190
0
      return m_dummy_response_status;
191
192
0
   std::optional<X509_Certificate> signing_cert;
193
194
0
   for(const auto& trusted_root : trusted_roots)
195
0
      {
196
0
      if(m_signer_name.empty() && m_key_hash.empty())
197
0
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
198
199
0
      if(!m_signer_name.empty())
200
0
         {
201
0
         signing_cert = trusted_root->find_cert(m_signer_name, std::vector<uint8_t>());
202
0
         if(signing_cert)
203
0
            {
204
0
            break;
205
0
            }
206
0
         }
207
208
0
      if(!m_key_hash.empty())
209
0
         {
210
0
         signing_cert = trusted_root->find_cert_by_pubkey_sha1(m_key_hash);
211
0
         if(signing_cert)
212
0
            {
213
0
            break;
214
0
            }
215
0
         }
216
0
      }
217
218
0
   if(!signing_cert && ee_cert_path.size() > 1)
219
0
      {
220
      // End entity cert is not allowed to sign their own OCSP request :)
221
0
      for(size_t i = 1; i < ee_cert_path.size(); ++i)
222
0
         {
223
         // Check all CA certificates in the (assumed validated) EE cert path
224
0
         if(!m_signer_name.empty() && ee_cert_path[i].subject_dn() == m_signer_name)
225
0
            {
226
0
            signing_cert = ee_cert_path[i];
227
0
            break;
228
0
            }
229
230
0
         if(!m_key_hash.empty() && ee_cert_path[i].subject_public_key_bitstring_sha1() == m_key_hash)
231
0
            {
232
0
            signing_cert = ee_cert_path[i];
233
0
            break;
234
0
            }
235
0
         }
236
0
      }
237
238
0
   if(!signing_cert && !m_certs.empty())
239
0
      {
240
0
      for(const auto& cert : m_certs)
241
0
         {
242
         // Check all CA certificates in the (assumed validated) EE cert path
243
0
         if(!m_signer_name.empty() && cert.subject_dn() == m_signer_name)
244
0
            {
245
0
            signing_cert = cert;
246
0
            break;
247
0
            }
248
249
0
         if(!m_key_hash.empty() && cert.subject_public_key_bitstring_sha1() == m_key_hash)
250
0
            {
251
0
            signing_cert = cert;
252
0
            break;
253
0
            }
254
0
         }
255
0
      }
256
257
0
   if(!signing_cert)
258
0
      return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
259
260
0
   if(!signing_cert->allowed_usage(CRL_SIGN) &&
261
0
      !signing_cert->allowed_extended_usage("PKIX.OCSPSigning"))
262
0
      {
263
0
      return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;
264
0
      }
265
266
0
   return this->verify_signature(*signing_cert);
267
0
   }
268
269
Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
270
      const X509_Certificate& subject,
271
      std::chrono::system_clock::time_point ref_time,
272
      std::chrono::seconds max_age) const
273
0
   {
274
0
   if(m_responses.empty())
275
0
      { return m_dummy_response_status; }
276
277
0
   for(const auto& response : m_responses)
278
0
      {
279
0
      if(response.certid().is_id_for(issuer, subject))
280
0
         {
281
0
         X509_Time x509_ref_time(ref_time);
282
283
0
         if(response.cert_status() == 1)
284
0
            { return Certificate_Status_Code::CERT_IS_REVOKED; }
285
286
0
         if(response.this_update() > x509_ref_time)
287
0
            { return Certificate_Status_Code::OCSP_NOT_YET_VALID; }
288
289
0
         if(response.next_update().time_is_set())
290
0
            {
291
0
            if(x509_ref_time > response.next_update())
292
0
               { return Certificate_Status_Code::OCSP_HAS_EXPIRED; }
293
0
            }
294
0
         else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age)
295
0
            { return Certificate_Status_Code::OCSP_IS_TOO_OLD; }
296
297
0
         if(response.cert_status() == 0)
298
0
            { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; }
299
0
         else
300
0
            { return Certificate_Status_Code::OCSP_BAD_STATUS; }
301
0
         }
302
0
      }
303
304
0
   return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
305
0
   }
306
307
#if defined(BOTAN_HAS_HTTP_UTIL)
308
309
Response online_check(const X509_Certificate& issuer,
310
                      const BigInt& subject_serial,
311
                      const std::string& ocsp_responder,
312
                      Certificate_Store* trusted_roots,
313
                      std::chrono::milliseconds timeout)
314
0
   {
315
0
   if(ocsp_responder.empty())
316
0
      throw Invalid_Argument("No OCSP responder specified");
317
318
0
   OCSP::Request req(issuer, subject_serial);
319
320
0
   auto http = HTTP::POST_sync(ocsp_responder,
321
0
                               "application/ocsp-request",
322
0
                               req.BER_encode(),
323
0
                               1,
324
0
                               timeout);
325
326
0
   http.throw_unless_ok();
327
328
   // Check the MIME type?
329
330
0
   OCSP::Response response(http.body());
331
332
0
   std::vector<Certificate_Store*> trusted_roots_vec;
333
0
   trusted_roots_vec.push_back(trusted_roots);
334
335
0
   if(trusted_roots)
336
0
      response.check_signature(trusted_roots_vec);
337
338
0
   return response;
339
0
   }
340
341
342
Response online_check(const X509_Certificate& issuer,
343
                      const X509_Certificate& subject,
344
                      Certificate_Store* trusted_roots,
345
                      std::chrono::milliseconds timeout)
346
0
   {
347
0
   if(subject.issuer_dn() != issuer.subject_dn())
348
0
      throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
349
350
0
   return online_check(issuer,
351
0
                       BigInt::decode(subject.serial_number()),
352
0
                       subject.ocsp_responder(),
353
0
                       trusted_roots,
354
0
                       timeout);
355
0
   }
356
357
#endif
358
359
}