aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
*/