QSslSocket - make ocsp response into ... ocsp responseS

If later we try to introduce multiple ocsp support, the API returning
a single response will be somewhat broken and illogical/not clear
how to use at all. Let's return a vector of responses (for now it's
one, can change in future). This makes isNull() redundant on a
response, also, we now need 'subject' - a cert that response was for.

Change-Id: Ibbd9dec163b53906b2fd61fa31c43db7d08adc4d
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
bb10
Timur Pocheptsov 2019-01-25 15:11:34 +01:00
parent 5ae8fcd17b
commit 315969725d
7 changed files with 35 additions and 55 deletions

View File

@ -53,11 +53,10 @@ QT_BEGIN_NAMESPACE
The QOcspResponse class represents the revocation status of a server's certficate,
received by the client-side socket during the TLS handshake. QSslSocket must be
configured with OCSP stapling enabled. A non-empty response corresponds to the
certificate that can be obtained from QSslConfiguration::peerCertificate().
configured with OCSP stapling enabled.
\sa QSslSocket, QSslSocket::ocspResponse(), isNull(), clear(), certificateStatus(),
revocationReason(), responder(), OcspCertificateStatus, OcspRevocationReason,
\sa QSslSocket, QSslSocket::ocspResponse(), certificateStatus(),
revocationReason(), responder(), subject(), OcspCertificateStatus, OcspRevocationReason,
QSslConfiguration::setOcspStaplingEnabled(), QSslConfiguration::ocspStaplingEnabled(),
QSslConfiguration::peerCertificate()
*/
@ -110,9 +109,10 @@ QT_BEGIN_NAMESPACE
/*!
\since 5.13
Creates a new, null OCSP response.
Creates a new response with status OcspCertificateStatus::Unknown
and revocation reason OcspRevocationReason::None.
\sa isNull()
\sa OcspCertificateStatus
*/
QOcspResponse::QOcspResponse()
: d(new QOcspResponsePrivate)
@ -132,7 +132,7 @@ QOcspResponse::QOcspResponse(const QOcspResponse &other)
/*!
\since 5.13
Move-constructs a QOcspResponse instance.
Move-constructs a QOcspResponse instance from \a other.
*/
QOcspResponse::QOcspResponse(QOcspResponse &&other) Q_DECL_NOTHROW
{
@ -174,35 +174,6 @@ QOcspResponse &QOcspResponse::operator=(QOcspResponse &&other) Q_DECL_NOTHROW
return *this;
}
/*!
\since 5.13
Returns \c true for default-constructed OCSP responses and also if during a
handshake no definitive OCSP response, or no response was received at all.
\sa QOcspResponse(), QSslSocket::ocspResponse()
*/
bool QOcspResponse::isNull() const
{
return d->isNull;
}
/*!
\since 5.13
Resets this QOcspResponse to its default, null state.
\sa QOcspResponse(), isNull()
*/
void QOcspResponse::clear()
{
d->certificateStatus = OcspCertificateStatus::Unknown;
d->revocationReason = OcspRevocationReason::None;
d->isNull = true;
d->signerCert.clear();
}
/*!
\since 5.13
@ -235,4 +206,14 @@ QSslCertificate QOcspResponse::responder() const
return d->signerCert;
}
/*!
\since 5.13
This function returns a certificate, for which this response was issued.
*/
QSslCertificate QOcspResponse::subject() const
{
return d->subjectCert;
}
QT_END_NAMESPACE

View File

@ -84,13 +84,11 @@ public:
QOcspResponse &operator = (const QOcspResponse &other);
QOcspResponse &operator = (QOcspResponse &&other) Q_DECL_NOTHROW;
bool isNull() const;
void clear();
OcspCertificateStatus certificateStatus() const;
OcspRevocationReason revocationReason() const;
class QSslCertificate responder() const;
QSslCertificate subject() const;
private:

View File

@ -63,9 +63,9 @@ public:
OcspCertificateStatus certificateStatus = OcspCertificateStatus::Unknown;
OcspRevocationReason revocationReason = OcspRevocationReason::None;
bool isNull = true;
QSslCertificate signerCert;
QSslCertificate subjectCert;
};
QT_END_NAMESPACE

View File

@ -1155,16 +1155,16 @@ QSsl::SslProtocol QSslSocket::sessionProtocol() const
/*!
\since 5.13
This function returns Online Certificate Status Protocol response that
a server may send during a TLS handshake using OCSP stapling. If no
definitive or no response was received at all, the response is empty.
This function returns Online Certificate Status Protocol responses that
a server may send during a TLS handshake using OCSP stapling. The vector
is empty if no definitive response or no response at all was received.
\sa QSslConfiguration::setOcspStaplingEnabled(), QOcspResponse::isNull()
\sa QSslConfiguration::setOcspStaplingEnabled()
*/
QOcspResponse QSslSocket::ocspResponse() const
QVector<QOcspResponse> QSslSocket::ocspResponses() const
{
Q_D(const QSslSocket);
return d->ocspResponse;
return d->ocspResponses;
}
/*!
@ -2150,7 +2150,7 @@ void QSslSocketPrivate::init()
shutdown = false;
pendingClose = false;
flushTriggered = false;
ocspResponse.clear();
ocspResponses.clear();
// we don't want to clear the ignoreErrorsList, so
// that it is possible setting it before connecting

View File

@ -61,6 +61,7 @@ class QSslConfiguration;
class QSslEllipticCurve;
class QSslPreSharedKeyAuthenticator;
class QOcspResponse;
template<class> class QVector;
class QSslSocketPrivate;
class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket
@ -143,7 +144,7 @@ public:
QList<QSslCertificate> peerCertificateChain() const;
QSslCipher sessionCipher() const;
QSsl::SslProtocol sessionProtocol() const;
QOcspResponse ocspResponse() const;
QVector<QOcspResponse> ocspResponses() const;
// Private keys, for server sockets.
void setPrivateKey(const QSslKey &key);

View File

@ -1458,9 +1458,7 @@ 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();
ocspResponses.clear();
ocspErrorDescription.clear();
ocspErrors.clear();
@ -1556,7 +1554,9 @@ 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;
ocspResponses.push_back(QOcspResponse());
QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
dResponse->subjectCert = configuration.peerCertificate;
bool matchFound = false;
if (configuration.peerCertificate.isSelfSigned()) {
dResponse->signerCert = configuration.peerCertificate;
@ -1599,7 +1599,7 @@ bool QSslSocketBackendPrivate::checkOcspStatus()
// This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer
// to be != nullptr.
ocspErrors.clear();
ocspResponse.clear();
ocspResponses.clear();
ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse");
return false;
}

View File

@ -66,7 +66,7 @@ class QSslContext;
#endif
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
#include <private/qringbuffer_p.h>
#if defined(Q_OS_MAC)
@ -208,7 +208,7 @@ protected:
bool verifyErrorsHaveBeenIgnored();
bool paused;
bool flushTriggered;
QOcspResponse ocspResponse;
QVector<QOcspResponse> ocspResponses;
};
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)