diff --git a/src/crypto/OCSP.cpp b/src/crypto/OCSP.cpp index 86262053d..4a158594a 100644 --- a/src/crypto/OCSP.cpp +++ b/src/crypto/OCSP.cpp @@ -34,6 +34,7 @@ #include #include #include +#include using namespace digidoc; using namespace std; @@ -203,6 +204,10 @@ void OCSP::verifyResponse(const X509Cert &cert) const } } auto store = X509CertStore::createStore(X509CertStore::OCSP, tm); + // OCSP_NOCHECKS skips ocsp_check_issuer() which requires the responder to be directly + // delegated by the cert's issuing CA. SK PKI uses a cross-CA OCSP responder issued by + // the root CA rather than the intermediate CA, so this check would always fail. + // We compensate by verifying the responder cert has id-kp-OCSPSigning EKU below. if(OCSP_basic_verify(basic.get(), stack.get(), store.get(), OCSP_NOCHECKS | OCSP_PARTIAL_CHAIN) != 1) { unsigned long err = ERR_get_error(); @@ -217,7 +222,7 @@ void OCSP::verifyResponse(const X509Cert &cert) const throw OpenSSLException(EXCEPTION_PARAMS("Failed to verify OCSP response."), err); } - // Find issuer before OCSP validation to activate region TSL + // Find issuer before status validation X509Cert issuer = X509CertStore::instance()->findIssuer(cert, X509CertStore::CA); if(!issuer) { @@ -226,6 +231,19 @@ void OCSP::verifyResponse(const X509Cert &cert) const throw e; } + // Explicitly check the OCSP responder has id-kp-OCSPSigning EKU (normally done by + // ocsp_check_issuer which we skipped above). + if(X509Cert responder = responderCert(); responder) + { + bool hasOCSPSign = issuer == responder; + auto eku = make_unique_cast( + X509_get_ext_d2i(responder.handle(), NID_ext_key_usage, nullptr, nullptr)); + for(int i = 0; eku && i < sk_ASN1_OBJECT_num(eku.get()); i++) + hasOCSPSign |= OBJ_obj2nid(sk_ASN1_OBJECT_value(eku.get(), i)) == NID_OCSP_sign; + if(!hasOCSPSign) + THROW("OCSP responder certificate does not have id-kp-OCSPSigning EKU"); + } + int status = V_OCSP_CERTSTATUS_UNKNOWN; for(int i = 0, count = OCSP_resp_count(basic.get()); i < count; ++i) {