diff options
Diffstat (limited to 'src/cert/x509/x509path.cpp')
-rw-r--r-- | src/cert/x509/x509path.cpp | 133 |
1 files changed, 108 insertions, 25 deletions
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) { |