aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-03-28 23:24:38 +0000
committerlloyd <[email protected]>2012-03-28 23:24:38 +0000
commit0da08c29d55ddea710767267af3ec690e91a77a6 (patch)
treeedcf93c880c2f83fb91964f554637b77c94810f5
parentd4050e6b838acfd9552b4ab137fbf0717ff1e0ca (diff)
Pass a class to the validation function that represents any
restrictions on the validation process. Currently these are if revocation information (CRL or hypothetically OCSP) is required, and what hashes to trust. Default trusted hashes are SHA-1 and SHA-2. This will also be used for policy restrictions, likely other things. The result enum is now a member of Path_Validation_Result Remove the usage restrictions enum. It is easier, for applications that actually care about one of these, to just check the extended constraint attribute on the final result, if everything else validates.
-rw-r--r--checks/nist_tests/x509test.cpp192
-rw-r--r--checks/x509.cpp43
-rw-r--r--src/cert/x509/x509path.cpp133
-rw-r--r--src/cert/x509/x509path.h110
4 files changed, 292 insertions, 186 deletions
diff --git a/checks/nist_tests/x509test.cpp b/checks/nist_tests/x509test.cpp
index e4d55d252..18ed26534 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_Path_Validation_Code,
+void run_one_test(u32bit, Path_Validation_Result::Code,
std::string, std::string,
std::vector<std::string>,
std::vector<std::string>);
-std::map<u32bit, X509_Path_Validation_Code> expected_results;
+std::map<u32bit, Path_Validation_Result::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_Path_Validation_Code expected,
+void run_one_test(u32bit test_no, Path_Validation_Result::Code expected,
std::string root_cert, std::string to_verify,
std::vector<std::string> certs,
std::vector<std::string> crls)
@@ -131,9 +131,14 @@ void run_one_test(u32bit test_no, X509_Path_Validation_Code expected,
store.add_crl(crl);
}
- Path_Validation_Result validation_result = x509_path_validate(end_user, store);
+ Path_Validation_Restrictions restrictions(true);
- X509_Path_Validation_Code result = validation_result.validation_result;
+ Path_Validation_Result validation_result =
+ x509_path_validate(end_user,
+ restrictions,
+ store);
+
+ Path_Validation_Result::Code result = validation_result.result();
if(result == expected)
{
@@ -141,12 +146,12 @@ void run_one_test(u32bit test_no, X509_Path_Validation_Code expected,
return;
}
- if(expected == VERIFIED)
+ if(expected == Path_Validation_Result::VERIFIED)
{
std::cout << "unexpected failure: " << result << std::endl;
unexp_failure++;
}
- else if(result == VERIFIED)
+ else if(result == Path_Validation_Result::VERIFIED)
{
std::cout << "unexpected success: " << expected << std::endl;
unexp_success++;
@@ -198,46 +203,43 @@ std::vector<std::string> dir_listing(const std::string& dir_name)
void populate_expected_results()
{
/* OK, not a super great way of doing this... */
- expected_results[1] = VERIFIED;
- expected_results[2] = SIGNATURE_ERROR;
- expected_results[3] = SIGNATURE_ERROR;
- expected_results[4] = VERIFIED;
- expected_results[5] = CERT_NOT_YET_VALID;
- expected_results[6] = CERT_NOT_YET_VALID;
- expected_results[7] = VERIFIED;
- expected_results[8] = CERT_NOT_YET_VALID;
- expected_results[9] = CERT_HAS_EXPIRED;
- expected_results[10] = CERT_HAS_EXPIRED;
- expected_results[11] = CERT_HAS_EXPIRED;
- expected_results[12] = VERIFIED;
- expected_results[13] = CERT_ISSUER_NOT_FOUND;
-
- // FIXME: we get the answer right for the wrong reason
- // ummm... I don't know if that is still true. I wish I had thought to
- // write down exactly what this 'wrong reason' was in the first place.
- expected_results[14] = CERT_ISSUER_NOT_FOUND;
- expected_results[15] = VERIFIED;
- expected_results[16] = VERIFIED;
- expected_results[17] = VERIFIED;
- expected_results[18] = VERIFIED;
-
- expected_results[19] = CRL_NOT_FOUND;
- expected_results[20] = CERT_IS_REVOKED;
- expected_results[21] = CERT_IS_REVOKED;
-
- expected_results[22] = CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[23] = CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[24] = VERIFIED;
- expected_results[25] = CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[26] = VERIFIED;
- expected_results[27] = VERIFIED;
- expected_results[28] = CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[29] = CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[30] = VERIFIED;
-
- expected_results[31] = CA_CERT_NOT_FOR_CRL_ISSUER;
- expected_results[32] = CA_CERT_NOT_FOR_CRL_ISSUER;
- expected_results[33] = VERIFIED;
+ expected_results[1] = Path_Validation_Result::VERIFIED;
+ expected_results[2] = Path_Validation_Result::SIGNATURE_ERROR;
+ expected_results[3] = Path_Validation_Result::SIGNATURE_ERROR;
+ expected_results[4] = Path_Validation_Result::VERIFIED;
+ expected_results[5] = Path_Validation_Result::CERT_NOT_YET_VALID;
+ expected_results[6] = Path_Validation_Result::CERT_NOT_YET_VALID;
+ expected_results[7] = Path_Validation_Result::VERIFIED;
+ expected_results[8] = Path_Validation_Result::CERT_NOT_YET_VALID;
+ expected_results[9] = Path_Validation_Result::CERT_HAS_EXPIRED;
+ expected_results[10] = Path_Validation_Result::CERT_HAS_EXPIRED;
+ expected_results[11] = Path_Validation_Result::CERT_HAS_EXPIRED;
+ expected_results[12] = Path_Validation_Result::VERIFIED;
+ expected_results[13] = Path_Validation_Result::CERT_ISSUER_NOT_FOUND;
+
+ expected_results[14] = Path_Validation_Result::CERT_ISSUER_NOT_FOUND;
+ expected_results[15] = Path_Validation_Result::VERIFIED;
+ expected_results[16] = Path_Validation_Result::VERIFIED;
+ expected_results[17] = Path_Validation_Result::VERIFIED;
+ expected_results[18] = Path_Validation_Result::VERIFIED;
+
+ expected_results[19] = Path_Validation_Result::CRL_NOT_FOUND;
+ expected_results[20] = Path_Validation_Result::CERT_IS_REVOKED;
+ expected_results[21] = Path_Validation_Result::CERT_IS_REVOKED;
+
+ expected_results[22] = Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[23] = Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[24] = Path_Validation_Result::VERIFIED;
+ expected_results[25] = Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[26] = Path_Validation_Result::VERIFIED;
+ expected_results[27] = Path_Validation_Result::VERIFIED;
+ expected_results[28] = Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[29] = Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[30] = Path_Validation_Result::VERIFIED;
+
+ expected_results[31] = Path_Validation_Result::CA_CERT_NOT_FOR_CRL_ISSUER;
+ expected_results[32] = Path_Validation_Result::CA_CERT_NOT_FOR_CRL_ISSUER;
+ expected_results[33] = Path_Validation_Result::VERIFIED;
/*
Policy tests: a little trickier because there are other inputs
@@ -259,54 +261,54 @@ void populate_expected_results()
This provides reasonably good coverage of the possible outcomes.
*/
- expected_results[34] = VERIFIED;
- expected_results[35] = VERIFIED;
- expected_results[36] = VERIFIED;
- expected_results[37] = VERIFIED;
- expected_results[38] = VERIFIED;
- expected_results[39] = VERIFIED;
- expected_results[40] = VERIFIED;
- expected_results[41] = VERIFIED;
- expected_results[42] = VERIFIED;
- expected_results[43] = VERIFIED;
- expected_results[44] = VERIFIED;
-
- //expected_results[45] = EXPLICT_POLICY_REQUIRED;
- //expected_results[46] = ACCEPT;
- //expected_results[47] = EXPLICT_POLICY_REQUIRED;
-
- expected_results[48] = VERIFIED;
- expected_results[49] = VERIFIED;
- expected_results[50] = VERIFIED;
- expected_results[51] = VERIFIED;
- expected_results[52] = VERIFIED;
- expected_results[53] = VERIFIED;
-
- expected_results[54] = CERT_CHAIN_TOO_LONG;
- expected_results[55] = CERT_CHAIN_TOO_LONG;
- expected_results[56] = VERIFIED;
- expected_results[57] = VERIFIED;
- expected_results[58] = CERT_CHAIN_TOO_LONG;
- expected_results[59] = CERT_CHAIN_TOO_LONG;
- expected_results[60] = CERT_CHAIN_TOO_LONG;
- expected_results[61] = CERT_CHAIN_TOO_LONG;
- expected_results[62] = VERIFIED;
- expected_results[63] = VERIFIED;
-
- expected_results[64] = SIGNATURE_ERROR;
-
- 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;
- expected_results[70] = CERT_IS_REVOKED;
- expected_results[71] = CERT_IS_REVOKED;
- expected_results[72] = CRL_HAS_EXPIRED;
- expected_results[73] = CRL_HAS_EXPIRED;
- expected_results[74] = VERIFIED;
+ expected_results[34] = Path_Validation_Result::VERIFIED;
+ expected_results[35] = Path_Validation_Result::VERIFIED;
+ expected_results[36] = Path_Validation_Result::VERIFIED;
+ expected_results[37] = Path_Validation_Result::VERIFIED;
+ expected_results[38] = Path_Validation_Result::VERIFIED;
+ expected_results[39] = Path_Validation_Result::VERIFIED;
+ expected_results[40] = Path_Validation_Result::VERIFIED;
+ expected_results[41] = Path_Validation_Result::VERIFIED;
+ expected_results[42] = Path_Validation_Result::VERIFIED;
+ expected_results[43] = Path_Validation_Result::VERIFIED;
+ expected_results[44] = Path_Validation_Result::VERIFIED;
+
+ //expected_results[45] = Path_Validation_Result::EXPLICT_POLICY_REQUIRED;
+ //expected_results[46] = Path_Validation_Result::ACCEPT;
+ //expected_results[47] = Path_Validation_Result::EXPLICT_POLICY_REQUIRED;
+
+ expected_results[48] = Path_Validation_Result::VERIFIED;
+ expected_results[49] = Path_Validation_Result::VERIFIED;
+ expected_results[50] = Path_Validation_Result::VERIFIED;
+ expected_results[51] = Path_Validation_Result::VERIFIED;
+ expected_results[52] = Path_Validation_Result::VERIFIED;
+ expected_results[53] = Path_Validation_Result::VERIFIED;
+
+ expected_results[54] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[55] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[56] = Path_Validation_Result::VERIFIED;
+ expected_results[57] = Path_Validation_Result::VERIFIED;
+ expected_results[58] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[59] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[60] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[61] = Path_Validation_Result::CERT_CHAIN_TOO_LONG;
+ expected_results[62] = Path_Validation_Result::VERIFIED;
+ expected_results[63] = Path_Validation_Result::VERIFIED;
+
+ expected_results[64] = Path_Validation_Result::SIGNATURE_ERROR;
+
+ expected_results[65] = Path_Validation_Result::CRL_NOT_FOUND;
+ expected_results[66] = Path_Validation_Result::CRL_NOT_FOUND;
+
+ expected_results[67] = Path_Validation_Result::VERIFIED;
+
+ expected_results[68] = Path_Validation_Result::CERT_IS_REVOKED;
+ expected_results[69] = Path_Validation_Result::CERT_IS_REVOKED;
+ expected_results[70] = Path_Validation_Result::CERT_IS_REVOKED;
+ expected_results[71] = Path_Validation_Result::CERT_IS_REVOKED;
+ expected_results[72] = Path_Validation_Result::CRL_HAS_EXPIRED;
+ expected_results[73] = Path_Validation_Result::CRL_HAS_EXPIRED;
+ expected_results[74] = Path_Validation_Result::VERIFIED;
/* These tests use weird CRL extensions which aren't supported yet */
//expected_results[75] = ;
diff --git a/checks/x509.cpp b/checks/x509.cpp
index 9ae295d35..138d1b346 100644
--- a/checks/x509.cpp
+++ b/checks/x509.cpp
@@ -137,7 +137,7 @@ void do_x509_tests(RandomNumberGenerator& rng)
/* Create the CA's key and self-signed cert */
std::cout << '.' << std::flush;
- RSA_PrivateKey ca_key(rng, 1024);
+ RSA_PrivateKey ca_key(rng, 2048);
std::cout << '.' << std::flush;
X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(),
@@ -148,7 +148,7 @@ void do_x509_tests(RandomNumberGenerator& rng)
/* Create user #1's key and cert request */
std::cout << '.' << std::flush;
- DSA_PrivateKey user1_key(rng, DL_Group("dsa/jce/1024"));
+ DSA_PrivateKey user1_key(rng, DL_Group("dsa/botan/2048"));
std::cout << '.' << std::flush;
PKCS10_Request user1_req = X509::create_cert_req(req_opts1(),
@@ -162,7 +162,7 @@ void do_x509_tests(RandomNumberGenerator& rng)
EC_Group ecc_domain(OID("1.2.840.10045.3.1.7"));
ECDSA_PrivateKey user2_key(rng, ecc_domain);
#else
- RSA_PrivateKey user2_key(rng, 1024);
+ RSA_PrivateKey user2_key(rng, 1536);
#endif
std::cout << '.' << std::flush;
@@ -197,13 +197,17 @@ void do_x509_tests(RandomNumberGenerator& rng)
std::cout << '.' << std::flush;
- 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 - " << result_u1.validation_result << std::endl;
+ Path_Validation_Restrictions restrictions;
- 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 - " << result_u2.validation_result << std::endl;
+ Path_Validation_Result result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(!result_u1.successful_validation())
+ std::cout << "FAILED: User cert #1 did not validate - "
+ << result_u1.result_string() << std::endl;
+
+ Path_Validation_Result result_u2 = x509_path_validate(user2_cert, restrictions, store);
+ if(!result_u2.successful_validation())
+ std::cout << "FAILED: User cert #2 did not validate - "
+ << result_u2.result_string() << std::endl;
store.add_crl(crl1);
@@ -215,13 +219,15 @@ void do_x509_tests(RandomNumberGenerator& rng)
store.add_crl(crl2);
- result_u1 = x509_path_validate(user1_cert, store);
- if(result_u1.validation_result != CERT_IS_REVOKED)
- std::cout << "\nFAILED: User cert #1 was not revoked" << std::endl;
+ result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(result_u1.result() != Path_Validation_Result::CERT_IS_REVOKED)
+ std::cout << "FAILED: User cert #1 was not revoked - "
+ << result_u1.result_string() << std::endl;
- result_u2 = x509_path_validate(user2_cert, store);
- if(result_u2.validation_result != CERT_IS_REVOKED)
- std::cout << "\nFAILED: User cert #2 was not revoked" << std::endl;
+ result_u2 = x509_path_validate(user2_cert, restrictions, store);
+ if(result_u2.result() != Path_Validation_Result::CERT_IS_REVOKED)
+ std::cout << "FAILED: User cert #2 was not revoked - "
+ << result_u2.result_string() << std::endl;
revoked.clear();
revoked.push_back(CRL_Entry(user1_cert, REMOVE_FROM_CRL));
@@ -229,9 +235,10 @@ void do_x509_tests(RandomNumberGenerator& rng)
store.add_crl(crl3);
- result_u1 = x509_path_validate(user1_cert, store);
- if(result_u1.validation_result != VERIFIED)
- std::cout << "\nFAILED: User cert #1 was not un-revoked" << std::endl;
+ result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(!result_u1.successful_validation())
+ std::cout << "FAILED: User cert #1 was not un-revoked - "
+ << result_u1.result_string() << std::endl;
check_against_copy(ca_key, rng);
check_against_copy(user1_key, rng);
diff --git a/src/cert/x509/x509path.cpp b/src/cert/x509/x509path.cpp
index a9b8150ae..fcf27841d 100644
--- a/src/cert/x509/x509path.cpp
+++ b/src/cert/x509/x509path.cpp
@@ -1,6 +1,6 @@
/*
* X.509 Certificate Path Validation
-* (C) 2010-2011 Jack Lloyd
+* (C) 2010,2011,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -20,13 +20,13 @@ namespace {
class PKIX_Validation_Failure : public std::exception
{
public:
- PKIX_Validation_Failure(X509_Path_Validation_Code code) : m_code(code) {}
+ PKIX_Validation_Failure(Path_Validation_Result::Code code) : m_code(code) {}
- X509_Path_Validation_Code code() const { return m_code; }
+ Path_Validation_Result::Code code() const { return m_code; }
const char* what() { return "PKIX validation failed"; }
private:
- X509_Path_Validation_Code m_code;
+ Path_Validation_Result::Code m_code;
};
X509_Certificate find_issuing_cert(const X509_Certificate& cert,
@@ -41,14 +41,14 @@ X509_Certificate find_issuing_cert(const X509_Certificate& cert,
certstores[i]->find_cert_by_subject_and_key_id(issuer_dn, auth_key_id);
if(certs.size() == 0)
- throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_ISSUER_NOT_FOUND);
else if(certs.size() > 1)
- throw PKIX_Validation_Failure(CERT_MULTIPLE_ISSUERS_FOUND);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_MULTIPLE_ISSUERS_FOUND);
return certs[0];
}
- throw PKIX_Validation_Failure(CERT_ISSUER_NOT_FOUND);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_ISSUER_NOT_FOUND);
}
std::vector<X509_CRL> find_crls_from(const X509_Certificate& cert,
@@ -71,6 +71,16 @@ std::vector<X509_CRL> find_crls_from(const X509_Certificate& cert,
}
+Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev) :
+ m_require_revocation_information(require_rev)
+ {
+ m_trusted_hashes.insert("SHA-160");
+ m_trusted_hashes.insert("SHA-224");
+ m_trusted_hashes.insert("SHA-256");
+ m_trusted_hashes.insert("SHA-384");
+ m_trusted_hashes.insert("SHA-512");
+ }
+
const X509_Certificate& Path_Validation_Result::trust_root() const
{
return m_cert_path[m_cert_path.size()-1];
@@ -84,27 +94,83 @@ std::set<std::string> Path_Validation_Result::trusted_hashes() const
return hashes;
}
+std::string Path_Validation_Result::result_string() const
+ {
+ switch(m_result)
+ {
+ case VERIFIED:
+ return "verified";
+ case UNKNOWN_X509_ERROR:
+ return "unknown error";
+ case CANNOT_ESTABLISH_TRUST:
+ return "cannot establish trust";
+ case CERT_CHAIN_TOO_LONG:
+ return "certificate chain too long";
+ case SIGNATURE_ERROR:
+ return "signature error";
+ case POLICY_ERROR:
+ return "policy error";
+ case INVALID_USAGE:
+ return "invalid usage";
+ case UNTRUSTED_HASH:
+ return "untrusted hash function";
+
+ case CERT_MULTIPLE_ISSUERS_FOUND:
+ return "Multiple certificate issuers found";
+ case CERT_FORMAT_ERROR:
+ return "Certificate format error";
+ case CERT_ISSUER_NOT_FOUND:
+ return "Certificate issuer not found";
+ case CERT_NOT_YET_VALID:
+ return "Certificate is not yet valid";
+ case CERT_HAS_EXPIRED:
+ return "Certificate has expired";
+ case CERT_IS_REVOKED:
+ return "Certificate is revoked";
+ case CRL_NOT_FOUND:
+ return "CRL not found";
+ case CRL_FORMAT_ERROR:
+ return "CRL format error";
+ case CRL_NOT_YET_VALID:
+ return "CRL is not yet valid";
+ case CRL_HAS_EXPIRED:
+ return "CRL has expired";
+ case CA_CERT_CANNOT_SIGN:
+ return "CA certificate cannot sign";
+ case CA_CERT_NOT_FOR_CERT_ISSUER:
+ return "CA certificate not allowed to issue certs";
+ case CA_CERT_NOT_FOR_CRL_ISSUER:
+ return "CA certificate not allowed to issue CRLs";
+
+ default:
+ return "Unknown code " + to_string(m_result);
+ }
+ }
+
Path_Validation_Result x509_path_validate(
const X509_Certificate& end_cert,
+ const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores)
{
std::vector<X509_Certificate> certs;
certs.push_back(end_cert);
- return x509_path_validate(certs, certstores);
+ return x509_path_validate(certs, restrictions, certstores);
}
Path_Validation_Result x509_path_validate(
const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
Certificate_Store& store)
{
std::vector<Certificate_Store*> certstores;
certstores.push_back(&store);
- return x509_path_validate(end_certs, certstores);
+ return x509_path_validate(end_certs, restrictions, certstores);
}
Path_Validation_Result x509_path_validate(
const X509_Certificate& end_cert,
+ const Path_Validation_Restrictions& restrictions,
Certificate_Store& store)
{
std::vector<X509_Certificate> certs;
@@ -113,19 +179,25 @@ Path_Validation_Result x509_path_validate(
std::vector<Certificate_Store*> certstores;
certstores.push_back(&store);
- return x509_path_validate(certs, certstores);
+ return x509_path_validate(certs, restrictions, certstores);
}
-Path_Validation_Result
-x509_path_validate(const std::vector<X509_Certificate>& end_certs,
- const std::vector<Certificate_Store*>& certstores)
+Path_Validation_Result x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
+ const std::vector<Certificate_Store*>& certstores)
{
+ if(end_certs.empty())
+ throw std::invalid_argument("x509_path_validate called with no subjects");
+
Path_Validation_Result r;
r.m_cert_path = end_certs;
std::vector<X509_Certificate>& cert_path = r.m_cert_path;
+ const std::set<std::string>& trusted_hashes = restrictions.trusted_hashes();
+
try
{
// iterate until we reach a root or cannot find the issuer
@@ -144,12 +216,18 @@ x509_path_validate(const std::vector<X509_Certificate>& end_certs,
{
const X509_Certificate& subject = cert_path[i];
+ if(!trusted_hashes.empty())
+ {
+ if(trusted_hashes.count(subject.hash_used_for_signature()) == 0)
+ throw PKIX_Validation_Failure(Path_Validation_Result::UNTRUSTED_HASH);
+ }
+
// Check all certs for valid time range
if(current_time < X509_Time(subject.start_time()))
- throw PKIX_Validation_Failure(CERT_NOT_YET_VALID);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_NOT_YET_VALID);
if(current_time > X509_Time(subject.end_time()))
- throw PKIX_Validation_Failure(CERT_HAS_EXPIRED);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_HAS_EXPIRED);
const bool at_self_signed_root = (i == cert_path.size() - 1);
@@ -160,13 +238,13 @@ x509_path_validate(const std::vector<X509_Certificate>& end_certs,
// Don't require CA bit set on self-signed end entity cert
if(!issuer.is_CA_cert() && !self_signed_ee_cert)
- throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CERT_ISSUER);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER);
if(issuer.path_limit() < i)
- throw PKIX_Validation_Failure(CERT_CHAIN_TOO_LONG);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_CHAIN_TOO_LONG);
if(subject.check_signature(issuer.subject_public_key()) == false)
- throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+ throw PKIX_Validation_Failure(Path_Validation_Result::SIGNATURE_ERROR);
}
for(size_t i = 1; i != cert_path.size(); ++i)
@@ -177,28 +255,33 @@ x509_path_validate(const std::vector<X509_Certificate>& end_certs,
std::vector<X509_CRL> crls = find_crls_from(ca, certstores);
if(crls.empty())
- //throw PKIX_Validation_Failure(CRL_NOT_FOUND);
+ {
+ if(restrictions.require_revocation_information())
+ throw PKIX_Validation_Failure(Path_Validation_Result::CRL_NOT_FOUND);
continue;
+ }
const X509_CRL& crl = crls[0];
if(!ca.allowed_usage(CRL_SIGN))
- throw PKIX_Validation_Failure(CA_CERT_NOT_FOR_CRL_ISSUER);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CA_CERT_NOT_FOR_CRL_ISSUER);
if(current_time < X509_Time(crl.this_update()))
- throw PKIX_Validation_Failure(CRL_NOT_YET_VALID);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CRL_NOT_YET_VALID);
if(current_time > X509_Time(crl.next_update()))
- throw PKIX_Validation_Failure(CRL_HAS_EXPIRED);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CRL_HAS_EXPIRED);
if(crl.check_signature(ca.subject_public_key()) == false)
- throw PKIX_Validation_Failure(SIGNATURE_ERROR);
+ throw PKIX_Validation_Failure(Path_Validation_Result::SIGNATURE_ERROR);
if(crl.is_revoked(subject))
- throw PKIX_Validation_Failure(CERT_IS_REVOKED);
+ throw PKIX_Validation_Failure(Path_Validation_Result::CERT_IS_REVOKED);
}
- r.set_result(self_signed_ee_cert ? CANNOT_ESTABLISH_TRUST : VERIFIED);
+ r.set_result(self_signed_ee_cert ?
+ Path_Validation_Result::CANNOT_ESTABLISH_TRUST :
+ Path_Validation_Result::VERIFIED);
}
catch(PKIX_Validation_Failure& e)
{
diff --git a/src/cert/x509/x509path.h b/src/cert/x509/x509path.h
index c389431d8..18129a236 100644
--- a/src/cert/x509/x509path.h
+++ b/src/cert/x509/x509path.h
@@ -14,54 +14,59 @@
namespace Botan {
-/**
-* X.509 Certificate Validation Result
-*/
-enum X509_Path_Validation_Code {
- VERIFIED,
- UNKNOWN_X509_ERROR,
- CANNOT_ESTABLISH_TRUST,
- CERT_CHAIN_TOO_LONG,
- SIGNATURE_ERROR,
- POLICY_ERROR,
- INVALID_USAGE,
-
- CERT_MULTIPLE_ISSUERS_FOUND,
-
- CERT_FORMAT_ERROR,
- CERT_ISSUER_NOT_FOUND,
- CERT_NOT_YET_VALID,
- CERT_HAS_EXPIRED,
- CERT_IS_REVOKED,
-
- CRL_NOT_FOUND,
- CRL_FORMAT_ERROR,
- CRL_ISSUER_NOT_FOUND,
- CRL_NOT_YET_VALID,
- CRL_HAS_EXPIRED,
-
- CA_CERT_CANNOT_SIGN,
- CA_CERT_NOT_FOR_CERT_ISSUER,
- CA_CERT_NOT_FOR_CRL_ISSUER
-};
-
-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 BOTAN_DLL Path_Validation_Restrictions
+ {
+ public:
+ Path_Validation_Restrictions(bool require_rev = false);
+
+ Path_Validation_Restrictions(bool require_rev,
+ const std::set<std::string>& trusted_hashes) :
+ m_require_revocation_information(require_rev),
+ m_trusted_hashes(trusted_hashes) {}
+
+ bool require_revocation_information() const
+ { return m_require_revocation_information; }
+
+ const std::set<std::string>& trusted_hashes() const
+ { return m_trusted_hashes; }
+ private:
+ bool m_require_revocation_information;
+ std::set<std::string> m_trusted_hashes;
+ };
class BOTAN_DLL Path_Validation_Result
{
public:
- Path_Validation_Result() :
- m_result(UNKNOWN_X509_ERROR),
- m_usages(NO_RESTRICTIONS)
- {}
+ /**
+ * X.509 Certificate Validation Result
+ */
+ enum Code {
+ VERIFIED,
+ UNKNOWN_X509_ERROR,
+ CANNOT_ESTABLISH_TRUST,
+ CERT_CHAIN_TOO_LONG,
+ SIGNATURE_ERROR,
+ POLICY_ERROR,
+ INVALID_USAGE,
+ UNTRUSTED_HASH,
+
+ CERT_MULTIPLE_ISSUERS_FOUND,
+
+ CERT_FORMAT_ERROR,
+ CERT_ISSUER_NOT_FOUND,
+ CERT_NOT_YET_VALID,
+ CERT_HAS_EXPIRED,
+ CERT_IS_REVOKED,
+
+ CRL_NOT_FOUND,
+ CRL_FORMAT_ERROR,
+ CRL_NOT_YET_VALID,
+ CRL_HAS_EXPIRED,
+
+ CA_CERT_CANNOT_SIGN,
+ CA_CERT_NOT_FOR_CERT_ISSUER,
+ CA_CERT_NOT_FOR_CRL_ISSUER
+ };
/**
* Returns the set of hash functions you are implicitly
@@ -75,34 +80,43 @@ class BOTAN_DLL Path_Validation_Result
bool successful_validation() const { return result() == VERIFIED; }
- X509_Path_Validation_Code result() const { return m_result; }
+ Code result() const { return m_result; }
+
+ std::string result_string() const;
+
private:
+ Path_Validation_Result() : m_result(UNKNOWN_X509_ERROR) {}
+
friend Path_Validation_Result x509_path_validate(
const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores);
- void set_result(X509_Path_Validation_Code result) { m_result = result; }
+ void set_result(Code result) { m_result = result; }
- X509_Path_Validation_Code m_result;
- Usage_Restrictions m_usages;
+ Code m_result;
std::vector<X509_Certificate> m_cert_path;
};
Path_Validation_Result BOTAN_DLL x509_path_validate(
const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores);
Path_Validation_Result BOTAN_DLL x509_path_validate(
const X509_Certificate& end_cert,
+ const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores);
Path_Validation_Result BOTAN_DLL x509_path_validate(
const X509_Certificate& end_cert,
+ const Path_Validation_Restrictions& restrictions,
Certificate_Store& store);
Path_Validation_Result BOTAN_DLL x509_path_validate(
const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
Certificate_Store& store);
}