aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-11-29 19:42:46 +0000
committerlloyd <[email protected]>2013-11-29 19:42:46 +0000
commit7ef2285a09c8476708f45e3bb69dbb8c8b6fb704 (patch)
tree03a30d21e64dea5b3ab88a1993a85ca20eb65e50
parent0e7e188973c0361ba77cfeb0eb2bbae1c2e0ea63 (diff)
Have OCSP responses return an enum allowing a range of conditions to be expressed
(good status, cert revoked, some other error, etc). Add a certificate store backed by files (requiring boost filesystem). Change Certificate_Store interface somewhat to support retrieval without copying.
-rw-r--r--doc/examples/credentials.h23
-rw-r--r--src/cert/ocsp/ocsp.cpp43
-rw-r--r--src/cert/ocsp/ocsp.h5
-rw-r--r--src/cert/ocsp/ocsp_types.cpp23
-rw-r--r--src/cert/ocsp/ocsp_types.h15
-rw-r--r--src/cert/x509/cert_status.h54
-rw-r--r--src/cert/x509/certstor.cpp91
-rw-r--r--src/cert/x509/certstor.h67
-rw-r--r--src/cert/x509/info.txt2
-rw-r--r--src/cert/x509/x509path.cpp320
-rw-r--r--src/cert/x509/x509path.h40
11 files changed, 368 insertions, 315 deletions
diff --git a/doc/examples/credentials.h b/doc/examples/credentials.h
index c7dae364a..d87fab7ba 100644
--- a/doc/examples/credentials.h
+++ b/doc/examples/credentials.h
@@ -25,7 +25,11 @@ bool value_exists(const std::vector<std::string>& vec,
class Credentials_Manager_Simple : public Botan::Credentials_Manager
{
public:
- Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : rng(rng) {}
+ Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) :
+ rng(rng)
+ {
+ m_certstores.push_back(new Botan::Certificate_Store_In_Memory("/usr/share/ca-certificates"));
+ }
std::string srp_identifier(const std::string& type,
const std::string& hostname)
@@ -47,19 +51,8 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager
trusted_certificate_authorities(const std::string& type,
const std::string& hostname)
{
-
- std::vector<Botan::Certificate_Store*> certs;
-
- if(type == "tls-client" && hostname == "twitter.com")
- {
- Botan::X509_Certificate verisign("/usr/share/ca-certificates/mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.crt");
-
- auto store = new Botan::Certificate_Store_In_Memory;
- store->add_certificate(verisign);
- certs.push_back(store);
- }
-
- return certs;
+ // can very based on hostname eg for pinning
+ return m_certstores;
}
void verify_certificate_chain(
@@ -291,6 +284,8 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager
Botan::SymmetricKey session_ticket_key;
std::map<Botan::X509_Certificate, Botan::Private_Key*> certs_and_keys;
+
+ std::vector<Botan::Certificate_Store*> m_certstores;
};
#endif
diff --git a/src/cert/ocsp/ocsp.cpp b/src/cert/ocsp/ocsp.cpp
index d894abc97..2ea413e76 100644
--- a/src/cert/ocsp/ocsp.cpp
+++ b/src/cert/ocsp/ocsp.cpp
@@ -1,6 +1,6 @@
/*
* OCSP
-* (C) 2012 Jack Lloyd
+* (C) 2012,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -77,7 +77,7 @@ void check_signature(const std::vector<byte>& tbs_response,
if(certs.size() < 1)
throw std::invalid_argument("Short cert chain for check_signature");
- if(trusted_roots.certificate_known(certs[0])) // directly signed by
+ if(trusted_roots.certificate_known(certs[0]))
return check_signature(tbs_response, sig_algo, signature, certs[0]);
// Otherwise attempt to chain the signing cert to a trust root
@@ -85,10 +85,7 @@ void check_signature(const std::vector<byte>& tbs_response,
if(!certs[0].allowed_usage("PKIX.OCSPSigning"))
throw std::runtime_error("OCSP response cert does not allow OCSP signing");
- Path_Validation_Result result =
- x509_path_validate(certs,
- Path_Validation_Restrictions(),
- trusted_roots);
+ auto result = x509_path_validate(certs, Path_Validation_Restrictions(), trusted_roots);
if(!result.successful_validation())
throw std::runtime_error("Certificate validation failure: " + result.result_string());
@@ -186,8 +183,9 @@ Response::Response(const Certificate_Store& trusted_roots,
if(certs.empty())
{
- certs = trusted_roots.find_cert_by_subject_and_key_id(name, std::vector<byte>());
- if(certs.empty())
+ if(auto cert = trusted_roots.find_cert(name, std::vector<byte>()))
+ certs.push_back(*cert);
+ else
throw std::runtime_error("Could not find certificate that signed OCSP response");
}
@@ -197,14 +195,31 @@ Response::Response(const Certificate_Store& trusted_roots,
response_outer.end_cons();
}
-bool Response::affirmative_response_for(const X509_Certificate& issuer,
- const X509_Certificate& subject) const
+Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
+ const X509_Certificate& subject) const
{
- for(auto response : m_responses)
- if(response.affirmative_response_for(issuer, subject))
- return true;
+ for(const auto& response : m_responses)
+ {
+ if(response.certid().is_id_for(issuer, subject))
+ {
+ X509_Time current_time(std::chrono::system_clock::now());
+
+ if(response.this_update() > current_time)
+ return Certificate_Status_Code::OCSP_NOT_YET_VALID;
+
+ if(response.next_update().time_is_set() && current_time > response.next_update())
+ return Certificate_Status_Code::OCSP_EXPIRED;
+
+ if(response.cert_status() == 1)
+ return Certificate_Status_Code::CERT_IS_REVOKED;
+ else if(response.cert_status() == 0)
+ return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
+ else
+ return Certificate_Status_Code::OCSP_BAD_STATUS;
+ }
+ }
- return false;
+ return Certificate_Status_Code::OCSP_CERT_NOT_LISTED;
}
Response online_check(const X509_Certificate& issuer,
diff --git a/src/cert/ocsp/ocsp.h b/src/cert/ocsp/ocsp.h
index ec86b434e..0c40bc282 100644
--- a/src/cert/ocsp/ocsp.h
+++ b/src/cert/ocsp/ocsp.h
@@ -8,6 +8,7 @@
#ifndef BOTAN_OCSP_H__
#define BOTAN_OCSP_H__
+#include <botan/cert_status.h>
#include <botan/ocsp_types.h>
namespace Botan {
@@ -42,8 +43,8 @@ class BOTAN_DLL Response
Response(const Certificate_Store& trusted_roots,
const std::vector<byte>& response);
- bool affirmative_response_for(const X509_Certificate& issuer,
- const X509_Certificate& subject) const;
+ Certificate_Status_Code status_for(const X509_Certificate& issuer,
+ const X509_Certificate& subject) const;
private:
std::vector<SingleResponse> m_responses;
diff --git a/src/cert/ocsp/ocsp_types.cpp b/src/cert/ocsp/ocsp_types.cpp
index ed78f839b..be41499ee 100644
--- a/src/cert/ocsp/ocsp_types.cpp
+++ b/src/cert/ocsp/ocsp_types.cpp
@@ -92,27 +92,6 @@ void CertID::decode_from(class BER_Decoder& from)
}
-bool SingleResponse::affirmative_response_for(
- const X509_Certificate& issuer,
- const X509_Certificate& subject) const
- {
- if(!m_good_status)
- return false;
-
- if(!m_certid.is_id_for(issuer, subject))
- return false;
-
- X509_Time current_time(std::chrono::system_clock::now());
-
- if(m_thisupdate > current_time)
- return false; // not yet valid?
-
- if(m_nextupdate.time_is_set() && current_time > m_nextupdate)
- return false; // expired, probably replayed
-
- return true;
- }
-
void SingleResponse::encode_into(class DER_Encoder&) const
{
throw std::runtime_error("Not implemented (SingleResponse::encode_into)");
@@ -134,7 +113,7 @@ void SingleResponse::decode_from(class BER_Decoder& from)
ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))
.end_cons();
- m_good_status = (cert_status.type_tag == 0);
+ m_cert_status = cert_status.type_tag;
}
}
diff --git a/src/cert/ocsp/ocsp_types.h b/src/cert/ocsp/ocsp_types.h
index e51089aca..f693600ea 100644
--- a/src/cert/ocsp/ocsp_types.h
+++ b/src/cert/ocsp/ocsp_types.h
@@ -42,21 +42,20 @@ class BOTAN_DLL CertID : public ASN1_Object
class BOTAN_DLL SingleResponse : public ASN1_Object
{
public:
- SingleResponse() : m_good_status(false) {}
+ const CertID& certid() const { return m_certid; }
- /**
- * Return true if and only if this response is one matching
- * the current issuer and subject AND is a postive affirmation
- */
- bool affirmative_response_for(const X509_Certificate& issuer,
- const X509_Certificate& subject) const;
+ size_t cert_status() const { return m_cert_status; }
+
+ X509_Time this_update() const { return m_thisupdate; }
+
+ X509_Time next_update() const { return m_thisupdate; }
void encode_into(class DER_Encoder& to) const override;
void decode_from(class BER_Decoder& from) override;
private:
CertID m_certid;
- bool m_good_status;
+ size_t m_cert_status = 2; // unknown
X509_Time m_thisupdate;
X509_Time m_nextupdate;
};
diff --git a/src/cert/x509/cert_status.h b/src/cert/x509/cert_status.h
new file mode 100644
index 000000000..d78f14473
--- /dev/null
+++ b/src/cert/x509/cert_status.h
@@ -0,0 +1,54 @@
+/*
+* Result enums
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_X509_PATH_RESULT_H__
+#define BOTAN_X509_PATH_RESULT_H__
+
+#include <string>
+
+namespace Botan {
+
+enum Certificate_Status_Code {
+ VERIFIED,
+ UNKNOWN_X509_ERROR,
+ CANNOT_ESTABLISH_TRUST,
+ CERT_CHAIN_TOO_LONG,
+ SIGNATURE_ERROR,
+ POLICY_ERROR,
+ INVALID_USAGE,
+
+ SIGNATURE_METHOD_TOO_WEAK,
+ 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,
+
+ OCSP_CERT_NOT_LISTED,
+ OCSP_NOT_YET_VALID,
+ OCSP_EXPIRED,
+ OCSP_BAD_STATUS,
+ OCSP_RESPONSE_GOOD,
+
+ CA_CERT_CANNOT_SIGN,
+ CA_CERT_NOT_FOR_CERT_ISSUER,
+ CA_CERT_NOT_FOR_CRL_ISSUER
+};
+
+
+}
+
+#endif
diff --git a/src/cert/x509/certstor.cpp b/src/cert/x509/certstor.cpp
index afb0ddd0c..e8b3a0718 100644
--- a/src/cert/x509/certstor.cpp
+++ b/src/cert/x509/certstor.cpp
@@ -1,21 +1,18 @@
/*
* Certificate Store
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/certstor.h>
+#include <boost/filesystem.hpp>
namespace Botan {
-bool Certificate_Store::certificate_known(const X509_Certificate& cert) const
+const X509_CRL* Certificate_Store::find_crl(const X509_Certificate&) const
{
- std::vector<X509_Certificate> found =
- find_cert_by_subject_and_key_id(cert.subject_dn(),
- cert.subject_key_id());
-
- return !found.empty();
+ return nullptr;
}
void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
@@ -37,29 +34,37 @@ std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const
return subjects;
}
-std::vector<X509_Certificate>
-Certificate_Store_In_Memory::find_cert_by_subject_and_key_id(
- const X509_DN& subject_dn,
- const std::vector<byte>& key_id) const
- {
- std::vector<X509_Certificate> result;
+namespace {
- for(size_t i = 0; i != m_certs.size(); ++i)
+const X509_Certificate*
+cert_search(const X509_DN& subject_dn, const std::vector<byte>& key_id,
+ const std::vector<X509_Certificate>& certs)
+ {
+ for(size_t i = 0; i != certs.size(); ++i)
{
// Only compare key ids if set in both call and in the cert
if(key_id.size())
{
- std::vector<byte> skid = m_certs[i].subject_key_id();
+ std::vector<byte> skid = certs[i].subject_key_id();
if(skid.size() && skid != key_id) // no match
continue;
}
- if(m_certs[i].subject_dn() == subject_dn)
- result.push_back(m_certs[i]);
+ if(certs[i].subject_dn() == subject_dn)
+ return &certs[i];
}
- return result;
+ return nullptr;
+ }
+
+}
+
+const X509_Certificate*
+Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
+ const std::vector<byte>& key_id) const
+ {
+ return cert_search(subject_dn, key_id, m_certs);
}
void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
@@ -81,12 +86,9 @@ void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
m_crls.push_back(crl);
}
-std::vector<X509_CRL>
-Certificate_Store_In_Memory::find_crl_by_issuer_and_key_id(
- const X509_DN& issuer_dn,
- const std::vector<byte>& key_id) const
+const X509_CRL* Certificate_Store_In_Memory::find_crl(const X509_Certificate& subject) const
{
- std::vector<X509_CRL> result;
+ const std::vector<byte>& key_id = subject.authority_key_id();
for(size_t i = 0; i != m_crls.size(); ++i)
{
@@ -99,11 +101,48 @@ Certificate_Store_In_Memory::find_crl_by_issuer_and_key_id(
continue;
}
- if(m_crls[i].issuer_dn() == issuer_dn)
- result.push_back(m_crls[i]);
+ if(m_crls[i].issuer_dn() == subject.issuer_dn())
+ return &m_crls[i];
}
- return result;
+ return nullptr;
+ }
+
+Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir)
+ {
+ if(dir == "")
+ return;
+
+ boost::filesystem::recursive_directory_iterator i(dir);
+ boost::filesystem::recursive_directory_iterator end;
+
+ while(i != end)
+ {
+ auto path = i->path();
+ ++i;
+
+ try
+ {
+ if(boost::filesystem::is_regular_file(path))
+ m_certs.push_back(X509_Certificate(path.native()));
+ }
+ catch(...) {}
+ }
+ }
+
+const X509_Certificate*
+Certificate_Store_Overlay::find_cert(const X509_DN& subject_dn,
+ const std::vector<byte>& key_id) const
+ {
+ return cert_search(subject_dn, key_id, m_certs);
+ }
+
+std::vector<X509_DN> Certificate_Store_Overlay::all_subjects() const
+ {
+ std::vector<X509_DN> subjects;
+ for(size_t i = 0; i != m_certs.size(); ++i)
+ subjects.push_back(m_certs[i].subject_dn());
+ return subjects;
}
}
diff --git a/src/cert/x509/certstor.h b/src/cert/x509/certstor.h
index 6faa0bfae..fc37d8327 100644
--- a/src/cert/x509/certstor.h
+++ b/src/cert/x509/certstor.h
@@ -1,6 +1,6 @@
/*
* Certificate Store
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -22,34 +22,20 @@ class BOTAN_DLL Certificate_Store
virtual ~Certificate_Store() {}
/**
- * Add a certificate; this may fail if the store is write-only
+ * Subject DN and (optionally) key identifier
*/
- virtual void add_certificate(const X509_Certificate& cert) = 0;
+ virtual const X509_Certificate*
+ find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const = 0;
- /**
- * Add a CRL; this may fail if the store is write-only
- */
- virtual void add_crl(const X509_CRL& crl) = 0;
+ virtual const X509_CRL* find_crl(const X509_Certificate& subject) const;
- bool certificate_known(const X509_Certificate& cert) const;
+ bool certificate_known(const X509_Certificate& cert) const
+ {
+ return find_cert(cert.subject_dn(), cert.subject_key_id());
+ }
+ // remove this (used by TLS::Server)
virtual std::vector<X509_DN> all_subjects() const = 0;
-
- /**
- * Subject DN and (optionally) key identifier
- */
- virtual std::vector<X509_Certificate>
- find_cert_by_subject_and_key_id(
- const X509_DN& subject_dn,
- const std::vector<byte>& key_id) const = 0;
-
- /**
- * Find CRLs by the DN and key id of the issuer
- */
- virtual std::vector<X509_CRL>
- find_crl_by_issuer_and_key_id(
- const X509_DN& issuer_dn,
- const std::vector<byte>& key_id) const = 0;
};
/**
@@ -58,30 +44,45 @@ class BOTAN_DLL Certificate_Store
class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store
{
public:
+ /**
+ * Attempt to parse all files in dir (including subdirectories)
+ * as certificates. Ignores errors.
+ */
+ Certificate_Store_In_Memory(const std::string& dir);
+
Certificate_Store_In_Memory() {}
- void add_certificate(const X509_Certificate& cert) override;
+ void add_certificate(const X509_Certificate& cert);
- void add_crl(const X509_CRL& crl) override;
+ void add_crl(const X509_CRL& crl);
std::vector<X509_DN> all_subjects() const override;
- std::vector<X509_Certificate> find_cert_by_subject_and_key_id(
+ const X509_Certificate* find_cert(
const X509_DN& subject_dn,
const std::vector<byte>& key_id) const override;
- std::vector<X509_CRL> find_crl_by_issuer_and_key_id(
- const X509_DN& issuer_dn,
- const std::vector<byte>& key_id) const override;
+ const X509_CRL* find_crl(const X509_Certificate& subject) const override;
private:
// TODO: Add indexing on the DN and key id to avoid linear search
std::vector<X509_Certificate> m_certs;
std::vector<X509_CRL> m_crls;
};
-// TODO: file backed store
-// TODO: directory backed store (eg /usr/share/ca-certificates)
-// TODO: sqlite3 backed store
+class BOTAN_DLL Certificate_Store_Overlay : public Certificate_Store
+ {
+ public:
+ Certificate_Store_Overlay(const std::vector<X509_Certificate>& certs) :
+ m_certs(certs) {}
+
+ std::vector<X509_DN> all_subjects() const override;
+
+ const X509_Certificate* find_cert(
+ const X509_DN& subject_dn,
+ const std::vector<byte>& key_id) const override;
+ private:
+ const std::vector<X509_Certificate>& m_certs;
+ };
}
diff --git a/src/cert/x509/info.txt b/src/cert/x509/info.txt
index 061c52a13..1aebd0c81 100644
--- a/src/cert/x509/info.txt
+++ b/src/cert/x509/info.txt
@@ -2,4 +2,6 @@ define X509_CERTIFICATES 20131128
<requires>
datastor
+http_util
+ocsp
</requires>
diff --git a/src/cert/x509/x509path.cpp b/src/cert/x509/x509path.cpp
index e3cd0b424..c8266c129 100644
--- a/src/cert/x509/x509path.cpp
+++ b/src/cert/x509/x509path.cpp
@@ -20,13 +20,13 @@ namespace {
class PKIX_Validation_Failure : public std::exception
{
public:
- PKIX_Validation_Failure(Path_Validation_Result::Code code) : m_code(code) {}
+ PKIX_Validation_Failure(Certificate_Status_Code code) : m_code(code) {}
- Path_Validation_Result::Code code() const { return m_code; }
+ Certificate_Status_Code code() const { return m_code; }
const char* what() const noexcept { return "PKIX validation failed"; }
private:
- Path_Validation_Result::Code m_code;
+ Certificate_Status_Code m_code;
};
X509_Certificate find_issuing_cert(const X509_Certificate& cert,
@@ -37,157 +37,30 @@ X509_Certificate find_issuing_cert(const X509_Certificate& cert,
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);
-
- if(certs.empty())
- continue;
-
- if(certs.size() > 1)
- throw PKIX_Validation_Failure(Path_Validation_Result::CERT_MULTIPLE_ISSUERS_FOUND);
-
- return certs[0];
+ if(const X509_Certificate* cert = certstores[i]->find_cert(issuer_dn, auth_key_id))
+ return *cert;
}
- throw PKIX_Validation_Failure(Path_Validation_Result::CERT_ISSUER_NOT_FOUND);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND);
}
-std::vector<X509_CRL> find_crls_from(const X509_Certificate& cert,
- const std::vector<Certificate_Store*>& certstores)
+const X509_CRL* find_crls_from(const X509_Certificate& cert,
+ const std::vector<Certificate_Store*>& certstores)
{
const X509_DN issuer_dn = cert.subject_dn();
const std::vector<byte> auth_key_id = cert.subject_key_id();
for(size_t i = 0; i != certstores.size(); ++i)
{
- std::vector<X509_CRL> crl =
- certstores[i]->find_crl_by_issuer_and_key_id(issuer_dn, auth_key_id);
-
- if(!crl.empty())
+ if(const X509_CRL* crl = certstores[i]->find_crl(cert))
return crl;
}
- return std::vector<X509_CRL>();
+ return nullptr;
}
}
-Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
- size_t key_strength) :
- m_require_revocation_information(require_rev),
- m_minimum_key_strength(key_strength)
- {
- 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];
- }
-
-std::set<std::string> Path_Validation_Result::trusted_hashes() const
- {
- std::set<std::string> hashes;
- for(size_t i = 0; i != m_cert_path.size(); ++i)
- hashes.insert(m_cert_path[i].hash_used_for_signature());
- 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 SIGNATURE_METHOD_TOO_WEAK:
- return "signature method too weak";
-
- 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 case
- return "Unknown code " + std::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, restrictions, certstores);
- }
-
-Path_Validation_Result x509_path_validate(
- const std::vector<X509_Certificate>& end_certs,
- const Path_Validation_Restrictions& restrictions,
- const Certificate_Store& store)
- {
- std::vector<Certificate_Store*> certstores;
- certstores.push_back(const_cast<Certificate_Store*>(&store));
-
- return x509_path_validate(end_certs, restrictions, certstores);
- }
-
-Path_Validation_Result x509_path_validate(
- const X509_Certificate& end_cert,
- const Path_Validation_Restrictions& restrictions,
- const Certificate_Store& store)
- {
- std::vector<X509_Certificate> certs;
- certs.push_back(end_cert);
-
- std::vector<Certificate_Store*> certstores;
- certstores.push_back(const_cast<Certificate_Store*>(&store));
-
- 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,
@@ -222,18 +95,12 @@ Path_Validation_Result x509_path_validate(
{
const X509_Certificate& subject = cert_path[i];
- if(!trusted_hashes.empty() && i != cert_path.size() - 1)
- {
- 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(Path_Validation_Result::CERT_NOT_YET_VALID);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CERT_NOT_YET_VALID);
if(current_time > X509_Time(subject.end_time()))
- throw PKIX_Validation_Failure(Path_Validation_Result::CERT_HAS_EXPIRED);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CERT_HAS_EXPIRED);
const bool at_self_signed_root = (i == cert_path.size() - 1);
@@ -244,18 +111,22 @@ Path_Validation_Result x509_path_validate(
// 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(Path_Validation_Result::CA_CERT_NOT_FOR_CERT_ISSUER);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER);
if(issuer.path_limit() < i)
- throw PKIX_Validation_Failure(Path_Validation_Result::CERT_CHAIN_TOO_LONG);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CERT_CHAIN_TOO_LONG);
std::unique_ptr<Public_Key> issuer_key(issuer.subject_public_key());
if(subject.check_signature(*issuer_key) == false)
- throw PKIX_Validation_Failure(Path_Validation_Result::SIGNATURE_ERROR);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::SIGNATURE_ERROR);
if(issuer_key->estimated_strength() < restrictions.minimum_key_strength())
- throw PKIX_Validation_Failure(Path_Validation_Result::SIGNATURE_METHOD_TOO_WEAK);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK);
+
+ if(!trusted_hashes.empty() && !at_self_signed_root)
+ if(!trusted_hashes.count(subject.hash_used_for_signature()))
+ throw PKIX_Validation_Failure(Certificate_Status_Code::UNTRUSTED_HASH);
}
for(size_t i = 1; i != cert_path.size(); ++i)
@@ -263,36 +134,36 @@ Path_Validation_Result x509_path_validate(
const X509_Certificate& subject = cert_path[i-1];
const X509_Certificate& ca = cert_path[i];
- std::vector<X509_CRL> crls = find_crls_from(ca, certstores);
+ const X509_CRL* crl_p = find_crls_from(ca, certstores);
- if(crls.empty())
+ if(!crl_p)
{
if(restrictions.require_revocation_information())
- throw PKIX_Validation_Failure(Path_Validation_Result::CRL_NOT_FOUND);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CRL_NOT_FOUND);
continue;
}
- const X509_CRL& crl = crls[0];
+ const X509_CRL& crl = *crl_p;
if(!ca.allowed_usage(CRL_SIGN))
- throw PKIX_Validation_Failure(Path_Validation_Result::CA_CERT_NOT_FOR_CRL_ISSUER);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
if(current_time < X509_Time(crl.this_update()))
- throw PKIX_Validation_Failure(Path_Validation_Result::CRL_NOT_YET_VALID);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CRL_NOT_YET_VALID);
if(current_time > X509_Time(crl.next_update()))
- throw PKIX_Validation_Failure(Path_Validation_Result::CRL_HAS_EXPIRED);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CRL_HAS_EXPIRED);
if(crl.check_signature(ca.subject_public_key()) == false)
- throw PKIX_Validation_Failure(Path_Validation_Result::SIGNATURE_ERROR);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::SIGNATURE_ERROR);
if(crl.is_revoked(subject))
- throw PKIX_Validation_Failure(Path_Validation_Result::CERT_IS_REVOKED);
+ throw PKIX_Validation_Failure(Certificate_Status_Code::CERT_IS_REVOKED);
}
r.set_result(self_signed_ee_cert ?
- Path_Validation_Result::CANNOT_ESTABLISH_TRUST :
- Path_Validation_Result::VERIFIED);
+ Certificate_Status_Code::CANNOT_ESTABLISH_TRUST :
+ Certificate_Status_Code::VERIFIED);
}
catch(PKIX_Validation_Failure& e)
{
@@ -302,4 +173,133 @@ Path_Validation_Result x509_path_validate(
return r;
}
+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, restrictions, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const std::vector<X509_Certificate>& end_certs,
+ const Path_Validation_Restrictions& restrictions,
+ const Certificate_Store& store)
+ {
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(const_cast<Certificate_Store*>(&store));
+
+ return x509_path_validate(end_certs, restrictions, certstores);
+ }
+
+Path_Validation_Result x509_path_validate(
+ const X509_Certificate& end_cert,
+ const Path_Validation_Restrictions& restrictions,
+ const Certificate_Store& store)
+ {
+ std::vector<X509_Certificate> certs;
+ certs.push_back(end_cert);
+
+ std::vector<Certificate_Store*> certstores;
+ certstores.push_back(const_cast<Certificate_Store*>(&store));
+
+ return x509_path_validate(certs, restrictions, certstores);
+ }
+
+Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
+ size_t key_strength) :
+ m_require_revocation_information(require_rev),
+ m_minimum_key_strength(key_strength)
+ {
+ if(key_strength <= 80)
+ 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];
+ }
+
+std::set<std::string> Path_Validation_Result::trusted_hashes() const
+ {
+ std::set<std::string> hashes;
+ for(size_t i = 0; i != m_cert_path.size(); ++i)
+ hashes.insert(m_cert_path[i].hash_used_for_signature());
+ 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 SIGNATURE_METHOD_TOO_WEAK:
+ return "signature method too weak";
+
+ 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";
+
+ case OCSP_CERT_NOT_LISTED:
+ return "OCSP response does not included requested cert";
+ case OCSP_NOT_YET_VALID:
+ return "OCSP response is from the future";
+ case OCSP_EXPIRED:
+ return "OCSP response is expired";
+ case OCSP_BAD_STATUS:
+ return "OCSP response had unknown/bad status";
+ case OCSP_RESPONSE_GOOD:
+ return "OCSP response had good status";
+ }
+
+ // default case
+ return "Unknown code " + std::to_string(m_result);
+ }
+
}
diff --git a/src/cert/x509/x509path.h b/src/cert/x509/x509path.h
index 829aa9d91..a3854ebf3 100644
--- a/src/cert/x509/x509path.h
+++ b/src/cert/x509/x509path.h
@@ -8,6 +8,7 @@
#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H__
#define BOTAN_X509_CERT_PATH_VALIDATION_H__
+#include <botan/cert_status.h>
#include <botan/x509cert.h>
#include <botan/certstor.h>
#include <set>
@@ -67,39 +68,6 @@ class BOTAN_DLL Path_Validation_Result
{
public:
/**
- * X.509 Certificate Validation Result
- */
- enum Code {
- VERIFIED,
- UNKNOWN_X509_ERROR,
- CANNOT_ESTABLISH_TRUST,
- CERT_CHAIN_TOO_LONG,
- SIGNATURE_ERROR,
- POLICY_ERROR,
- INVALID_USAGE,
-
- SIGNATURE_METHOD_TOO_WEAK,
- 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
- };
-
- /**
* @return the set of hash functions you are implicitly
* trusting by trusting this result.
*/
@@ -123,7 +91,7 @@ class BOTAN_DLL Path_Validation_Result
/**
* @return validation result code
*/
- Code result() const { return m_result; }
+ Certificate_Status_Code result() const { return m_result; }
/**
* @return string representation of the validation result
@@ -138,9 +106,9 @@ class BOTAN_DLL Path_Validation_Result
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores);
- void set_result(Code result) { m_result = result; }
+ void set_result(Certificate_Status_Code result) { m_result = result; }
- Code m_result;
+ Certificate_Status_Code m_result;
std::vector<X509_Certificate> m_cert_path;
};