aboutsummaryrefslogtreecommitdiffstats
path: root/src/cert
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 /src/cert
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.
Diffstat (limited to 'src/cert')
-rw-r--r--src/cert/x509/x509path.cpp133
-rw-r--r--src/cert/x509/x509path.h110
2 files changed, 170 insertions, 73 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)
{
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);
}