Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

ocsp.cpp
Go to the documentation of this file.
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/x509path.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 {
33 BER_Object obj = ber.get_next_object();
34
35 if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))
36 {
37 ber.push_back(obj);
38 return;
39 }
40
41 BER_Decoder list(obj.value);
42
43 while(list.more_items())
44 {
45 BER_Object certbits = list.get_next_object();
46 X509_Certificate cert(unlock(certbits.value));
47 output.push_back(std::move(cert));
48 }
49 }
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 {
58 if(subject_cert.issuer_dn() != issuer_cert.subject_dn())
59 throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)");
60 }
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 {
67 }
68
69 std::vector<uint8_t> Request::BER_encode() const
70 {
71 return DER_Encoder().start_cons(SEQUENCE)
72 .start_cons(SEQUENCE)
73 .start_explicit(0)
74 .encode(static_cast<size_t>(0)) // version #
75 .end_explicit()
76 .start_cons(SEQUENCE)
77 .start_cons(SEQUENCE)
78 .encode(m_certid)
79 .end_cons()
80 .end_cons()
81 .end_cons()
82 .end_cons().get_contents_unlocked();
83 }
84
85 std::string Request::base64_encode() const
86 {
87 return Botan::base64_encode(BER_encode());
88 }
89
90 Response::Response(const uint8_t response_bits[], size_t response_bits_len) :
91 m_response_bits(response_bits, response_bits + response_bits_len)
92 {
93 BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE);
94
95 size_t resp_status = 0;
96
97 response_outer.decode(resp_status, ENUMERATED, UNIVERSAL);
98
99 if(resp_status != 0)
100 throw Exception("OCSP response status " + std::to_string(resp_status));
101
102 if(response_outer.more_items())
103 {
104 BER_Decoder response_bytes =
105 response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE);
106
107 response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"),
108 "Unknown response type in OCSP response");
109
110 BER_Decoder basicresponse =
111 BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE);
112
113 basicresponse.start_cons(SEQUENCE)
114 .raw_bytes(m_tbs_bits)
115 .end_cons()
116 .decode(m_sig_algo)
117 .decode(m_signature, BIT_STRING);
118 decode_optional_list(basicresponse, ASN1_Tag(0), m_certs);
119
120 size_t responsedata_version = 0;
121 Extensions extensions;
122
123 BER_Decoder(m_tbs_bits)
124 .decode_optional(responsedata_version, ASN1_Tag(0),
125 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
126
127 .decode_optional(m_signer_name, ASN1_Tag(1),
128 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
129
130 .decode_optional_string(m_key_hash, OCTET_STRING, 2,
131 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
132
133 .decode(m_produced_at)
134
135 .decode_list(m_responses)
136
137 .decode_optional(extensions, ASN1_Tag(1),
138 ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC));
139 }
140
141 response_outer.end_cons();
142 }
143
144 Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
145 {
146 try
147 {
148 std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());
149
150 const std::vector<std::string> sig_info =
151 split_on(OIDS::lookup(m_sig_algo.oid), '/');
152
153 if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
154 return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
155
156 std::string padding = sig_info[1];
157 Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;
158
159 PK_Verifier verifier(*pub_key, padding, format);
160
161 if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
162 return Certificate_Status_Code::OCSP_SIGNATURE_OK;
163 else
164 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
165 }
166 catch(Exception&)
167 {
168 return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
169 }
170 }
171
172 Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots,
173 const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const
174 {
175 std::shared_ptr<const X509_Certificate> signing_cert;
176
177 for(size_t i = 0; i != trusted_roots.size(); ++i)
178 {
179 if(m_signer_name.empty() && m_key_hash.empty())
180 return Certificate_Status_Code::OCSP_RESPONSE_INVALID;
181
182 if(!m_signer_name.empty())
183 {
184 signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<uint8_t>());
185 if(signing_cert)
186 {
187 break;
188 }
189 }
190
191 if(m_key_hash.size() > 0)
192 {
193 signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash);
194 if(signing_cert)
195 {
196 break;
197 }
198 }
199 }
200
201 if(!signing_cert && ee_cert_path.size() > 1)
202 {
203 // End entity cert is not allowed to sign their own OCSP request :)
204 for(size_t i = 1; i < ee_cert_path.size(); ++i)
205 {
206 // Check all CA certificates in the (assumed validated) EE cert path
207 if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name)
208 {
209 signing_cert = ee_cert_path[i];
210 break;
211 }
212
213 if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash)
214 {
215 signing_cert = ee_cert_path[i];
216 break;
217 }
218 }
219 }
220
221 if(!signing_cert && m_certs.size() > 0)
222 {
223 for(size_t i = 0; i < m_certs.size(); ++i)
224 {
225 // Check all CA certificates in the (assumed validated) EE cert path
226 if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name)
227 {
228 signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
229 break;
230 }
231
232 if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash)
233 {
234 signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]);
235 break;
236 }
237 }
238 }
239
240 if(!signing_cert)
241 return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND;
242
243 if(!signing_cert->allowed_usage(CRL_SIGN) &&
244 !signing_cert->allowed_extended_usage("PKIX.OCSPSigning"))
245 {
246 return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE;
247 }
248
249 return this->verify_signature(*signing_cert);
250 }
251
252 Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
253 const X509_Certificate& subject,
254 std::chrono::system_clock::time_point ref_time) const
255 {
256 for(const auto& response : m_responses)
257 {
258 if(response.certid().is_id_for(issuer, subject))
259 {
260 X509_Time x509_ref_time(ref_time);
261
262 if(response.cert_status() == 1)
263 return Certificate_Status_Code::CERT_IS_REVOKED;
264
265 if(response.this_update() > x509_ref_time)
266 return Certificate_Status_Code::OCSP_NOT_YET_VALID;
267
268 if(response.next_update().time_is_set() && x509_ref_time > response.next_update())
269 return Certificate_Status_Code::OCSP_HAS_EXPIRED;
270
271 if(response.cert_status() == 0)
272 return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
273 else
274 return Certificate_Status_Code::OCSP_BAD_STATUS;
275 }
276 }
277
278 return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
279 }
280
281 #if defined(BOTAN_HAS_HTTP_UTIL)
282
283 Response online_check(const X509_Certificate& issuer,
284 const BigInt& subject_serial,
285 const std::string& ocsp_responder,
286 Certificate_Store* trusted_roots)
287 {
288 if(ocsp_responder.empty())
289 throw Invalid_Argument("No OCSP responder specified");
290
291 OCSP::Request req(issuer, subject_serial);
292
293 auto http = HTTP::POST_sync(ocsp_responder,
294 "application/ocsp-request",
295 req.BER_encode());
296
297 http.throw_unless_ok();
298
299 // Check the MIME type?
300
301 OCSP::Response response(http.body());
302
303 std::vector<Certificate_Store*> trusted_roots_vec;
304 trusted_roots_vec.push_back(trusted_roots);
305
306 if(trusted_roots)
307 response.check_signature(trusted_roots_vec);
308
309 return response;
310 }
311
312
313 Response online_check(const X509_Certificate& issuer,
314 const X509_Certificate& subject,
315 Certificate_Store* trusted_roots)
316 {
317 if(subject.issuer_dn() != issuer.subject_dn())
318 throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)");
319
320 return online_check(issuer,
321 BigInt::decode(subject.serial_number()),
322 subject.ocsp_responder(),
323 trusted_roots);
324 }
325
326 #endif
327
328 }
329
330 }
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::Certificate_Status_Code::OCSP_SIGNATURE_ERROR
Botan::OCSP::Request
Definition: ocsp.h:23
Botan::OCSP::Response::status_for
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()) const
Definition: ocsp.cpp:252
Botan::Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE
Botan::PEM_Code::decode
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Botan::CONTEXT_SPECIFIC
Definition: asn1_obj.h:25
Botan::Exception
Definition: exceptn.h:21
Botan::Certificate_Status_Code::OCSP_CERT_NOT_LISTED
Botan::BigInt
Definition: bigint.h:23
Botan::X509_Certificate::serial_number
std::vector< uint8_t > serial_number() const
Definition: x509cert.cpp:427
Botan::DER_Encoder::get_contents_unlocked
std::vector< uint8_t > get_contents_unlocked()
Definition: der_enc.h:27
Botan::PK_Verifier::verify_message
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition: pubkey.cpp:280
Botan::BER_Decoder::decode_optional_string
BER_Decoder & decode_optional_string(std::vector< uint8_t, Alloc > &out, ASN1_Tag real_type, uint16_t type_no, ASN1_Tag class_tag=CONTEXT_SPECIFIC)
Definition: ber_dec.h:162
Botan::OCSP::Response::check_signature
Certificate_Status_Code check_signature(const std::vector< Certificate_Store * > &trust_roots, const std::vector< std::shared_ptr< const X509_Certificate >> &cert_path={}) const
Definition: ocsp.cpp:172
Botan::BER_Decoder::decode_and_check
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:146
Botan::OCSP::Request::base64_encode
std::string base64_encode() const
Definition: ocsp.cpp:85
Botan::Signature_Format
Signature_Format
Definition: pubkey.h:29
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:138
Botan::X509_Certificate::ocsp_responder
std::string ocsp_responder() const
Definition: x509cert.cpp:398
Botan::Extensions
Definition: x509_ext.h:86
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:376
Botan::DER_Encoder::end_explicit
DER_Encoder & end_explicit()
Definition: der_enc.cpp:174
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:147
Botan::ENUMERATED
Definition: asn1_obj.h:38
Botan::UNIVERSAL
Definition: asn1_obj.h:23
Botan::X509_DN::empty
bool empty() const
Definition: x509_dn.h:40
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:216
Botan::OCSP::Response
Definition: ocsp.h:69
Botan::BER_Decoder::decode_optional
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:213
Botan::OCTET_STRING
Definition: asn1_obj.h:35
Botan::DER_Encoder
Definition: der_enc.h:22
Botan::CRL_SIGN
Definition: key_constraint.h:29
Botan::X509_Certificate
Definition: x509cert.h:36
Botan::CONSTRUCTED
Definition: asn1_obj.h:27
Botan::BER_Decoder::end_cons
BER_Decoder & end_cons()
Definition: ber_dec.cpp:272
Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD
Botan::BER_Decoder::more_items
bool more_items() const
Definition: ber_dec.cpp:158
Botan::Certificate_Status_Code::OCSP_BAD_STATUS
Botan::OIDS::lookup
std::string lookup(const OID &oid)
Definition: oids.cpp:18
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:22
Botan::AlgorithmIdentifier::oid
OID oid
Definition: alg_id.h:36
Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID
Botan::SEQUENCE
Definition: asn1_obj.h:39
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:258
Botan::HTTP::POST_sync
Response POST_sync(const std::string &url, const std::string &content_type, const std::vector< uint8_t > &body, size_t allowable_redirects)
Definition: http_util.cpp:294
Botan
Definition: alg_id.cpp:13
Botan::PK_Verifier
Definition: pubkey.h:288
Botan::IEEE_1363
Definition: pubkey.h:29
Botan::ASN1::put_in_sequence
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition: asn1_obj.cpp:35
Botan::OCSP::Request::Request
Request(const X509_Certificate &issuer_cert, const X509_Certificate &subject_cert)
Definition: ocsp.cpp:53
Botan::OCSP::Response::Response
Response()=default
Botan::unlock
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:125
Botan::BIT_STRING
Definition: asn1_obj.h:34
Botan::X509_Certificate::issuer_dn
X509_DN issuer_dn() const
Definition: x509cert.cpp:432
Botan::base64_encode
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:35
Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:137
Botan::DER_SEQUENCE
Definition: pubkey.h:29
Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK
Botan::BER_Decoder::decode_list
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Tag type_tag=SEQUENCE, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.h:272
Botan::X509_Certificate::subject_public_key
Public_Key * subject_public_key() const
Definition: x509cert.cpp:215
Botan::Certificate_Store
Definition: certstor.h:19
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:18
Botan::BER_Decoder::get_next_octet_string
std::vector< uint8_t > get_next_octet_string()
Definition: ber_dec.cpp:405
Botan::OID
Definition: asn1_oid.h:20
Botan::BER_Decoder::raw_bytes
BER_Decoder & raw_bytes(secure_vector< uint8_t > &v)
Definition: ber_dec.cpp:178
Botan::BER_Decoder
Definition: ber_dec.h:19
Botan::X509_Certificate::subject_dn
X509_DN subject_dn() const
Definition: x509cert.cpp:449
Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID
Botan::OCSP::Response::verify_signature
Certificate_Status_Code verify_signature(const X509_Certificate &issuer) const
Definition: ocsp.cpp:144
Botan::X509_Time
Definition: asn1_time.h:19
Botan::Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND
Botan::BigInt::decode
static BigInt decode(const uint8_t buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:114
Botan::Certificate_Status_Code::CERT_IS_REVOKED
Botan::DER_Encoder::start_explicit
DER_Encoder & start_explicit(uint16_t type_tag)
Definition: der_enc.cpp:161
Botan::OCSP::Request::BER_encode
std::vector< uint8_t > BER_encode() const
Definition: ocsp.cpp:69