diff options
author | Patrick Schmidt <[email protected]> | 2019-05-24 10:45:13 +0200 |
---|---|---|
committer | Patrick Schmidt <[email protected]> | 2019-05-27 14:47:16 +0200 |
commit | 2780d052b592e7ce0443a4bff9d1b649df80f800 (patch) | |
tree | b74625bf1ebb1240467b2fb7828cca74ed3134bd /src | |
parent | 4c4e9a6a1c410dfa63ce430965b71efc9526b62e (diff) |
add optional max_age for ocsp checks
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/x509/cert_status.h | 1 | ||||
-rw-r--r-- | src/lib/x509/ocsp.cpp | 26 | ||||
-rw-r--r-- | src/lib/x509/ocsp.h | 6 | ||||
-rw-r--r-- | src/lib/x509/x509path.cpp | 5 | ||||
-rw-r--r-- | src/lib/x509/x509path.h | 3 | ||||
-rw-r--r-- | src/tests/test_ocsp.cpp | 32 |
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) |