From e649c4143e37591d5e32ca0b6abb1487cfea4c86 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 16 Jan 2019 14:43:09 +0100 Subject: Add class QOcspResponse, providing a bit more details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit about why a certificate was revoked (if it was) and the responder's certificate, if we managed to verify a signature, as was previously shortly discussed in the 'OCSP stapling' patch-set. Auto-test update will be in a separate patch. [ChangeLog][QtNetwork][Ssl] Added class QOcspResponse as a part of OCSP stapling support. Change-Id: I4e17fb6fc4c3dae0b8ad04ff2897a4823736d16e Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/ssl/qsslsocket_openssl.cpp | 48 +++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'src/network/ssl/qsslsocket_openssl.cpp') diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index d684100313..a7c681920e 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -65,6 +65,7 @@ #include "qsslellipticcurve.h" #include "qsslpresharedkeyauthenticator.h" #include "qsslpresharedkeyauthenticator_p.h" +#include "qocspresponse_p.h" #ifdef Q_OS_WIN #include "qwindowscarootfetcher_p.h" @@ -257,6 +258,34 @@ QSslError qt_OCSP_response_status_to_QSslError(long code) Q_UNREACHABLE(); } +OcspRevocationReason qt_OCSP_revocation_reason(int reason) +{ + switch (reason) { + case OCSP_REVOKED_STATUS_NOSTATUS: + return OcspRevocationReason::None; + case OCSP_REVOKED_STATUS_UNSPECIFIED: + return OcspRevocationReason::Unspecified; + case OCSP_REVOKED_STATUS_KEYCOMPROMISE: + return OcspRevocationReason::KeyCompromise; + case OCSP_REVOKED_STATUS_CACOMPROMISE: + return OcspRevocationReason::CACompromise; + case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: + return OcspRevocationReason::AffiliationChanged; + case OCSP_REVOKED_STATUS_SUPERSEDED: + return OcspRevocationReason::Superseded; + case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: + return OcspRevocationReason::CessationOfOperation; + case OCSP_REVOKED_STATUS_CERTIFICATEHOLD: + return OcspRevocationReason::CertificateHold; + case OCSP_REVOKED_STATUS_REMOVEFROMCRL: + return OcspRevocationReason::RemoveFromCRL; + default: + return OcspRevocationReason::None; + } + + Q_UNREACHABLE(); +} + bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer) { // OCSP_basic_verify does verify that the responder is legit, the response is @@ -1429,6 +1458,9 @@ bool QSslSocketBackendPrivate::checkOcspStatus() Q_ASSERT(mode == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode Q_ASSERT(configuration.peerVerifyMode != QSslSocket::VerifyNone); + ocspResponse.clear(); + QOcspResponsePrivate *dResponse = ocspResponse.d.data(); + ocspErrorDescription.clear(); ocspErrors.clear(); @@ -1524,9 +1556,10 @@ bool QSslSocketBackendPrivate::checkOcspStatus() // Let's make sure the response is for the correct certificate - we // can re-create this CertID using our peer's certificate and its // issuer's public key. - + dResponse->isNull = false; bool matchFound = false; if (configuration.peerCertificate.isSelfSigned()) { + dResponse->signerCert = configuration.peerCertificate; matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509); } else { const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl); @@ -1541,16 +1574,20 @@ bool QSslSocketBackendPrivate::checkOcspStatus() X509 *issuer = q_sk_X509_value(certs, i); matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer); if (matchFound) { - if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) + if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) { + dResponse->signerCert = QSslCertificatePrivate::QSslCertificate_from_X509(issuer); break; + } matchFound = false; } } } } - if (!matchFound) + if (!matchFound) { + dResponse->signerCert.clear(); ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate}); + } // Check if the response is valid time-wise: ASN1_GENERALIZEDTIME *revTime = nullptr; @@ -1562,6 +1599,7 @@ bool QSslSocketBackendPrivate::checkOcspStatus() // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer // to be != nullptr. ocspErrors.clear(); + ocspResponse.clear(); ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse"); return false; } @@ -1582,11 +1620,15 @@ bool QSslSocketBackendPrivate::checkOcspStatus() switch (certStatus) { case V_OCSP_CERTSTATUS_GOOD: // This certificate was not found among the revoked ones. + dResponse->certificateStatus = OcspCertificateStatus::Good; break; case V_OCSP_CERTSTATUS_REVOKED: + dResponse->certificateStatus = OcspCertificateStatus::Revoked; + dResponse->revocationReason = qt_OCSP_revocation_reason(reason); ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate}); break; case V_OCSP_CERTSTATUS_UNKNOWN: + dResponse->certificateStatus = OcspCertificateStatus::Unknown; ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate}); } -- cgit v1.2.3