aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-10-21 16:44:10 -0400
committerJack Lloyd <[email protected]>2016-10-21 16:44:10 -0400
commit6aa855bba613c7b6fedfbe71d15930964acb1633 (patch)
tree2365c5a5bba8d77c5703e036c111dbeeb317cde3
parent6ceeab949aae9d53914838c542e7b156c80b4b57 (diff)
Allow setting the validation time during PKIX path validation
Previously validation asked the system clock which is not always the correct thing (for example when using Roughtime protocol). Had been on the todo list forever, forced into it by some of the test certs expiring today.
-rw-r--r--src/lib/cert/x509/x509path.cpp34
-rw-r--r--src/lib/cert/x509/x509path.h13
-rw-r--r--src/tests/test_x509_path.cpp6
3 files changed, 34 insertions, 19 deletions
diff --git a/src/lib/cert/x509/x509path.cpp b/src/lib/cert/x509/x509path.cpp
index a0cae2c93..f0b07e5fc 100644
--- a/src/lib/cert/x509/x509path.cpp
+++ b/src/lib/cert/x509/x509path.cpp
@@ -77,13 +77,14 @@ std::shared_ptr<const X509_CRL> find_crls_for(const X509_Certificate& cert,
std::vector<std::set<Certificate_Status_Code>>
check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
const Path_Validation_Restrictions& restrictions,
- const std::vector<Certificate_Store*>& certstores)
+ const std::vector<Certificate_Store*>& certstores,
+ std::chrono::system_clock::time_point ref_time)
{
const std::set<std::string>& trusted_hashes = restrictions.trusted_hashes();
const bool self_signed_ee_cert = (cert_path.size() == 1);
- X509_Time current_time(std::chrono::system_clock::now());
+ X509_Time validation_time(ref_time);
std::vector<std::future<OCSP::Response>> ocsp_responses;
@@ -109,10 +110,10 @@ check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_pat
}
// Check all certs for valid time range
- if(current_time < X509_Time(subject->start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
+ if(validation_time < X509_Time(subject->start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID);
- if(current_time > X509_Time(subject->end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
+ if(validation_time > X509_Time(subject->end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED);
// Check issuer constraints
@@ -198,10 +199,10 @@ check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_pat
if(!ca->allowed_usage(CRL_SIGN))
status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
- if(current_time < X509_Time(crl.this_update()))
+ if(validation_time < X509_Time(crl.this_update()))
status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID);
- if(current_time > X509_Time(crl.next_update()))
+ if(validation_time > X509_Time(crl.next_update()))
status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED);
if(crl.check_signature(ca->subject_public_key()) == false)
@@ -224,7 +225,8 @@ Path_Validation_Result x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores,
const std::string& hostname,
- Usage_Type usage)
+ Usage_Type usage,
+ std::chrono::system_clock::time_point validation_time)
{
if(end_certs.empty())
throw Invalid_Argument("x509_path_validate called with no subjects");
@@ -259,7 +261,8 @@ Path_Validation_Result x509_path_validate(
cert_path.push_back(cert);
}
- std::vector<std::set<Certificate_Status_Code>> res = check_chain(cert_path, restrictions, certstores);
+ std::vector<std::set<Certificate_Status_Code>> res =
+ check_chain(cert_path, restrictions, certstores, validation_time);
if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
res[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
@@ -275,11 +278,12 @@ Path_Validation_Result x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores,
const std::string& hostname,
- Usage_Type usage)
+ Usage_Type usage,
+ std::chrono::system_clock::time_point when)
{
std::vector<X509_Certificate> certs;
certs.push_back(end_cert);
- return x509_path_validate(certs, restrictions, certstores, hostname, usage);
+ return x509_path_validate(certs, restrictions, certstores, hostname, usage, when);
}
Path_Validation_Result x509_path_validate(
@@ -287,12 +291,13 @@ Path_Validation_Result x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const Certificate_Store& store,
const std::string& hostname,
- Usage_Type usage)
+ Usage_Type usage,
+ std::chrono::system_clock::time_point when)
{
std::vector<Certificate_Store*> certstores;
certstores.push_back(const_cast<Certificate_Store*>(&store));
- return x509_path_validate(end_certs, restrictions, certstores, hostname, usage);
+ return x509_path_validate(end_certs, restrictions, certstores, hostname, usage, when);
}
Path_Validation_Result x509_path_validate(
@@ -300,7 +305,8 @@ Path_Validation_Result x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const Certificate_Store& store,
const std::string& hostname,
- Usage_Type usage)
+ Usage_Type usage,
+ std::chrono::system_clock::time_point when)
{
std::vector<X509_Certificate> certs;
certs.push_back(end_cert);
@@ -308,7 +314,7 @@ Path_Validation_Result x509_path_validate(
std::vector<Certificate_Store*> certstores;
certstores.push_back(const_cast<Certificate_Store*>(&store));
- return x509_path_validate(certs, restrictions, certstores, hostname, usage);
+ return x509_path_validate(certs, restrictions, certstores, hostname, usage, when);
}
Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
diff --git a/src/lib/cert/x509/x509path.h b/src/lib/cert/x509/x509path.h
index 362f65852..b33069f72 100644
--- a/src/lib/cert/x509/x509path.h
+++ b/src/lib/cert/x509/x509path.h
@@ -12,6 +12,7 @@
#include <botan/x509cert.h>
#include <botan/certstor.h>
#include <set>
+#include <chrono>
namespace Botan {
@@ -175,7 +176,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores,
const std::string& hostname = "",
- Usage_Type usage = Usage_Type::UNSPECIFIED);
+ Usage_Type usage = Usage_Type::UNSPECIFIED,
+ std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now());
/**
* PKIX Path Validation
@@ -191,7 +193,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores,
const std::string& hostname = "",
- Usage_Type usage = Usage_Type::UNSPECIFIED);
+ Usage_Type usage = Usage_Type::UNSPECIFIED,
+ std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now());
/**
* PKIX Path Validation
@@ -207,7 +210,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const Certificate_Store& store,
const std::string& hostname = "",
- Usage_Type usage = Usage_Type::UNSPECIFIED);
+ Usage_Type usage = Usage_Type::UNSPECIFIED,
+ std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now());
/**
* PKIX Path Validation
@@ -223,7 +227,8 @@ Path_Validation_Result BOTAN_DLL x509_path_validate(
const Path_Validation_Restrictions& restrictions,
const Certificate_Store& store,
const std::string& hostname = "",
- Usage_Type usage = Usage_Type::UNSPECIFIED);
+ Usage_Type usage = Usage_Type::UNSPECIFIED,
+ std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now());
}
diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp
index 96cc7a190..ae52de541 100644
--- a/src/tests/test_x509_path.cpp
+++ b/src/tests/test_x509_path.cpp
@@ -8,6 +8,7 @@
#if defined(BOTAN_HAS_X509_CERTIFICATES)
#include <botan/x509path.h>
+ #include <botan/calendar.h>
#include <botan/internal/filesystem.h>
#endif
@@ -70,6 +71,8 @@ class X509test_Path_Validation_Tests : public Test
Botan::Certificate_Store_In_Memory trusted;
trusted.add_certificate(root);
+ auto validation_time = Botan::calendar_point(2016,10,21,4,20,0).to_std_timepoint();
+
for(auto i = expected.begin(); i != expected.end(); ++i)
{
Test::Result result("X509test path validation");
@@ -84,7 +87,8 @@ class X509test_Path_Validation_Tests : public Test
Botan::Path_Validation_Result path_result = Botan::x509_path_validate(
certs, default_restrictions, trusted,
- "www.tls.test", Botan::Usage_Type::TLS_SERVER_AUTH);
+ "www.tls.test", Botan::Usage_Type::TLS_SERVER_AUTH,
+ validation_time);
if(path_result.successful_validation() && path_result.trust_root() != root)
path_result = Botan::Path_Validation_Result(Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST);