diff options
author | lloyd <[email protected]> | 2012-03-28 23:24:38 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-03-28 23:24:38 +0000 |
commit | 0da08c29d55ddea710767267af3ec690e91a77a6 (patch) | |
tree | edcf93c880c2f83fb91964f554637b77c94810f5 | |
parent | d4050e6b838acfd9552b4ab137fbf0717ff1e0ca (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.cpp | 192 | ||||
-rw-r--r-- | checks/x509.cpp | 43 | ||||
-rw-r--r-- | src/cert/x509/x509path.cpp | 133 | ||||
-rw-r--r-- | src/cert/x509/x509path.h | 110 |
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); } |