diff options
-rw-r--r-- | src/lib/x509/cert_status.cpp | 2 | ||||
-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/data/x509/ocsp/bdrive_encryption.pem | 43 | ||||
-rw-r--r-- | src/tests/data/x509/ocsp/bdrive_root.pem | 31 | ||||
-rw-r--r-- | src/tests/data/x509/ocsp/patrickschmidt.pem | 46 | ||||
-rw-r--r-- | src/tests/data/x509/ocsp/patrickschmidt_ocsp.der | bin | 0 -> 4235 bytes | |||
-rw-r--r-- | src/tests/test_ocsp.cpp | 149 |
11 files changed, 287 insertions, 25 deletions
diff --git a/src/lib/x509/cert_status.cpp b/src/lib/x509/cert_status.cpp index 79bcd1b07..4efd49edf 100644 --- a/src/lib/x509/cert_status.cpp +++ b/src/lib/x509/cert_status.cpp @@ -46,6 +46,8 @@ const char* to_string(Certificate_Status_Code code) return "OCSP is not yet valid"; case Certificate_Status_Code::OCSP_HAS_EXPIRED: return "OCSP response has expired"; + case Certificate_Status_Code::OCSP_IS_TOO_OLD: + return "OCSP response is too old"; case Certificate_Status_Code::CRL_NOT_YET_VALID: return "CRL response is not yet valid"; case Certificate_Status_Code::CRL_HAS_EXPIRED: 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/data/x509/ocsp/bdrive_encryption.pem b/src/tests/data/x509/ocsp/bdrive_encryption.pem new file mode 100644 index 000000000..395027a3a --- /dev/null +++ b/src/tests/data/x509/ocsp/bdrive_encryption.pem @@ -0,0 +1,43 @@ +-----BEGIN CERTIFICATE----- +MIIHiDCCBXCgAwIBAgIDD+SyMA0GCSqGSIb3DQEBDQUAMEwxCzAJBgNVBAYTAkRF +MR0wGwYDVQQKExRCdW5kZXNkcnVja2VyZWkgR21iSDEeMBwGA1UEAxMVQmRyaXZl +IFJvb3QgQ0EgMSAyMDE3MB4XDTE3MDYyOTE2MTAzNVoXDTMyMDYyOTEyMzAxNlow +ZTELMAkGA1UEBhMCREUxHTAbBgNVBAoTFEJ1bmRlc2RydWNrZXJlaSBHbWJIMRow +GAYDVQQLExFCZHJpdmUgRW5jcnlwdGlvbjEbMBkGA1UEAxMSQmRyaXZlIENBIDEt +MSAyMDE3MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuRNrAhqeS6J9 +v1LKzWsbKFt2HpfL4DsL5LGlc7AsDtYUsR117waFIsHQ0au+fRwY6FdBgDNntr1u +IGX26OUcHuVWDVyGQfEOlW4/OBg6vF2HkX7qds0BIaJqUwBhpFV+MZB8n7/njMRU +i0dKO0JAydIkr2cbtb6CPRnv6Hq3irEGv6GuXAAr77ja+CTuAEnH2W/XSwfj/nwe +U87LrVx5XMV7K7kkjd69TaSsowJk3wJ8XVGiT0TdontqqKH5uYu9qNFdjlEB6HXE +go3ookMyCIRF77lxAIznS/kHlsW/qwvvHWOJCBsktNbwAIYAGSohXQFhj7aAp6Qd +VB9B7A/lJ5O6IjdqpgmK+PRblfcmpvmo5TgNmVN3mAkBt+dI5kgRAuq7Opo8ZWyg +6/AQueeRrcBO2Cglxo4RMKsFht8CNcfbpdoqo+rQmcfmDqTEPa9VgqKBdmmZPc5W +1CCHlzASRJq95zLN9E6jIa9jUctWDrlcTTvLsF7cefGJGrq1t4KlzMVvxZ1MojWt +BxFyywLyiQJUSH+NZtmrAv1lA9398Sh/HP+wJ7mVXkGXGiqWbeMy1MQGvD/nWn6L +hJFR6q1Dk4z+Y69yGAZ3/kJ3KUduOft8uvfpp3bE6pWc8c2U+qt89r1VB9uCWJ6s +8Lq/0AQsMGpyQCDpBNSN9ZXt4BvNNskCAwEAAaOCAlgwggJUMB8GA1UdIwQYMBaA +FHKvqBQDb73a+QPjH7s39hTffforMIIBDwYIKwYBBQUHAQEEggEBMIH+MDkGCCsG +AQUFBzABhi1odHRwOi8vYmRyaXZlLXJvb3QtY2EtMS0yMDE3Lm9jc3AuZC10cnVz +dC5uZXQwRAYIKwYBBQUHMAKGOGh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY2dpLWJp +bi9CZHJpdmVfUm9vdF9DQV8xXzIwMTcuY3J0MHsGCCsGAQUFBzAChm9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUJkcml2ZSUyMFJvb3QlMjBDQSUyMDEl +MjAyMDE3LE89QnVuZGVzZHJ1Y2tlcmVpJTIwR21iSCxDPURFP2NBQ2VydGlmaWNh +dGU/YmFzZT8wFwYDVR0gBBAwDjAMBgoqghQAUIU9g3QBMIHBBgNVHR8EgbkwgbYw +gbOggbCgga2GdWxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049QmRyaXZl +JTIwUm9vdCUyMENBJTIwMSUyMDIwMTcsTz1CdW5kZXNkcnVja2VyZWklMjBHbWJI +LEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdIY0aHR0cDovL2NybC5kLXRy +dXN0Lm5ldC9jcmwvYmRyaXZlX3Jvb3RfY2FfMV8yMDE3LmNybDAdBgNVHQ4EFgQU +3PghhQ8DCnR3GLZtlmKvvrwca5YwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQAwDQYJKoZIhvcNAQENBQADggIBAClBw10/yUy4lN+VdvT71l22aMoC +LvrdyArq+XN5p2NTji0hGBVNLicGT8/GJ9Pssf8E4RbH3QCwhb68T7Kg5Atcn0e3 +5q7jws4ZuWOlpT2sgYkilWOi+Okp6Ty+QStgdpRsQ2U4RKpO0/h/0V0fv6VRaYVk +j6IRyd2pgAkrrutQh7F20D29j0emLmc0SF2hn++AACY7V021drKIJsEmbiQ7h68t +cFLZl660LYwJ+1ZrQDmcJTghROFi6DLb4dk/xPYlb2PoonBaGThCbyCNa+SpqbfS +6zoaBNMaYaA11zXoV/2fReYBtj5NZTu1KyqKfYcm/yAxws1a/lbf1moGdNwsxcxV +M3EcyZMkgB/XkPtjLCxCfKDonp0T4rt+pDgt+wfvyE8BUEXm8A6v+HD7rn8xmiLB +h/vhFIDqNaA9DlfjQFGU+d+JN/Iv92IZk63cqDn6kMJPiewscrrws4oc/V2yKi6v +Iicq3VRFsyrzdlcTWodQCIO4uKUBDJIqXfCs4wr6aW/JH4iGKDGYn4dcc9lLJ5sq +m2rTQyWJMa7+M6ZT4UrYX/rISr/i4KT/fHPR3HR9Oxv0mM6hGl2ihClegEhMEIeQ +vb/GhyisXfCxPNzDJawna+wm+rYZ4vcJq0/C3XVpv2vnraYTfqgASBevElDhmSZa +nsfsTJkA8VidAuBl +-----END CERTIFICATE----- diff --git a/src/tests/data/x509/ocsp/bdrive_root.pem b/src/tests/data/x509/ocsp/bdrive_root.pem new file mode 100644 index 000000000..21a29974a --- /dev/null +++ b/src/tests/data/x509/ocsp/bdrive_root.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgIDD+SxMA0GCSqGSIb3DQEBDQUAMEwxCzAJBgNVBAYTAkRF +MR0wGwYDVQQKExRCdW5kZXNkcnVja2VyZWkgR21iSDEeMBwGA1UEAxMVQmRyaXZl +IFJvb3QgQ0EgMSAyMDE3MB4XDTE3MDYyOTEyMzAxNloXDTMyMDYyOTEyMzAxNlow +TDELMAkGA1UEBhMCREUxHTAbBgNVBAoTFEJ1bmRlc2RydWNrZXJlaSBHbWJIMR4w +HAYDVQQDExVCZHJpdmUgUm9vdCBDQSAxIDIwMTcwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDSEdramwmqOL/lpQE3nEejFYIneJv8ruPMAhnjBeavcPWL +WUMaDP3jyU1S5PDF+QXJYszZhNPwED0NBv7fnQ4qbpbYLYWkfncBpzrBorwo6yub ++rlurRRsSd0rQjUuRNS9/iaJhriISWyakktj6+POyGDH/dCNjz3z+nwPzclJvIo0 +1R5vJbt24H6ScIINmJVMGiZ/rCYpzhzsY+rwyso+wmqoJ/jzJPt5J2FQ7vsA3GAM +ekVUtYc6xgIEsIBD4Jvm0Pq1neHr2WqADh4POT922kaki65MUsPOmd7eaE2bBeSR +/cTmbk5Qm2S6YpIRlQWW642gx4foQLaMSr+g7pRGpuQRhDk6tWIzcTkVQ0eyQz8s +qLSzGq5FZGtlRmDGgZBo37pD8aLqI12qqecAg46QTDoAn68KsDwhQUefZqJO7g5j +nD6sPBDuiSIHb97j5MQhu5/Qs5za8UT/x38wP57cpCEhtAegqBfdqg/1ZifD+xma +x282uympWgXxbRAfjEy59g9RwcK8jaP+r1E0qPcNiD+WG4f7DRhc4C7VF9ekSyH5 +MnIIipDyw094CXSoNBvoU5xISTkOOGm8q+plWun6wRTq6jZdExgTHzBQeTos664k +SS8ibVhUbIiNPEmYKvNY+4kZs9oZxNE2KXitKEIXxgZIm0VgK7/a3XAU01b5CQID +AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRyr6gUA2+92vkD4x+7 +N/YU3336KzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAD34vu6J +ZsC7UrXA5pwlOo1VKhIU5e8o6OjgbJ8FDmOP0YakwAe9B4TSIFhRjohXGM7Rj3mx +8zolPucMH95hNpeG/23af6tgy6a8+xeL/TTy0LMTYNcHaeRhyOIi6Hp3Om6+LhCG +/R/JRO0ilMEDHbZ4d3vAQ9x+QLiVuz2d4yw6eR3ucOVoXImlsO63O8n8QlI+SW6o +n8+L5EpMK7EcHlnqJKFqA1yPmZz/6sTUTaFVw/JeAEbACnP7+8EDT9yuE5H4IvTh +3Y0BHB6+nh/2koqZsuF+/hhjSP8Sp7LUH5Eu7plwsdLeUY7JXDTl5R8eCycwiMi3 +prpQacDKzdUb42zNkBcGdBQ99DG+emNjd2/Nwsp7r7nZltOx3C+emqLXIWoSkWvv +vdzukpJrhdkt4GPpGUv2I87yuxkqrRwSychrE+jVERyI8O7QjqWdsRSOAk6N7svm +zTKIwP6Rmj3LCu8UD4kiSOhdwAzuMTv8AKywZAYQ9eEEuuIoDTfWMIk2AYnklPVP +s00mKMlkjMt2EZZCKnNzQyZHn1jVRweqotKmZPCgtwUxvYscaz9PaEPsIC5DQc73 +6fpC5oGp4yXQBrw8dVzX65/sYy7GDCDzCxk8yM5lVXSdeufPOMCxIVDXXTbWBDDU +7mRl/EOq5wivzBx6bFGIRkSCPqi2T7oWPfoA +-----END CERTIFICATE----- diff --git a/src/tests/data/x509/ocsp/patrickschmidt.pem b/src/tests/data/x509/ocsp/patrickschmidt.pem new file mode 100644 index 000000000..0455f4b71 --- /dev/null +++ b/src/tests/data/x509/ocsp/patrickschmidt.pem @@ -0,0 +1,46 @@ +-----BEGIN CERTIFICATE----- +MIIINDCCBhygAwIBAgIDJF8VMA0GCSqGSIb3DQEBDQUAMGUxCzAJBgNVBAYTAkRF +MR0wGwYDVQQKExRCdW5kZXNkcnVja2VyZWkgR21iSDEaMBgGA1UECxMRQmRyaXZl +IEVuY3J5cHRpb24xGzAZBgNVBAMTEkJkcml2ZSBDQSAxLTEgMjAxNzAeFw0xOTAx +MTQxODU0MDhaFw0yMjAxMTQxODU0MDhaMIHiMQswCQYDVQQGEwJERTEQMA4GA1UE +ChMHTmV4ZW5pbzEtMCsGA1UECxMkMzcyZTc0NmItZTQ3NS00NWMyLWI4MmMtMzM0 +MTM4YTY2NDA3MRgwFgYDVQQDEw9QYXRyaWNrIFNjaG1pZHQxFTATBgNVBAUTDENT +TTAxNDgwMTMwOTEPMA0GA1UEBxMGQmVybGluMT8wPQYJKoZIhvcNAQkBFjAzNzJl +NzQ2Yi1lNDc1LTQ1YzItYjgyYy0zMzQxMzhhNjY0MDdAYmRyLW1haWwuZGUxDzAN +BgNVBAgTBkJlcmxpbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANoU +hK4HbAr3pRT0U62M9shiq1JK3209oZtFAyXbUdN5SFE7MXRefn2gE/x0W2Eq/PAr +dCbM8I7DovtXfnWpiJGYlM/WU8oGoWpayn7rkYfDicDuTFK0VwISXeRsvSf2DFv0 +eSdhVscyYle8sgNn9wBH2/nhOuSeeXBWOg/h9sGgiKkOVXZkNgZxNKdcet5kbVNW +lGfxa7LRJQMbTZL6WjgrrNKCJFEih7gRaEQsaPcCiaBOwDv8G89c2V4Cd45XmhAr +1YF7t42iMdW6aEDkohD5UW/eqvrb0VXWB02WrcQn/6X17hQzVRKol90DU/8LZ+9G +qSrb/x6byd9M4NGWHqr+dpskY2PW/eJdpyQd0pluCXbTPVkrebntsn1z0md95Rdq +HiOz3AZ6TN1noS7gmCHX4o/HBiAHc7SU8FziY1iDKofah17isAP7JD5L8TfBGiie +pcDTTn1tSSfzvgoI5mDUl10yyJ/fPXvlp4pKhIMCwwDKQOaAcKLYsRmi4cp+OsX6 +hGX4qcS3FiOF3u+pB/tggZ6Se1GkR6zJiAqeW7neRFuiU3+zVmrtLaAb1qm6vaUj +ZBfAWgUg2p1ug2FG+17K6NMf4ST2wgiTi64UmMQES6UBDxX2PkRfd+ooQE7JS8wU +jhmikglhOMwM+pb77NTOn0Dr3wmKinbBO3ngH00hAgMBAAGjggJtMIICaTAfBgNV +HSMEGDAWgBTc+CGFDwMKdHcYtm2WYq++vBxrljCCAQMGCCsGAQUFBwEBBIH2MIHz +MDYGCCsGAQUFBzABhipodHRwOi8vYmRyaXZlLWNhLTEtMS0yMDE3Lm9jc3AuZC10 +cnVzdC5uZXQwQQYIKwYBBQUHMAKGNWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY2dp +LWJpbi9CZHJpdmVfQ0FfMS0xXzIwMTcuY3J0MHYGCCsGAQUFBzAChmpsZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUJkcml2ZSUyMENBJTIwMS0xJTIwMjAx +NyxPPUJ1bmRlc2RydWNrZXJlaSUyMEdtYkgsQz1ERT9jQUNlcnRpZmljYXRlP2Jh +c2U/MBcGA1UdIAQQMA4wDAYKKoIUAFCFPYN0ATCBuQYDVR0fBIGxMIGuMIGroIGo +oIGlhnBsZGFwOi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUJkcml2ZSUyMENB +JTIwMS0xJTIwMjAxNyxPPUJ1bmRlc2RydWNrZXJlaSUyMEdtYkgsQz1ERT9jZXJ0 +aWZpY2F0ZXJldm9jYXRpb25saXN0hjFodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2Ny +bC9iZHJpdmVfY2FfMS0xXzIwMTcuY3JsMB0GA1UdDgQWBBRhGyV3lS9YNFG5FcWR +Ic5WTHPJJTAOBgNVHQ8BAf8EBAMCBDAwOwYDVR0RBDQwMoEwMzcyZTc0NmItZTQ3 +NS00NWMyLWI4MmMtMzM0MTM4YTY2NDA3QGJkci1tYWlsLmRlMA0GCSqGSIb3DQEB +DQUAA4ICAQAWD20kwhIJxYK6Ma3y/dV2lPsZqGb5z2JYoLzgsEp9INTeqwqxwFer +aSJmEkYxuR2z+g17lzeVCbu5ijHi0P1a6uKf6sB7goNorVC9ipU5gCTwt5LcZ66d +ZuXVTEc3XUsu6CJ4r1e1kAJckKugWkWvM/UqnhCYQMnm6GgoJA0PlwVLDpy4myQL +DEQvUqhDD+iPm0tttzLeoJ5g+gtsEMFqq96EFfkv8mHQLDvqDqT91QjoNBUNc7hQ +s7qlvQjCS15ntTCOV6ruvwAFDacCcFuFSyRN9wnf3TxgJ36q4JKAIiC1VrjqJWTD +yGO+2gIFkuCwRjSgsTy0bjtsTTe2rJVf5GXqDcrQQqaJdrv21XFlhwRuhjulkseU +ocWjvByMG/2rBhOQRXNHGkxsrUrlaVMaA+erdUgU4vGBQq1OfGtnDzLzB+XSYVH1 +8+Mc8DdS2TyhcnYTpA7ZLUOcXRxen68m+0QmNY5uKo0OqSbH1vU8/upme3BKL702 +08jtRbYLGMy+E0gVcIttZbQU2FGlmWXz4uTopgSeCvl1VVs9U+J+65UZlHi2gUVr +fNdGaRoMg9nYcDnxYCDaauAgeulHawquH8Ir3XBXmEkje4c56h7cnjPiCp1Yxg0a +ox1cE2ofXhF7Alk31z971RbA3dhfPPxGZ9AU3CAQA+leUkdjfCvtmw== +-----END CERTIFICATE----- diff --git a/src/tests/data/x509/ocsp/patrickschmidt_ocsp.der b/src/tests/data/x509/ocsp/patrickschmidt_ocsp.der Binary files differnew file mode 100644 index 000000000..39a7b20a5 --- /dev/null +++ b/src/tests/data/x509/ocsp/patrickschmidt_ocsp.der diff --git a/src/tests/test_ocsp.cpp b/src/tests/test_ocsp.cpp index 753e4455b..5c28c128d 100644 --- a/src/tests/test_ocsp.cpp +++ b/src/tests/test_ocsp.cpp @@ -124,9 +124,47 @@ class OCSP_Tests final : public Test return result; } - Test::Result test_response_verification() + Test::Result test_response_verification_with_next_update_without_max_age() { - Test::Result result("OCSP request check"); + Test::Result result("OCSP request check with next_update w/o max_age"); + + 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); + + auto check_ocsp = [&](const std::chrono::system_clock::time_point valid_time, + const Botan::Certificate_Status_Code expected) + { + const auto ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time); + + return result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1) && + result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1) && + result.confirm(std::string("Status: '") + Botan::to_string(expected) + "'", + ocsp_status[0].count(expected)); + }; + + check_ocsp(Botan::calendar_point(2016, 11, 11, 12, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID); + check_ocsp(Botan::calendar_point(2016, 11, 18, 12, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2016, 11, 20, 8, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2016, 11, 28, 8, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED); + + return result; + } + + Test::Result test_response_verification_with_next_update_with_max_age() + { + Test::Result result("OCSP request check with next_update with max_age"); 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"); @@ -140,16 +178,102 @@ class OCSP_Tests final : public Test 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 ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time); + const auto max_age = std::chrono::minutes(59); - if(result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1)) + auto check_ocsp = [&](const std::chrono::system_clock::time_point valid_time, + const Botan::Certificate_Status_Code expected) { - 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)); - } - } + const auto ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time, max_age); + + return result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1) && + result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1) && + result.confirm(std::string("Status: '") + Botan::to_string(expected) + "'", + ocsp_status[0].count(expected)); + }; + + check_ocsp(Botan::calendar_point(2016, 11, 11, 12, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID); + check_ocsp(Botan::calendar_point(2016, 11, 18, 12, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2016, 11, 20, 8, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2016, 11, 28, 8, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED); + + return result; + } + + Test::Result test_response_verification_without_next_update_with_max_age() + { + Test::Result result("OCSP request check w/o next_update with max_age"); + + std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem"); + std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem"); + std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.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/patrickschmidt_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 max_age = std::chrono::minutes(59); + + auto check_ocsp = [&](const std::chrono::system_clock::time_point valid_time, + const Botan::Certificate_Status_Code expected) + { + const auto ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time, max_age); + + return result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1) && + result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1) && + result.confirm(std::string("Status: '") + Botan::to_string(expected) + "'", + ocsp_status[0].count(expected)); + }; + + check_ocsp(Botan::calendar_point(2019, 5, 28, 7, 0, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID); + check_ocsp(Botan::calendar_point(2019, 5, 28, 7, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2019, 5, 28, 8, 0, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_IS_TOO_OLD); + + return result; + } + + Test::Result test_response_verification_without_next_update_without_max_age() + { + Test::Result result("OCSP request check w/o next_update w/o max_age"); + + std::shared_ptr<const Botan::X509_Certificate> ee = load_test_X509_cert("x509/ocsp/patrickschmidt.pem"); + std::shared_ptr<const Botan::X509_Certificate> ca = load_test_X509_cert("x509/ocsp/bdrive_encryption.pem"); + std::shared_ptr<const Botan::X509_Certificate> trust_root = load_test_X509_cert("x509/ocsp/bdrive_root.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/patrickschmidt_ocsp.der"); + + Botan::Certificate_Store_In_Memory certstore; + certstore.add_certificate(trust_root); + + auto check_ocsp = [&](const std::chrono::system_clock::time_point valid_time, + const Botan::Certificate_Status_Code expected) + { + const auto ocsp_status = Botan::PKIX::check_ocsp(cert_path, { ocsp }, { &certstore }, valid_time); + + return result.test_eq("Expected size of ocsp_status", ocsp_status.size(), 1) && + result.test_eq("Expected size of ocsp_status[0]", ocsp_status[0].size(), 1) && + result.confirm(std::string("Status: '") + Botan::to_string(expected) + "'", + ocsp_status[0].count(expected)); + }; + + check_ocsp(Botan::calendar_point(2019, 5, 28, 7, 0, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID); + check_ocsp(Botan::calendar_point(2019, 5, 28, 7, 30, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); + check_ocsp(Botan::calendar_point(2019, 5, 28, 8, 0, 0).to_std_timepoint(), + Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD); return result; } @@ -224,7 +348,10 @@ class OCSP_Tests final : public Test results.push_back(test_request_encoding()); 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_with_next_update_without_max_age()); + results.push_back(test_response_verification_with_next_update_with_max_age()); + results.push_back(test_response_verification_without_next_update_with_max_age()); + results.push_back(test_response_verification_without_next_update_without_max_age()); results.push_back(test_response_verification_softfail()); #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) |