aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPatrick Schmidt <[email protected]>2019-05-24 10:45:13 +0200
committerPatrick Schmidt <[email protected]>2019-05-27 14:47:16 +0200
commit2780d052b592e7ce0443a4bff9d1b649df80f800 (patch)
treeb74625bf1ebb1240467b2fb7828cca74ed3134bd /src
parent4c4e9a6a1c410dfa63ce430965b71efc9526b62e (diff)
add optional max_age for ocsp checks
Diffstat (limited to 'src')
-rw-r--r--src/lib/x509/cert_status.h1
-rw-r--r--src/lib/x509/ocsp.cpp26
-rw-r--r--src/lib/x509/ocsp.h6
-rw-r--r--src/lib/x509/x509path.cpp5
-rw-r--r--src/lib/x509/x509path.h3
-rw-r--r--src/tests/test_ocsp.cpp32
6 files changed, 59 insertions, 14 deletions
diff --git a/src/lib/x509/cert_status.h b/src/lib/x509/cert_status.h
index fc1174df3..b682746f8 100644
--- a/src/lib/x509/cert_status.h
+++ b/src/lib/x509/cert_status.h
@@ -48,6 +48,7 @@ enum class Certificate_Status_Code {
OCSP_HAS_EXPIRED = 2003,
CRL_NOT_YET_VALID = 2004,
CRL_HAS_EXPIRED = 2005,
+ OCSP_IS_TOO_OLD = 2006,
// Chain generation problems
CERT_ISSUER_NOT_FOUND = 3000,
diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp
index de229d412..7907d08e2 100644
--- a/src/lib/x509/ocsp.cpp
+++ b/src/lib/x509/ocsp.cpp
@@ -269,11 +269,12 @@ Certificate_Status_Code Response::check_signature(const std::vector<Certificate_
}
Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
- const X509_Certificate& subject,
- std::chrono::system_clock::time_point ref_time) const
+ const X509_Certificate& subject,
+ std::chrono::system_clock::time_point ref_time,
+ std::chrono::seconds max_age) const
{
- if (m_responses.empty())
- return m_dummy_response_status;
+ if(m_responses.empty())
+ { return m_dummy_response_status; }
for(const auto& response : m_responses)
{
@@ -282,18 +283,23 @@ Certificate_Status_Code Response::status_for(const X509_Certificate& issuer,
X509_Time x509_ref_time(ref_time);
if(response.cert_status() == 1)
- return Certificate_Status_Code::CERT_IS_REVOKED;
+ { return Certificate_Status_Code::CERT_IS_REVOKED; }
if(response.this_update() > x509_ref_time)
- return Certificate_Status_Code::OCSP_NOT_YET_VALID;
+ { return Certificate_Status_Code::OCSP_NOT_YET_VALID; }
- if(response.next_update().time_is_set() && x509_ref_time > response.next_update())
- return Certificate_Status_Code::OCSP_HAS_EXPIRED;
+ if(response.next_update().time_is_set())
+ {
+ if(x509_ref_time > response.next_update())
+ { return Certificate_Status_Code::OCSP_HAS_EXPIRED; }
+ }
+ else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age)
+ { return Certificate_Status_Code::OCSP_IS_TOO_OLD; }
if(response.cert_status() == 0)
- return Certificate_Status_Code::OCSP_RESPONSE_GOOD;
+ { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; }
else
- return Certificate_Status_Code::OCSP_BAD_STATUS;
+ { return Certificate_Status_Code::OCSP_BAD_STATUS; }
}
}
diff --git a/src/lib/x509/ocsp.h b/src/lib/x509/ocsp.h
index 884b1c5b3..e9d09850f 100644
--- a/src/lib/x509/ocsp.h
+++ b/src/lib/x509/ocsp.h
@@ -139,17 +139,21 @@ class BOTAN_PUBLIC_API(2,0) Response final
* @param issuer issuer certificate
* @param subject subject certificate
* @param ref_time the reference time
+ * @param max_age the maximum age the response should be considered valid
+ * if next_update is not set
* @return OCSP status code, possible values:
* CERT_IS_REVOKED,
* OCSP_NOT_YET_VALID,
* OCSP_HAS_EXPIRED,
+ * OCSP_IS_TOO_OLD,
* OCSP_RESPONSE_GOOD,
* OCSP_BAD_STATUS,
* OCSP_CERT_NOT_LISTED
*/
Certificate_Status_Code status_for(const X509_Certificate& issuer,
const X509_Certificate& subject,
- std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const;
+ std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now(),
+ std::chrono::seconds max_age = std::chrono::seconds::zero()) const;
/**
* @return the certificate chain, if provided in response
diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp
index 9d886ca7a..a889aa4d4 100644
--- a/src/lib/x509/x509path.cpp
+++ b/src/lib/x509/x509path.cpp
@@ -204,7 +204,8 @@ CertificatePathStatusCodes
PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
const std::vector<Certificate_Store*>& trusted_certstores,
- std::chrono::system_clock::time_point ref_time)
+ std::chrono::system_clock::time_point ref_time,
+ std::chrono::seconds max_age)
{
if(cert_path.empty())
throw Invalid_Argument("PKIX::check_ocsp cert_path empty");
@@ -227,7 +228,7 @@ PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cer
if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK)
{
// Signature ok, so check the claimed status
- Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time);
+ Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time, max_age);
status.insert(ocsp_status);
}
else
diff --git a/src/lib/x509/x509path.h b/src/lib/x509/x509path.h
index 841f1a8ef..3e457b970 100644
--- a/src/lib/x509/x509path.h
+++ b/src/lib/x509/x509path.h
@@ -352,7 +352,8 @@ CertificatePathStatusCodes
BOTAN_PUBLIC_API(2,0) check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
const std::vector<Certificate_Store*>& certstores,
- std::chrono::system_clock::time_point ref_time);
+ std::chrono::system_clock::time_point ref_time,
+ std::chrono::seconds max_age = std::chrono::seconds::zero());
/**
* Check CRLs for revocation information
diff --git a/src/tests/test_ocsp.cpp b/src/tests/test_ocsp.cpp
index 753e4455b..1e7676c48 100644
--- a/src/tests/test_ocsp.cpp
+++ b/src/tests/test_ocsp.cpp
@@ -154,6 +154,37 @@ class OCSP_Tests final : public Test
return result;
}
+ Test::Result test_response_verification_too_old()
+ {
+ Test::Result result("OCSP request check if too old");
+
+ std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/randombit.pem");
+ std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/letsencrypt.pem");
+ std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/geotrust.pem");
+
+ const std::vector<std::shared_ptr<const Botan::X509_Certificate>> cert_path = { ee, ca, trust_root };
+
+ std::shared_ptr<const Botan::OCSP::Response> ocsp = load_test_OCSP_resp("x509/ocsp/randombit_ocsp.der");
+
+ Botan::Certificate_Store_In_Memory certstore;
+ certstore.add_certificate(trust_root);
+
+ // Some arbitrary time within the validity period of the test certs
+ const auto valid_time = Botan::calendar_point(2016, 11, 20, 8, 30, 0).to_std_timepoint();
+ const auto max_age = std::chrono::hours(1);
+ const auto ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time, max_age);
+
+ if(result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1))
+ {
+ if(result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1))
+ {
+ result.confirm("Status good", ocsp_status[0].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD));
+ }
+ }
+
+ return result;
+ }
+
Test::Result test_response_verification_softfail()
{
Test::Result result("OCSP request softfail check");
@@ -225,6 +256,7 @@ class OCSP_Tests final : public Test
results.push_back(test_response_parsing());
results.push_back(test_response_certificate_access());
results.push_back(test_response_verification());
+ results.push_back(test_response_verification_too_old());
results.push_back(test_response_verification_softfail());
#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)