monotone

monotone Mtn Source Tree

Root/botan/x509stor.cpp

1/*************************************************
2* X.509 Certificate Store Source File *
3* (C) 1999-2006 The Botan Project *
4*************************************************/
5
6#include <botan/x509stor.h>
7#include <botan/parsing.h>
8#include <botan/pubkey.h>
9#include <botan/look_pk.h>
10#include <botan/oids.h>
11#include <botan/config.h>
12#include <botan/util.h>
13#include <algorithm>
14#include <memory>
15
16namespace Botan {
17
18namespace {
19
20/*************************************************
21* Compare the value of unique ID fields *
22*************************************************/
23bool compare_ids(const MemoryVector<byte>& id1,
24 const MemoryVector<byte>& id2)
25 {
26 if(!id1.size() || !id2.size())
27 return true;
28 return (id1 == id2);
29 }
30
31/*************************************************
32* Check a particular usage restriction *
33*************************************************/
34bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage,
35 X509_Store::Cert_Usage check_for, Key_Constraints constraints)
36 {
37 if((usage & check_for) == 0)
38 return true;
39 if(cert.constraints() == NO_CONSTRAINTS)
40 return true;
41 if(cert.constraints() & constraints)
42 return true;
43 return false;
44 }
45
46/*************************************************
47* Check a particular usage restriction *
48*************************************************/
49bool check_usage(const X509_Certificate& cert, X509_Store::Cert_Usage usage,
50 X509_Store::Cert_Usage check_for,
51 const std::string& usage_oid)
52 {
53 if((usage & check_for) == 0)
54 return true;
55
56 const std::vector<std::string> constraints = cert.ex_constraints();
57
58 if(constraints.empty())
59 return true;
60
61 return std::binary_search(constraints.begin(), constraints.end(),
62 usage_oid);
63 }
64
65/*************************************************
66* Check the usage restrictions *
67*************************************************/
68X509_Code usage_check(const X509_Certificate& cert,
69 X509_Store::Cert_Usage usage)
70 {
71 if(usage == X509_Store::ANY)
72 return VERIFIED;
73
74 if(!check_usage(cert, usage, X509_Store::CRL_SIGNING, CRL_SIGN))
75 return CA_CERT_NOT_FOR_CRL_ISSUER;
76
77 if(!check_usage(cert, usage, X509_Store::TLS_SERVER, "PKIX.ServerAuth"))
78 return INVALID_USAGE;
79 if(!check_usage(cert, usage, X509_Store::TLS_CLIENT, "PKIX.ClientAuth"))
80 return INVALID_USAGE;
81 if(!check_usage(cert, usage, X509_Store::CODE_SIGNING, "PKIX.CodeSigning"))
82 return INVALID_USAGE;
83 if(!check_usage(cert, usage, X509_Store::EMAIL_PROTECTION,
84 "PKIX.EmailProtection"))
85 return INVALID_USAGE;
86 if(!check_usage(cert, usage, X509_Store::TIME_STAMPING,
87 "PKIX.TimeStamping"))
88 return INVALID_USAGE;
89
90 return VERIFIED;
91 }
92
93}
94
95/*************************************************
96* Define equality for revocation data *
97*************************************************/
98bool X509_Store::CRL_Data::operator==(const CRL_Data& other) const
99 {
100 if(issuer != other.issuer)
101 return false;
102 if(serial != other.serial)
103 return false;
104 return compare_ids(auth_key_id, other.auth_key_id);
105 }
106
107/*************************************************
108* Define inequality for revocation data *
109*************************************************/
110bool X509_Store::CRL_Data::operator!=(const CRL_Data& other) const
111 {
112 return !((*this) == other);
113 }
114
115/*************************************************
116* Define an ordering for revocation data *
117*************************************************/
118bool X509_Store::CRL_Data::operator<(const X509_Store::CRL_Data& other) const
119 {
120 if(*this == other)
121 return false;
122
123 const MemoryVector<byte>& serial1 = serial;
124 const MemoryVector<byte>& key_id1 = auth_key_id;
125 const MemoryVector<byte>& serial2 = other.serial;
126 const MemoryVector<byte>& key_id2 = other.auth_key_id;
127
128 if(compare_ids(key_id1, key_id2) == false)
129 {
130 if(std::lexicographical_compare(key_id1.begin(), key_id1.end(),
131 key_id2.begin(), key_id2.end()))
132 return true;
133
134 if(std::lexicographical_compare(key_id2.begin(), key_id2.end(),
135 key_id1.begin(), key_id1.end()))
136 return false;
137 }
138
139 if(compare_ids(serial1, serial2) == false)
140 {
141 if(std::lexicographical_compare(serial1.begin(), serial1.end(),
142 serial2.begin(), serial2.end()))
143 return true;
144
145 if(std::lexicographical_compare(serial2.begin(), serial2.end(),
146 serial1.begin(), serial1.end()))
147 return false;
148 }
149
150 return (issuer < other.issuer);
151 }
152
153/*************************************************
154* X509_Store Constructor *
155*************************************************/
156X509_Store::X509_Store()
157 {
158 revoked_info_valid = true;
159 }
160
161/*************************************************
162* X509_Store Copy Constructor *
163*************************************************/
164X509_Store::X509_Store(const X509_Store& store)
165 {
166 certs = store.certs;
167 revoked = store.revoked;
168 revoked_info_valid = store.revoked_info_valid;
169 for(u32bit j = 0; j != store.stores.size(); ++j)
170 stores[j] = store.stores[j]->clone();
171 }
172
173/*************************************************
174* X509_Store Destructor *
175*************************************************/
176X509_Store::~X509_Store()
177 {
178 for(u32bit j = 0; j != stores.size(); ++j)
179 delete stores[j];
180 }
181
182/*************************************************
183* Verify a certificate's authenticity *
184*************************************************/
185X509_Code X509_Store::validate_cert(const X509_Certificate& cert,
186 Cert_Usage cert_usage)
187 {
188 recompute_revoked_info();
189
190 std::vector<u32bit> indexes;
191 X509_Code chaining_result = construct_cert_chain(cert, indexes);
192 if(chaining_result != VERIFIED)
193 return chaining_result;
194
195 const u64bit current_time = system_time();
196
197 s32bit time_check = validity_check(cert.start_time(), cert.end_time(),
198 current_time);
199 if(time_check < 0) return CERT_NOT_YET_VALID;
200 else if(time_check > 0) return CERT_HAS_EXPIRED;
201
202 X509_Code sig_check_result = check_sig(cert, certs[indexes[0]]);
203 if(sig_check_result != VERIFIED)
204 return sig_check_result;
205
206 if(is_revoked(cert))
207 return CERT_IS_REVOKED;
208
209 for(u32bit j = 0; j != indexes.size() - 1; ++j)
210 {
211 const X509_Certificate& current_cert = certs[indexes[j]].cert;
212 time_check = validity_check(current_cert.start_time(),
213 current_cert.end_time(), current_time);
214 if(time_check < 0) return CERT_NOT_YET_VALID;
215 else if(time_check > 0) return CERT_HAS_EXPIRED;
216
217 sig_check_result = check_sig(certs[indexes[j]], certs[indexes[j+1]]);
218 if(sig_check_result != VERIFIED)
219 return sig_check_result;
220 }
221
222 return usage_check(cert, cert_usage);
223 }
224
225/*************************************************
226* Find this certificate *
227*************************************************/
228u32bit X509_Store::find_cert(const X509_DN& subject_dn,
229 const MemoryRegion<byte>& subject_key_id) const
230 {
231 for(u32bit j = 0; j != certs.size(); ++j)
232 {
233 const X509_Certificate& this_cert = certs[j].cert;
234 if(compare_ids(this_cert.subject_key_id(), subject_key_id) &&
235 this_cert.subject_dn() == subject_dn)
236 return j;
237 }
238 return NO_CERT_FOUND;
239 }
240
241/*************************************************
242* Find the parent of this certificate *
243*************************************************/
244u32bit X509_Store::find_parent_of(const X509_Certificate& cert)
245 {
246 const X509_DN issuer_dn = cert.issuer_dn();
247 const MemoryVector<byte> auth_key_id = cert.authority_key_id();
248
249 u32bit index = find_cert(issuer_dn, auth_key_id);
250
251 if(index != NO_CERT_FOUND)
252 return index;
253
254 if(auth_key_id.size())
255 {
256 for(u32bit j = 0; j != stores.size(); ++j)
257 {
258 std::vector<X509_Certificate> got = stores[j]->by_SKID(auth_key_id);
259
260 if(got.empty())
261 continue;
262
263 for(u32bit k = 0; k != got.size(); ++k)
264 add_cert(got[k]);
265 return find_cert(issuer_dn, auth_key_id);
266 }
267 }
268
269 return NO_CERT_FOUND;
270 }
271
272/*************************************************
273* Construct a chain of certificate relationships *
274*************************************************/
275X509_Code X509_Store::construct_cert_chain(const X509_Certificate& end_cert,
276 std::vector<u32bit>& indexes,
277 bool need_full_chain)
278 {
279 u32bit parent = find_parent_of(end_cert);
280
281 while(true)
282 {
283 if(parent == NO_CERT_FOUND)
284 return CERT_ISSUER_NOT_FOUND;
285 indexes.push_back(parent);
286
287 if(certs[parent].is_verified())
288 if(certs[parent].verify_result() != VERIFIED)
289 return certs[parent].verify_result();
290
291 const X509_Certificate& parent_cert = certs[parent].cert;
292 if(!parent_cert.is_CA_cert())
293 return CA_CERT_NOT_FOR_CERT_ISSUER;
294
295 if(certs[parent].is_trusted())
296 break;
297 if(parent_cert.is_self_signed())
298 return CANNOT_ESTABLISH_TRUST;
299
300 if(parent_cert.path_limit() < indexes.size() - 1)
301 return CERT_CHAIN_TOO_LONG;
302
303 parent = find_parent_of(parent_cert);
304 }
305
306 if(need_full_chain)
307 return VERIFIED;
308
309 while(true)
310 {
311 if(indexes.size() < 2)
312 break;
313
314 const u32bit cert = indexes.back();
315
316 if(certs[cert].is_verified())
317 {
318 if(certs[cert].verify_result() != VERIFIED)
319 throw Internal_Error("X509_Store::construct_cert_chain");
320 indexes.pop_back();
321 }
322 else
323 break;
324 }
325
326 const u32bit last_cert = indexes.back();
327 const u32bit parent_of_last_cert = find_parent_of(certs[last_cert].cert);
328 if(parent_of_last_cert == NO_CERT_FOUND)
329 return CERT_ISSUER_NOT_FOUND;
330 indexes.push_back(parent_of_last_cert);
331
332 return VERIFIED;
333 }
334
335/*************************************************
336* Check the CAs signature on a certificate *
337*************************************************/
338X509_Code X509_Store::check_sig(const Cert_Info& cert_info,
339 const Cert_Info& ca_cert_info) const
340 {
341 if(cert_info.is_verified())
342 return cert_info.verify_result();
343
344 const X509_Certificate& cert = cert_info.cert;
345 const X509_Certificate& ca_cert = ca_cert_info.cert;
346
347 X509_Code verify_code = check_sig(cert, ca_cert.subject_public_key());
348
349 cert_info.set_result(verify_code);
350
351 return verify_code;
352 }
353
354/*************************************************
355* Check a CA's signature *
356*************************************************/
357X509_Code X509_Store::check_sig(const X509_Object& object, Public_Key* key)
358 {
359 std::auto_ptr<Public_Key> pub_key(key);
360 std::auto_ptr<PK_Verifier> verifier;
361
362 try {
363 std::vector<std::string> sig_info =
364 split_on(OIDS::lookup(object.signature_algorithm().oid), '/');
365
366 if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
367 return SIGNATURE_ERROR;
368
369 std::string padding = sig_info[1];
370 Signature_Format format;
371 if(key->message_parts() >= 2) format = DER_SEQUENCE;
372 else format = IEEE_1363;
373
374 if(dynamic_cast<PK_Verifying_with_MR_Key*>(pub_key.get()))
375 {
376 PK_Verifying_with_MR_Key* sig_key =
377 dynamic_cast<PK_Verifying_with_MR_Key*>(pub_key.get());
378 verifier.reset(get_pk_verifier(*sig_key, padding, format));
379 }
380 else if(dynamic_cast<PK_Verifying_wo_MR_Key*>(pub_key.get()))
381 {
382 PK_Verifying_wo_MR_Key* sig_key =
383 dynamic_cast<PK_Verifying_wo_MR_Key*>(pub_key.get());
384 verifier.reset(get_pk_verifier(*sig_key, padding, format));
385 }
386 else
387 return CA_CERT_CANNOT_SIGN;
388
389 bool valid = verifier->verify_message(object.tbs_data(),
390 object.signature());
391
392 if(valid)
393 return VERIFIED;
394 else
395 return SIGNATURE_ERROR;
396 }
397 catch(Decoding_Error) { return CERT_FORMAT_ERROR; }
398 catch(Exception) {}
399
400 return UNKNOWN_X509_ERROR;
401 }
402
403/*************************************************
404* Recompute the revocation status of the certs *
405*************************************************/
406void X509_Store::recompute_revoked_info() const
407 {
408 if(revoked_info_valid)
409 return;
410
411 for(u32bit j = 0; j != certs.size(); ++j)
412 {
413 if((certs[j].is_verified()) && (certs[j].verify_result() != VERIFIED))
414 continue;
415
416 if(is_revoked(certs[j].cert))
417 certs[j].set_result(CERT_IS_REVOKED);
418 }
419
420 revoked_info_valid = true;
421 }
422
423/*************************************************
424* Check if a certificate is revoked *
425*************************************************/
426bool X509_Store::is_revoked(const X509_Certificate& cert) const
427 {
428 CRL_Data revoked_info;
429 revoked_info.issuer = cert.issuer_dn();
430 revoked_info.serial = cert.serial_number();
431 revoked_info.auth_key_id = cert.authority_key_id();
432
433 if(std::binary_search(revoked.begin(), revoked.end(), revoked_info))
434 return true;
435 return false;
436 }
437
438/*************************************************
439* Retrieve all the certificates in the store *
440*************************************************/
441std::vector<X509_Certificate>
442X509_Store::get_certs(const Search_Func& search) const
443 {
444 std::vector<X509_Certificate> found_certs;
445 for(u32bit j = 0; j != certs.size(); ++j)
446 {
447 if(search.match(certs[j].cert))
448 found_certs.push_back(certs[j].cert);
449 }
450 return found_certs;
451 }
452
453/*************************************************
454* Construct a path back to a root for this cert *
455*************************************************/
456std::vector<X509_Certificate>
457X509_Store::get_cert_chain(const X509_Certificate& cert)
458 {
459 std::vector<X509_Certificate> result;
460 std::vector<u32bit> indexes;
461 X509_Code chaining_result = construct_cert_chain(cert, indexes, true);
462
463 if(chaining_result != VERIFIED)
464 throw Invalid_State("X509_Store::get_cert_chain: Can't construct chain");
465
466 for(u32bit j = 0; j != indexes.size(); ++j)
467 result.push_back(certs[indexes[j]].cert);
468 return result;
469 }
470
471/*************************************************
472* Add a certificate store to the list of stores *
473*************************************************/
474void X509_Store::add_new_certstore(Certificate_Store* certstore)
475 {
476 stores.push_back(certstore);
477 }
478
479/*************************************************
480* Add a certificate to the store *
481*************************************************/
482void X509_Store::add_cert(const X509_Certificate& cert, bool trusted)
483 {
484 if(trusted && !cert.is_self_signed())
485 throw Invalid_Argument("X509_Store: Trusted certs must be self-signed");
486
487 if(find_cert(cert.subject_dn(), cert.subject_key_id()) == NO_CERT_FOUND)
488 {
489 revoked_info_valid = false;
490 Cert_Info info(cert, trusted);
491 certs.push_back(info);
492 }
493 else if(trusted)
494 {
495 for(u32bit j = 0; j != certs.size(); ++j)
496 {
497 const X509_Certificate& this_cert = certs[j].cert;
498 if(this_cert == cert)
499 certs[j].trusted = trusted;
500 }
501 }
502 }
503
504/*************************************************
505* Add one or more certificates to the store *
506*************************************************/
507void X509_Store::do_add_certs(DataSource& source, bool trusted)
508 {
509 while(!source.end_of_data())
510 {
511 try {
512 X509_Certificate cert(source);
513 add_cert(cert, trusted);
514 }
515 catch(Decoding_Error) {}
516 catch(Invalid_Argument) {}
517 }
518 }
519
520/*************************************************
521* Add one or more certificates to the store *
522*************************************************/
523void X509_Store::add_certs(DataSource& source)
524 {
525 do_add_certs(source, false);
526 }
527
528/*************************************************
529* Add one or more certificates to the store *
530*************************************************/
531void X509_Store::add_trusted_certs(DataSource& source)
532 {
533 do_add_certs(source, true);
534 }
535
536/*************************************************
537* Add one or more certificates to the store *
538*************************************************/
539X509_Code X509_Store::add_crl(const X509_CRL& crl)
540 {
541 s32bit time_check = validity_check(crl.this_update(), crl.next_update(),
542 system_time());
543 if(time_check < 0) return CRL_NOT_YET_VALID;
544 else if(time_check > 0) return CRL_HAS_EXPIRED;
545
546 u32bit cert_index = NO_CERT_FOUND;
547
548 for(u32bit j = 0; j != certs.size(); ++j)
549 {
550 const X509_Certificate& this_cert = certs[j].cert;
551 if(compare_ids(this_cert.subject_key_id(), crl.authority_key_id()))
552 {
553 if(this_cert.subject_dn() == crl.issuer_dn())
554 cert_index = j;
555 }
556 }
557
558 if(cert_index == NO_CERT_FOUND)
559 return CRL_ISSUER_NOT_FOUND;
560
561 const X509_Certificate& ca_cert = certs[cert_index].cert;
562
563 X509_Code verify_result = validate_cert(ca_cert, CRL_SIGNING);
564 if(verify_result != VERIFIED)
565 return verify_result;
566
567 verify_result = check_sig(crl, ca_cert.subject_public_key());
568 if(verify_result != VERIFIED)
569 return verify_result;
570
571 std::vector<CRL_Entry> revoked_certs = crl.get_revoked();
572
573 for(u32bit j = 0; j != revoked_certs.size(); ++j)
574 {
575 CRL_Data revoked_info;
576 revoked_info.issuer = crl.issuer_dn();
577 revoked_info.serial = revoked_certs[j].serial_number();
578 revoked_info.auth_key_id = crl.authority_key_id();
579
580 std::vector<CRL_Data>::iterator p =
581 std::find(revoked.begin(), revoked.end(), revoked_info);
582
583 if(revoked_certs[j].reason_code() == REMOVE_FROM_CRL)
584 {
585 if(p == revoked.end()) continue;
586 revoked.erase(p);
587 }
588 else
589 {
590 if(p != revoked.end()) continue;
591 revoked.push_back(revoked_info);
592 }
593 }
594
595 std::sort(revoked.begin(), revoked.end());
596 revoked_info_valid = false;
597
598 return VERIFIED;
599 }
600
601/*************************************************
602* PEM encode the set of certificates *
603*************************************************/
604std::string X509_Store::PEM_encode() const
605 {
606 std::string cert_store;
607 for(u32bit j = 0; j != certs.size(); ++j)
608 cert_store += certs[j].cert.PEM_encode();
609 return cert_store;
610 }
611
612/*************************************************
613* Create a Cert_Info structure *
614*************************************************/
615X509_Store::Cert_Info::Cert_Info(const X509_Certificate& c,
616 bool t) : cert(c), trusted(t)
617 {
618 checked = false;
619 result = UNKNOWN_X509_ERROR;
620 last_checked = 0;
621 }
622
623/*************************************************
624* Return the verification results *
625*************************************************/
626X509_Code X509_Store::Cert_Info::verify_result() const
627 {
628 if(!checked)
629 throw Invalid_State("Cert_Info::verify_result() called; not checked");
630 return result;
631 }
632
633/*************************************************
634* Set the verification results *
635*************************************************/
636void X509_Store::Cert_Info::set_result(X509_Code code) const
637 {
638 result = code;
639 last_checked = system_time();
640 checked = true;
641 }
642
643/*************************************************
644* Check if this certificate can be trusted *
645*************************************************/
646bool X509_Store::Cert_Info::is_trusted() const
647 {
648 return trusted;
649 }
650
651/*************************************************
652* Check if this certificate has been verified *
653*************************************************/
654bool X509_Store::Cert_Info::is_verified() const
655 {
656 if(!checked)
657 return false;
658 if(result != VERIFIED && result != CERT_NOT_YET_VALID)
659 return true;
660
661 const u32bit CACHE_TIME =
662 global_config().option_as_time("x509/cache_verify_results");
663
664 const u64bit current_time = system_time();
665
666 if(current_time > last_checked + CACHE_TIME)
667 checked = false;
668
669 return checked;
670 }
671
672}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status