Coverage Report

Created: 2020-02-14 15:38

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