Coverage Report

Created: 2023-04-05 14:54

/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/base64.h>
14
#include <botan/pubkey.h>
15
#include <botan/internal/parsing.h>
16
17
#include <functional>
18
19
#if defined(BOTAN_HAS_HTTP_UTIL)
20
  #include <botan/internal/http_util.h>
21
#endif
22
23
namespace Botan::OCSP {
24
25
namespace {
26
27
// TODO: should this be in a header somewhere?
28
void decode_optional_list(BER_Decoder& ber,
29
                          ASN1_Type tag,
30
                          std::vector<X509_Certificate>& output)
31
0
   {
32
0
   BER_Object obj = ber.get_next_object();
33
34
0
   if(obj.is_a(tag, ASN1_Class::ContextSpecific | ASN1_Class::Constructed) == false)
35
0
      {
36
0
      ber.push_back(obj);
37
0
      return;
38
0
      }
39
40
0
   BER_Decoder list(obj);
41
42
0
   while(list.more_items())
43
0
      {
44
0
      BER_Object certbits = list.get_next_object();
45
0
      X509_Certificate cert(certbits.bits(), certbits.length());
46
0
      output.push_back(std::move(cert));
47
0
      }
48
0
   }
49
50
}
51
52
Request::Request(const X509_Certificate& issuer_cert,
53
                 const X509_Certificate& subject_cert) :
54
   m_issuer(issuer_cert),
55
   m_certid(m_issuer, BigInt::decode(subject_cert.serial_number()))
56
0
   {
57
0
   if(subject_cert.issuer_dn() != issuer_cert.subject_dn())
58
0
      throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
59
0
   }
60
61
Request::Request(const X509_Certificate& issuer_cert,
62
                 const BigInt& subject_serial) :
63
   m_issuer(issuer_cert),
64
   m_certid(m_issuer, subject_serial)
65
0
   {
66
0
   }
67
68
std::vector<uint8_t> Request::BER_encode() const
69
0
   {
70
0
   std::vector<uint8_t> output;
71
0
   DER_Encoder(output).start_sequence()
72
0
        .start_sequence()
73
0
          .start_explicit(0)
74
0
            .encode(static_cast<size_t>(0)) // version #
75
0
          .end_explicit()
76
0
            .start_sequence()
77
0
              .start_sequence()
78
0
                .encode(m_certid)
79
0
              .end_cons()
80
0
            .end_cons()
81
0
          .end_cons()
82
0
      .end_cons();
83
84
0
   return output;
85
0
   }
86
87
std::string Request::base64_encode() const
88
0
   {
89
0
   return Botan::base64_encode(BER_encode());
90
0
   }
91
92
Response::Response(Certificate_Status_Code status)
93
   : m_status(Response_Status_Code::Successful)
94
   , m_dummy_response_status(status)
95
0
   {
96
0
   }
97
98
Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
99
   m_response_bits(response_bits, response_bits + response_bits_len)
100
0
   {
101
0
   BER_Decoder response_outer = BER_Decoder(m_response_bits).start_sequence();
102
103
0
   size_t resp_status = 0;
104
105
0
   response_outer.decode(resp_status, ASN1_Type::Enumerated, ASN1_Class::Universal);
106
107
0
   m_status = static_cast<Response_Status_Code>(resp_status);
108
109
0
   if(m_status != Response_Status_Code::Successful)
110
0
      { return; }
111
112
0
   if(response_outer.more_items())
113
0
      {
114
0
      BER_Decoder response_bytes =
115
0
         response_outer.start_context_specific(0).start_sequence();
116
117
0
      response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
118
0
                                      "Unknown response type in OCSP response");
119
120
0
      BER_Decoder basicresponse =
121
0
         BER_Decoder(response_bytes.get_next_octet_string()).start_sequence();
122
123
0
      basicresponse.start_sequence()
124
0
           .raw_bytes(m_tbs_bits)
125
0
         .end_cons()
126
0
         .decode(m_sig_algo)
127
0
         .decode(m_signature, ASN1_Type::BitString);
128
0
      decode_optional_list(basicresponse, ASN1_Type(0), m_certs);
129
130
0
      size_t responsedata_version = 0;
131
0
      Extensions extensions;
132
133
0
      BER_Decoder(m_tbs_bits)
134
0
         .decode_optional(responsedata_version, ASN1_Type(0),
135
0
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
136
137
0
         .decode_optional(m_signer_name, ASN1_Type(1),
138
0
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
139
140
0
         .decode_optional_string(m_key_hash, ASN1_Type::OctetString, 2,
141
0
                                 ASN1_Class::ContextSpecific | ASN1_Class::Constructed)
142
143
0
         .decode(m_produced_at)
144
145
0
         .decode_list(m_responses)
146
147
0
         .decode_optional(extensions, ASN1_Type(1),
148
0
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed);
149
0
      }
150
151
0
   response_outer.end_cons();
152
0
   }
153
154
Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
155
0
   {
156
0
   if(m_dummy_response_status)
157
0
      return m_dummy_response_status.value();
158
159
0
   if(m_signer_name.empty() && m_key_hash.empty())
160
0
      return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
161
162
0
   if(!is_issued_by(issuer))
163
0
      return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
164
165
0
   try
166
0
      {
167
0
      auto pub_key = issuer.subject_public_key();
168
169
0
      PK_Verifier verifier(*pub_key, m_sig_algo);
170
171
0
      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
172
0
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
173
0
      else
174
0
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
175
0
      }
176
0
   catch(Exception&)
177
0
      {
178
0
      return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
179
0
      }
180
0
   }
181
182
183
std::optional<X509_Certificate>
184
Response::find_signing_certificate(const X509_Certificate& issuer_certificate,
185
                                   const Certificate_Store* trusted_ocsp_responders) const
186
0
   {
187
0
   using namespace std::placeholders;
188
189
   // Check whether the CA issuing the certificate in question also signed this
190
0
   if(is_issued_by(issuer_certificate))
191
0
      {
192
0
      return issuer_certificate;
193
0
      }
194
195
   // Then try to find a delegated responder certificate in the stapled certs
196
0
   auto match = std::find_if(m_certs.begin(), m_certs.end(), std::bind(&Response::is_issued_by, this, _1));
197
0
   if(match != m_certs.end())
198
0
      {
199
0
      return *match;
200
0
      }
201
202
   // Last resort: check the additionally provides trusted OCSP responders
203
0
   if(trusted_ocsp_responders)
204
0
      {
205
0
      if(!m_key_hash.empty())
206
0
         {
207
0
         auto signing_cert = trusted_ocsp_responders->find_cert_by_pubkey_sha1(m_key_hash);
208
0
         if(signing_cert)
209
0
            return signing_cert;
210
0
         }
211
212
0
      if(!m_signer_name.empty())
213
0
         {
214
0
         auto signing_cert = trusted_ocsp_responders->find_cert(m_signer_name, {});
215
0
         if(signing_cert)
216
0
            return signing_cert;
217
0
         }
218
0
      }
219
220
0
   return std::nullopt;
221
0
   }
222
223
224
Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
225
      const X509_Certificate& subject,
226
      std::chrono::system_clock::time_point ref_time,
227
      std::chrono::seconds max_age) const
228
0
   {
229
0
   if(m_dummy_response_status)
230
0
      { return m_dummy_response_status.value(); }
231
232
0
   for(const auto& response : m_responses)
233
0
      {
234
0
      if(response.certid().is_id_for(issuer, subject))
235
0
         {
236
0
         X509_Time x509_ref_time(ref_time);
237
238
0
         if(response.cert_status() == 1)
239
0
            { return Certificate_Status_Code::CERT_IS_REVOKED; }
240
241
0
         if(response.this_update() > x509_ref_time)
242
0
            { return Certificate_Status_Code::OCSP_NOT_YET_VALID; }
243
244
0
         if(response.next_update().time_is_set())
245
0
            {
246
0
            if(x509_ref_time > response.next_update())
247
0
               { return Certificate_Status_Code::OCSP_HAS_EXPIRED; }
248
0
            }
249
0
         else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age)
250
0
            { return Certificate_Status_Code::OCSP_IS_TOO_OLD; }
251
252
0
         if(response.cert_status() == 0)
253
0
            { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; }
254
0
         else
255
0
            { return Certificate_Status_Code::OCSP_BAD_STATUS; }
256
0
         }
257
0
      }
258
259
0
   return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
260
0
   }
