aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-02-06 14:12:35 +0000
committerlloyd <[email protected]>2012-02-06 14:12:35 +0000
commitcd58927000ef86eacc9de5b80f361d4d05e71731 (patch)
tree975d2e50e77567d14ea3d24e6ebaf24a9e4d7c3b
parent03bc906a6a94d236f192fa3b1bb370c013fc753a (diff)
Fully working path validation. Even fixes the cases in PKITS where we
got the answer wrong before. Still no policy or name constraints support, though.
-rw-r--r--checks/nist_tests/Makefile4
-rw-r--r--checks/nist_tests/x509test.cpp58
-rw-r--r--checks/x509.cpp6
-rw-r--r--src/asn1/x509_dn.cpp31
-rw-r--r--src/asn1/x509_dn.h3
-rw-r--r--src/cert/certstore/certstor.cpp19
-rw-r--r--src/cert/certstore/certstor.h14
-rw-r--r--src/cert/x509cert/x509_ext.h2
-rw-r--r--src/cert/x509cert/x509_obj.cpp5
-rw-r--r--src/cert/x509cert/x509cert.cpp10
-rw-r--r--src/cert/x509cert/x509cert.h10
-rw-r--r--src/cert/x509crl/crl_ent.h20
-rw-r--r--src/cert/x509crl/x509_crl.cpp38
-rw-r--r--src/cert/x509crl/x509_crl.h7
-rw-r--r--src/cert/x509path/x509path.cpp186
-rw-r--r--src/cert/x509path/x509path.h48
-rw-r--r--src/pubkey/pubkey_enums.h20
17 files changed, 351 insertions, 130 deletions
diff --git a/checks/nist_tests/Makefile b/checks/nist_tests/Makefile
index 96c958dd7..52dc340c9 100644
--- a/checks/nist_tests/Makefile
+++ b/checks/nist_tests/Makefile
@@ -1,9 +1,9 @@
-BOTAN_CONFIG=botan-config
+BOTAN_CONFIG=../../build/botan-config-1.10
CC=g++
FLAGS=-g -Os -W -Wall -ansi
-LDFLAGS=$(shell $(BOTAN_CONFIG) --libs)
+LDFLAGS=$(shell $(BOTAN_CONFIG) --libs) -L../.. -lbotan-1.10
CFLAGS=$(shell $(BOTAN_CONFIG) --cflags) -I../../build/include
x509test: x509test.cpp
diff --git a/checks/nist_tests/x509test.cpp b/checks/nist_tests/x509test.cpp
index 66b274c6c..e4d55d252 100644
--- a/checks/nist_tests/x509test.cpp
+++ b/checks/nist_tests/x509test.cpp
@@ -20,12 +20,12 @@ using namespace Botan;
std::vector<std::string> dir_listing(const std::string&);
-void run_one_test(u32bit, X509_Code,
+void run_one_test(u32bit, X509_Path_Validation_Code,
std::string, std::string,
std::vector<std::string>,
std::vector<std::string>);
-std::map<u32bit, X509_Code> expected_results;
+std::map<u32bit, X509_Path_Validation_Code> expected_results;
u32bit unexp_failure, unexp_success, wrong_error, skipped;
@@ -96,7 +96,7 @@ int main()
return 0;
}
-void run_one_test(u32bit test_no, X509_Code expected,
+void run_one_test(u32bit test_no, X509_Path_Validation_Code expected,
std::string root_cert, std::string to_verify,
std::vector<std::string> certs,
std::vector<std::string> crls)
@@ -104,16 +104,14 @@ void run_one_test(u32bit test_no, X509_Code expected,
std::cout << "Processing test #" << test_no << "... ";
std::cout.flush();
- X509_Code result = VERIFIED;
+ Certificate_Store_In_Memory store;
- Certificate_Store_Memory store;
-
- store.add_cert(X509_Certificate(root_cert));
+ store.add_certificate(X509_Certificate(root_cert));
X509_Certificate end_user(to_verify);
for(size_t j = 0; j != certs.size(); j++)
- store.add_cert(X509_Certificate(certs[j]));
+ store.add_certificate(X509_Certificate(certs[j]));
for(size_t j = 0; j != crls.size(); j++)
{
@@ -133,18 +131,9 @@ void run_one_test(u32bit test_no, X509_Code expected,
store.add_crl(crl);
}
- /* if everything has gone well up until now */
-
- if(result == VERIFIED)
- {
- result = store.validate_cert(end_user);
-
- X509_Code result2 = store.validate_cert(end_user);
+ Path_Validation_Result validation_result = x509_path_validate(end_user, store);
- if(result != result2)
- std::cout << "Two runs, two answers: " << result << " "
- << result2 << std::endl;
- }
+ X509_Path_Validation_Code result = validation_result.validation_result;
if(result == expected)
{
@@ -232,15 +221,7 @@ void populate_expected_results()
expected_results[17] = VERIFIED;
expected_results[18] = VERIFIED;
- /************* CHANGE OF TEST RESULT FOR TEST #19 ************************
- One of the certificates has no attached CRL. By strict X.509 rules, if
- there is no good CRL in hand, then the certificate shouldn't be used for
- CA stuff. But while this is usually a good idea, it interferes with simple
- uses of certificates which shouldn't (IMO) force the use of CRLs. There is
- no assigned error code for this scenario because I don't consider it to be
- an error (probably would be something like NO_REVOCATION_DATA_AVAILABLE)
- **************************************************************************/
- expected_results[19] = VERIFIED;
+ expected_results[19] = CRL_NOT_FOUND;
expected_results[20] = CERT_IS_REVOKED;
expected_results[21] = CERT_IS_REVOKED;
@@ -314,23 +295,10 @@ void populate_expected_results()
expected_results[64] = SIGNATURE_ERROR;
- /************ CHANGE OF TEST RESULT FOR TEST #65 *************************
- I cannot figure out what exactly the problem here is supposed to be;
- looking at it by hand, everything seems fine. If someone can explain I
- would be happy to listen.
- ************************************************************************/
- expected_results[65] = VERIFIED;
- expected_results[66] = CRL_ISSUER_NOT_FOUND;
-
- /************ CHANGE OF TEST RESULT FOR TEST #67 *************************
- The test docs say this should be verified. However, the problem being that
- there is an extra CRL with an unknown issuer. Returning VERIFIED in this
- case is obviously bad, since the user may well want to know that the CRL
- in question has no known issuer. So we return CRL_ISSUER_NOT_FOUND instead
- of VERIFIED. The actual certificate path of course still verifies, but
- it's kind of an all-or-nothing testing procedure.
- ************************************************************************/
- expected_results[67] = CRL_ISSUER_NOT_FOUND;
+ expected_results[65] = CRL_NOT_FOUND;
+ expected_results[66] = CRL_NOT_FOUND;
+
+ expected_results[67] = VERIFIED;
expected_results[68] = CERT_IS_REVOKED;
expected_results[69] = CERT_IS_REVOKED;
diff --git a/checks/x509.cpp b/checks/x509.cpp
index 919fa3508..9ae295d35 100644
--- a/checks/x509.cpp
+++ b/checks/x509.cpp
@@ -191,7 +191,7 @@ void do_x509_tests(RandomNumberGenerator& rng)
X509_CRL crl1 = ca.new_crl(rng);
/* Verify the certs */
- Certificate_Store_Memory store;
+ Certificate_Store_In_Memory store;
store.add_certificate(ca_cert);
@@ -199,11 +199,11 @@ void do_x509_tests(RandomNumberGenerator& rng)
Path_Validation_Result result_u1 = x509_path_validate(user1_cert, store);
if(result_u1.validation_result != VERIFIED)
- std::cout << "\nFAILED: User cert #1 did not validate" << std::endl;
+ std::cout << "\nFAILED: User cert #1 did not validate - " << result_u1.validation_result << std::endl;
Path_Validation_Result result_u2 = x509_path_validate(user2_cert, store);
if(result_u2.validation_result != VERIFIED)
- std::cout << "\nFAILED: User cert #2 did not validate" << std::endl;
+ std::cout << "\nFAILED: User cert #2 did not validate - " << result_u2.validation_result << std::endl;
store.add_crl(crl1);
diff --git a/src/asn1/x509_dn.cpp b/src/asn1/x509_dn.cpp
index f91303296..37eecc6a3 100644
--- a/src/asn1/x509_dn.cpp
+++ b/src/asn1/x509_dn.cpp
@@ -11,6 +11,7 @@
#include <botan/parsing.h>
#include <botan/internal/stl_util.h>
#include <botan/oids.h>
+#include <iostream>
namespace Botan {
@@ -293,4 +294,34 @@ void X509_DN::decode_from(BER_Decoder& source)
dn_bits = bits;
}
+namespace {
+
+std::string to_short_form(const std::string& long_id)
+ {
+ if(long_id == "X520.CommonName")
+ return "CN";
+
+ if(long_id == "X520.Organization")
+ return "O";
+
+ if(long_id == "X520.OrganizationalUnit")
+ return "OU";
+
+ return long_id;
+ }
+
+}
+
+std::ostream& operator<<(std::ostream& out, const X509_DN& dn)
+ {
+ std::multimap<std::string, std::string> contents = dn.contents();
+
+ for(std::multimap<std::string, std::string>::const_iterator i = contents.begin();
+ i != contents.end(); ++i)
+ {
+ out << to_short_form(i->first) << "=" << i->second << ' ';
+ }
+ return out;
+ }
+
}
diff --git a/src/asn1/x509_dn.h b/src/asn1/x509_dn.h
index 3f63eb49c..de44f8c78 100644
--- a/src/asn1/x509_dn.h
+++ b/src/asn1/x509_dn.h
@@ -12,6 +12,7 @@
#include <botan/asn1_oid.h>
#include <botan/asn1_str.h>
#include <map>
+#include <iosfwd>
namespace Botan {
@@ -48,6 +49,8 @@ bool BOTAN_DLL operator==(const X509_DN&, const X509_DN&);
bool BOTAN_DLL operator!=(const X509_DN&, const X509_DN&);
bool BOTAN_DLL operator<(const X509_DN&, const X509_DN&);
+BOTAN_DLL std::ostream& operator<<(std::ostream& out, const X509_DN& dn);
+
}
#endif
diff --git a/src/cert/certstore/certstor.cpp b/src/cert/certstore/certstor.cpp
index 3cba2f39e..7aa528d04 100644
--- a/src/cert/certstore/certstor.cpp
+++ b/src/cert/certstore/certstor.cpp
@@ -9,12 +9,7 @@
namespace Botan {
-Certificate_Store* Certificate_Store_Memory::clone() const
- {
- return new Certificate_Store_Memory(*this);
- }
-
-void Certificate_Store_Memory::add_certificate(const X509_Certificate& cert)
+void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
{
for(size_t i = 0; i != certs.size(); ++i)
{
@@ -26,7 +21,7 @@ void Certificate_Store_Memory::add_certificate(const X509_Certificate& cert)
}
std::vector<X509_Certificate>
-Certificate_Store_Memory::find_cert_by_subject_and_key_id(
+Certificate_Store_In_Memory::find_cert_by_subject_and_key_id(
const X509_DN& subject_dn,
const MemoryRegion<byte>& key_id) const
{
@@ -50,7 +45,7 @@ Certificate_Store_Memory::find_cert_by_subject_and_key_id(
return result;
}
-void Certificate_Store_Memory::add_crl(const X509_CRL& crl)
+void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
{
X509_DN crl_issuer = crl.issuer_dn();
@@ -59,11 +54,9 @@ void Certificate_Store_Memory::add_crl(const X509_CRL& crl)
// Found an update of a previously existing one; replace it
if(crls[i].issuer_dn() == crl_issuer)
{
- if(crls[i].this_update() < crl.this_update())
- {
+ if(crls[i].this_update() <= crl.this_update())
crls[i] = crl;
- return;
- }
+ return;
}
}
@@ -72,7 +65,7 @@ void Certificate_Store_Memory::add_crl(const X509_CRL& crl)
}
std::vector<X509_CRL>
-Certificate_Store_Memory::find_crl_by_subject_and_key_id(
+Certificate_Store_In_Memory::find_crl_by_issuer_and_key_id(
const X509_DN& issuer_dn,
const MemoryRegion<byte>& key_id) const
{
diff --git a/src/cert/certstore/certstor.h b/src/cert/certstore/certstor.h
index 374013984..604541d52 100644
--- a/src/cert/certstore/certstor.h
+++ b/src/cert/certstore/certstor.h
@@ -21,8 +21,6 @@ class BOTAN_DLL Certificate_Store
public:
virtual ~Certificate_Store() {}
- virtual Certificate_Store* clone() const = 0;
-
/**
* Add a certificate; this may fail if the store is write-only
*/
@@ -45,7 +43,7 @@ class BOTAN_DLL Certificate_Store
* Find CRLs by the DN and key id of the issuer
*/
virtual std::vector<X509_CRL>
- find_crl_by_subject_and_key_id(
+ find_crl_by_issuer_and_key_id(
const X509_DN& issuer_dn,
const MemoryRegion<byte>& key_id) const = 0;
};
@@ -53,11 +51,9 @@ class BOTAN_DLL Certificate_Store
/**
* In Memory Certificate Store
*/
-class BOTAN_DLL Certificate_Store_Memory : public Certificate_Store
+class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store
{
public:
- Certificate_Store* clone() const;
-
void add_certificate(const X509_Certificate& cert);
void add_crl(const X509_CRL& crl);
@@ -66,13 +62,13 @@ class BOTAN_DLL Certificate_Store_Memory : public Certificate_Store
const X509_DN& subject_dn,
const MemoryRegion<byte>& key_id) const;
- std::vector<X509_CRL> find_crl_by_subject_and_key_id(
+ std::vector<X509_CRL> find_crl_by_issuer_and_key_id(
const X509_DN& issuer_dn,
const MemoryRegion<byte>& key_id) const;
- Certificate_Store_Memory() {}
+ Certificate_Store_In_Memory() {}
private:
- // TODO: Add indexing on the DN and key id to avoid linear search?
+ // TODO: Add indexing on the DN and key id to avoid linear search
std::vector<X509_Certificate> certs;
std::vector<X509_CRL> crls;
};
diff --git a/src/cert/x509cert/x509_ext.h b/src/cert/x509cert/x509_ext.h
index 8799c5921..714e29562 100644
--- a/src/cert/x509cert/x509_ext.h
+++ b/src/cert/x509cert/x509_ext.h
@@ -12,7 +12,7 @@
#include <botan/asn1_oid.h>
#include <botan/asn1_obj.h>
#include <botan/datastor.h>
-#include <botan/pubkey_enums.h>
+#include <botan/crl_ent.h>
namespace Botan {
diff --git a/src/cert/x509cert/x509_obj.cpp b/src/cert/x509cert/x509_obj.cpp
index 13193f09c..c58081225 100644
--- a/src/cert/x509cert/x509_obj.cpp
+++ b/src/cert/x509cert/x509_obj.cpp
@@ -16,6 +16,8 @@
#include <algorithm>
#include <memory>
+#include <stdio.h>
+
namespace Botan {
/*
@@ -192,8 +194,9 @@ bool X509_Object::check_signature(Public_Key& pub_key) const
return verifier.verify_message(tbs_data(), signature());
}
- catch(...)
+ catch(std::exception& e)
{
+ printf("Failure during validation %s\n", e.what());
return false;
}
}
diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp
index 7d9370f2a..52115a1a8 100644
--- a/src/cert/x509cert/x509cert.cpp
+++ b/src/cert/x509cert/x509cert.cpp
@@ -206,9 +206,15 @@ bool X509_Certificate::is_CA_cert() const
{
if(!subject.get1_u32bit("X509v3.BasicConstraints.is_ca"))
return false;
- if((constraints() & KEY_CERT_SIGN) || (constraints() == NO_CONSTRAINTS))
+
+ return allowed_usage(KEY_CERT_SIGN);
+ }
+
+bool X509_Certificate::allowed_usage(Key_Constraints restriction) const
+ {
+ if(constraints() == NO_CONSTRAINTS)
return true;
- return false;
+ return (constraints() & restriction);
}
/*
diff --git a/src/cert/x509cert/x509cert.h b/src/cert/x509cert/x509cert.h
index 8798ef1c2..d25b97694 100644
--- a/src/cert/x509cert/x509cert.h
+++ b/src/cert/x509cert/x509cert.h
@@ -23,10 +23,10 @@ namespace Botan {
class BOTAN_DLL X509_Certificate : public X509_Object
{
public:
- /**
- * Get the public key associated with this certificate.
- * @return subject public key of this certificate
- */
+ /**
+ * Get the public key associated with this certificate.
+ * @return subject public key of this certificate
+ */
Public_Key* subject_public_key() const;
/**
@@ -111,6 +111,8 @@ class BOTAN_DLL X509_Certificate : public X509_Object
*/
bool is_CA_cert() const;
+ bool allowed_usage(Key_Constraints restriction) const;
+
/**
* Get the path limit as defined in the BasicConstraints extension of
* this certificate.
diff --git a/src/cert/x509crl/crl_ent.h b/src/cert/x509crl/crl_ent.h
index b3e696a86..ae9535484 100644
--- a/src/cert/x509crl/crl_ent.h
+++ b/src/cert/x509crl/crl_ent.h
@@ -13,6 +13,26 @@
namespace Botan {
/**
+* X.509v2 CRL Reason Code.
+*/
+enum CRL_Code {
+ UNSPECIFIED = 0,
+ KEY_COMPROMISE = 1,
+ CA_COMPROMISE = 2,
+ AFFILIATION_CHANGED = 3,
+ SUPERSEDED = 4,
+ CESSATION_OF_OPERATION = 5,
+ CERTIFICATE_HOLD = 6,
+ REMOVE_FROM_CRL = 8,
+ PRIVLEDGE_WITHDRAWN = 9,
+ AA_COMPROMISE = 10,
+
+ DELETE_CRL_ENTRY = 0xFF00,
+ OCSP_GOOD = 0xFF01,
+ OCSP_UNKNOWN = 0xFF02
+};
+
+/**
* This class represents CRL entries
*/
class BOTAN_DLL CRL_Entry : public ASN1_Object
diff --git a/src/cert/x509crl/x509_crl.cpp b/src/cert/x509crl/x509_crl.cpp
index 01fce4c52..9c6b891c7 100644
--- a/src/cert/x509crl/x509_crl.cpp
+++ b/src/cert/x509crl/x509_crl.cpp
@@ -7,6 +7,7 @@
#include <botan/x509_crl.h>
#include <botan/x509_ext.h>
+#include <botan/x509cert.h>
#include <botan/ber_dec.h>
#include <botan/parsing.h>
#include <botan/bigint.h>
@@ -32,6 +33,43 @@ X509_CRL::X509_CRL(const std::string& in, bool touc) :
do_decode();
}
+/**
+* Check if this particular certificate is listed in the CRL
+*/
+bool X509_CRL::is_revoked(const X509_Certificate& cert) const
+ {
+ /*
+ If the cert wasn't issued by the CRL issuer, it's possible the cert
+ is revoked, but not by this CRL. Maybe throw an exception instead?
+ */
+ if(cert.issuer_dn() != issuer_dn())
+ return false;
+
+ MemoryVector<byte> crl_akid = authority_key_id();
+ MemoryVector<byte> cert_akid = cert.authority_key_id();
+
+ if(!crl_akid.empty() && !cert_akid.empty())
+ if(crl_akid != cert_akid)
+ return false;
+
+ MemoryVector<byte> cert_serial = cert.serial_number();
+
+ bool is_revoked = false;
+
+ for(size_t i = 0; i != revoked.size(); ++i)
+ {
+ if(cert_serial == revoked[i].serial_number())
+ {
+ if(revoked[i].reason_code() == REMOVE_FROM_CRL)
+ is_revoked = false;
+ else
+ is_revoked = true;
+ }
+ }
+
+ return is_revoked;
+ }
+
/*
* Decode the TBSCertList data
*/
diff --git a/src/cert/x509crl/x509_crl.h b/src/cert/x509crl/x509_crl.h
index c2b3c4f5c..55eb8424b 100644
--- a/src/cert/x509crl/x509_crl.h
+++ b/src/cert/x509crl/x509_crl.h
@@ -14,6 +14,8 @@
namespace Botan {
+class X509_Certificate;
+
/**
* This class represents X.509 Certificate Revocation Lists (CRLs).
*/
@@ -30,6 +32,11 @@ class BOTAN_DLL X509_CRL : public X509_Object
};
/**
+ * Check if this particular certificate is listed in the CRL
+ */
+ bool is_revoked(const X509_Certificate& cert) const;
+
+ /**
* Get the entries of this CRL in the form of a vector.
* @return vector containing the entries of this CRL.
*/
diff --git a/src/cert/x509path/x509path.cpp b/src/cert/x509path/x509path.cpp
index d0153309c..e18c3b2f8 100644
--- a/src/cert/x509path/x509path.cpp
+++ b/src/cert/x509path/x509path.cpp
@@ -15,33 +15,193 @@
namespace Botan {
-Path_Validation_Result x509_path_validate(
- const X509_Certificate& cert,
- const std::vector<Certificate_Store*>& certstores)
+namespace {
+
+class PKIX_Validation_Failure : public std::exception
+ {
+ public:
+ PKIX_Validation_Failure(X509_Path_Validation_Code code) : m_code(code) {}
+
+ X509_Path_Validation_Code code() const { return m_code; }
+
+ const char* what() { return "PKIX validation failed"; }
+ private:
+ X509_Path_Validation_Code m_code;
+ };
+
+X509_Certificate find_issuing_cert(const X509_Certificate& cert,
+ const std::vector<Certificate_Store*>& certstores)
{
const X509_DN issuer_dn = cert.issuer_dn();
const MemoryVector<byte> auth_key_id = cert.authority_key_id();
- Path_Validation_Result result;
+ for(size_t i = 0; i != certstores.size(); ++i)
+ {
+ std::vector<X509_Certificate> certs =
+ certstores[i]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id);
- std::vector<X509_Certificate> cert_path;
+ if(certs.size() == 0)
+ throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ else if(certs.size() > 1)
+ throw PKIX_Validation_Failure(CERT_MULTIPLE_ISSUERS_FOUND);
- cert_path.push_back(cert);
+ return certs[0];
+ }
+
+ throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ }
+
+std::vector<X509_CRL> find_crls_from(const X509_Certificate& cert,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ const X509_DN issuer_dn = cert.subject_dn();
+ const MemoryVector<byte> auth_key_id = cert.subject_key_id();
for(size_t i = 0; i != certstores.size(); ++i)
{
- std::vector<X509_Certificate> got =
- certstores[i]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id);
+ std::vector<X509_CRL> crl =
+ certstores[i]->find_crl_by_issuer_and_key_id(issuer_dn, auth_key_id);
+
+ if(!crl.empty())
+ return crl;
+ }
+
+ return std::vector<X509_CRL>();
+ }
+
+}
+
+std::set<std::string> Path_Validation_Result::trusted_hashes() const
+ {
+ std::set<std::string> hashes;
+ for(size_t i = 0; i != cert_path.size(); ++i)
+ hashes.insert(cert_path[i].hash_used_for_signature());
+ return hashes;
+ }
+
+Path_Validation_Result x509_path_validate(
+ const X509_Certificate& end_cert,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ std::vector<X509_Certificate> certs;
+ certs.push_back(end_cert);
+ return x509_path_validate(certs, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ Certificate_Store& store)
+ {
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(&store);
+
+ return x509_path_validate(end_certs, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const X509_Certificate& end_cert,
+ Certificate_Store& store)
+ {
+ std::vector<X509_Certificate> certs;
+ certs.push_back(end_cert);
+
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(&store);
+
+ return x509_path_validate(certs, certstores);
+ }
+
+Path_Validation_Result
+x509_path_validate(const std::vector<X509_Certificate>& end_certs,
+ const std::vector<Certificate_Store*>& certstores)
+ {
+ Path_Validation_Result r;
+
+ r.cert_path = end_certs;
- // What to do if it returns more than one match?
- if(got.size() == 1)
+ try
+ {
+ // iterate until we reach a root or cannot find the issuer
+
+ while(!r.cert_path.back().is_self_signed())
{
- cert_path.push_back(got[0]);
- break;
+ X509_Certificate cert = find_issuing_cert(r.cert_path.back(),
+ certstores);
+
+ r.cert_path.push_back(cert);
}
+
+ /*
+ for(size_t i = 0; i != r.cert_path.size(); ++i)
+ std::cout << "Cert " << i << " = " << r.cert_path[i].subject_dn() << "\n";
+ */
+
+ X509_Time current_time(system_time());
+
+ for(size_t i = 0; i != r.cert_path.size(); ++i)
+ {
+ const X509_Certificate& subject = r.cert_path[i];
+
+ // Check all certs for valid time range
+ if(current_time < X509_Time(subject.start_time()))
+ throw PKIX_Validation_Failure(CERT_NOT_YET_VALID);
+
+ if(current_time > X509_Time(subject.end_time()))
+ throw PKIX_Validation_Failure(CERT_HAS_EXPIRED);
+
+ const bool at_self_signed_root = (i == r.cert_path.size() - 1);
+
+ const X509_Certificate& issuer =
+ r.cert_path[at_self_signed_root ? (i) : (i + 1)];
+
+ // Check issuer constraints
+ if(!issuer.is_CA_cert()) // require this for self-signed end-entity?
+ throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CERT_ISSUER);
+
+ if(issuer.path_limit() < i)
+ throw PKIX_Validation_Failure(CERT_CHAIN_TOO_LONG);
+
+ if(subject.check_signature(issuer.subject_public_key()) == false)
+ throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+ }
+
+ r.validation_result = VERIFIED;
+
+ for(size_t i = 1; i != r.cert_path.size(); ++i)
+ {
+ const X509_Certificate& subject = r.cert_path[i-1];
+ const X509_Certificate& ca = r.cert_path[i];
+
+ std::vector<X509_CRL> crls = find_crls_from(ca, certstores);
+
+ if(crls.empty())
+ throw PKIX_Validation_Failure(CRL_NOT_FOUND);
+
+ const X509_CRL& crl = crls[0];
+
+ if(!ca.allowed_usage(CRL_SIGN))
+ throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CRL_ISSUER);
+
+ if(current_time < X509_Time(crl.this_update()))
+ throw PKIX_Validation_Failure(CRL_NOT_YET_VALID);
+
+ if(current_time > X509_Time(crl.next_update()))
+ throw PKIX_Validation_Failure(CRL_HAS_EXPIRED);
+
+ if(crl.check_signature(ca.subject_public_key()) == false)
+ throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+
+ if(crl.is_revoked(subject))
+ throw PKIX_Validation_Failure(CERT_IS_REVOKED);
+ }
+
+ }
+ catch(PKIX_Validation_Failure& e)
+ {
+ r.validation_result = e.code();
}
- return result;
+ return r;
}
}
diff --git a/src/cert/x509path/x509path.h b/src/cert/x509path/x509path.h
index 57e4764cc..b32a69162 100644
--- a/src/cert/x509path/x509path.h
+++ b/src/cert/x509path/x509path.h
@@ -34,6 +34,7 @@ enum X509_Path_Validation_Code {
CERT_HAS_EXPIRED,
CERT_IS_REVOKED,
+ CRL_NOT_FOUND,
CRL_FORMAT_ERROR,
CRL_ISSUER_NOT_FOUND,
CRL_NOT_YET_VALID,
@@ -44,38 +45,51 @@ enum X509_Path_Validation_Code {
CA_CERT_NOT_FOR_CRL_ISSUER
};
-enum X509_Cert_Usage {
- NO_RESTRICTIONS = 0x00,
- TLS_SERVER = 0x01,
- TLS_CLIENT = 0x02,
- CODE_SIGNING = 0x04,
- EMAIL_PROTECTION = 0x08,
- TIME_STAMPING = 0x10,
- CRL_SIGNING = 0x20
-};
+ enum Usage_Restrictions {
+ NO_RESTRICTIONS = 0x00,
+ TLS_SERVER = 0x01,
+ TLS_CLIENT = 0x02,
+ CODE_SIGNING = 0x04,
+ EMAIL_PROTECTION = 0x08,
+ TIME_STAMPING = 0x10,
+ CRL_SIGNING = 0x20
+ };
class Path_Validation_Result
{
public:
+ Path_Validation_Result() :
+ validation_result(UNKNOWN_X509_ERROR),
+ allowed_usages(NO_RESTRICTIONS)
+ {}
+
X509_Path_Validation_Code validation_result;
- X509_Cert_Usage allowed_usages;
+ Usage_Restrictions allowed_usages;
+
std::vector<X509_Certificate> cert_path;
+ /**
+ * Returns the set of hash functions you are implicitly
+ * trusting by trusting this result.
+ */
std::set<std::string> trusted_hashes() const;
};
Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ const std::vector<Certificate_Store*>& certstores);
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
const X509_Certificate& end_cert,
const std::vector<Certificate_Store*>& certstores);
-inline Path_Validation_Result x509_path_validate(
+Path_Validation_Result BOTAN_DLL x509_path_validate(
const X509_Certificate& end_cert,
- Certificate_Store& store)
- {
- std::vector<Certificate_Store*> store_vec;
- store_vec.push_back(&store);
- return x509_path_validate(end_cert, store_vec);
- }
+ Certificate_Store& store);
+
+Path_Validation_Result BOTAN_DLL x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ Certificate_Store& store);
}
diff --git a/src/pubkey/pubkey_enums.h b/src/pubkey/pubkey_enums.h
index 99f804e0a..c64a8493d 100644
--- a/src/pubkey/pubkey_enums.h
+++ b/src/pubkey/pubkey_enums.h
@@ -37,26 +37,6 @@ void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&);
}
-/**
-* X.509v2 CRL Reason Code.
-*/
-enum CRL_Code {
- UNSPECIFIED = 0,
- KEY_COMPROMISE = 1,
- CA_COMPROMISE = 2,
- AFFILIATION_CHANGED = 3,
- SUPERSEDED = 4,
- CESSATION_OF_OPERATION = 5,
- CERTIFICATE_HOLD = 6,
- REMOVE_FROM_CRL = 8,
- PRIVLEDGE_WITHDRAWN = 9,
- AA_COMPROMISE = 10,
-
- DELETE_CRL_ENTRY = 0xFF00,
- OCSP_GOOD = 0xFF01,
- OCSP_UNKNOWN = 0xFF02
-};
-
/*
* Various Other Enumerations
*/