261
262
#if defined(BOTAN_HAS_HTTP_UTIL)
263
264
Response online_check(const X509_Certificate& issuer,
265
                      const BigInt& subject_serial,
266
                      const std::string& ocsp_responder,
267
                      std::chrono::milliseconds timeout)
268
0
   {
269
0
   if(ocsp_responder.empty())
270
0
      throw Invalid_Argument("No OCSP responder specified");
271
272
0
   OCSP::Request req(issuer, subject_serial);
273
274
0
   auto http = HTTP::POST_sync(ocsp_responder,
275
0
                               "application/ocsp-request",
276
0
                               req.BER_encode(),
277
0
                               1,
278
0
                               timeout);
279
280
0
   http.throw_unless_ok();
281
282
   // Check the MIME type?
283
284
0
   return OCSP::Response(http.body());
285
0
   }
286
287
288
Response online_check(const X509_Certificate& issuer,
289
                      const X509_Certificate& subject,
290
                      std::chrono::milliseconds timeout)
291
0
   {
292
0
   if(subject.issuer_dn() != issuer.subject_dn())
293
0
      throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
294
295
0
   return online_check(issuer,
296
0
                       BigInt::decode(subject.serial_number()),
297
0
                       subject.ocsp_responder(),
298
0
                       timeout);
299
0
   }
300
301
#endif
302
303
}