OCSP response - fix API

as proposed in the API review.

Change-Id: I607a38d24d533da59fc0d33dac886fa7693ed6c8
Fixes: QTBUG-73739
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
bb10
Timur Pocheptsov 2019-02-11 16:07:04 +01:00
parent 94a4f06fb8
commit 28a87f1f21
5 changed files with 125 additions and 60 deletions

View File

@ -40,6 +40,8 @@
#include "qocspresponse_p.h"
#include "qocspresponse.h"
#include "qhashfunctions.h"
QT_BEGIN_NAMESPACE
/*!
@ -56,13 +58,13 @@ QT_BEGIN_NAMESPACE
configured with OCSP stapling enabled.
\sa QSslSocket, QSslSocket::ocspResponse(), certificateStatus(),
revocationReason(), responder(), subject(), OcspCertificateStatus, OcspRevocationReason,
revocationReason(), responder(), subject(), QOcspCertificateStatus, QOcspRevocationReason,
QSslConfiguration::setOcspStaplingEnabled(), QSslConfiguration::ocspStaplingEnabled(),
QSslConfiguration::peerCertificate()
*/
/*!
\enum OcspCertificateStatus
\enum QOcspCertificateStatus
\brief Describes the Online Certificate Status
\relates QOcspResponse
\since 5.13
@ -79,11 +81,11 @@ QT_BEGIN_NAMESPACE
\value Unknown This state indicates that the responder doesn't know about
the certificate being requested.
\sa OcspRevocationReason
\sa QOcspRevocationReason
*/
/*!
\enum OcspRevocationReason
\enum QOcspRevocationReason
\brief Describes the reason for revocation
\relates QOcspResponse
\since 5.13
@ -109,10 +111,10 @@ QT_BEGIN_NAMESPACE
/*!
\since 5.13
Creates a new response with status OcspCertificateStatus::Unknown
and revocation reason OcspRevocationReason::None.
Creates a new response with status QOcspCertificateStatus::Unknown
and revocation reason QOcspRevocationReason::None.
\sa OcspCertificateStatus
\sa QOcspCertificateStatus
*/
QOcspResponse::QOcspResponse()
: d(new QOcspResponsePrivate)
@ -124,64 +126,51 @@ QOcspResponse::QOcspResponse()
Creates a new response, the copy of \a other.
*/
QOcspResponse::QOcspResponse(const QOcspResponse &other)
{
*d = *other.d;
}
QOcspResponse::QOcspResponse(const QOcspResponse &other) = default;
/*!
\since 5.13
Move-constructs a QOcspResponse instance from \a other.
*/
QOcspResponse::QOcspResponse(QOcspResponse &&other) Q_DECL_NOTHROW
{
d.swap(other.d);
}
QOcspResponse::QOcspResponse(QOcspResponse &&other) Q_DECL_NOTHROW = default;
/*!
\since 5.13
Destroys the response.
*/
QOcspResponse::~QOcspResponse()
{
}
QOcspResponse::~QOcspResponse() = default;
/*!
\since 5.13
Assignes \a other to the response and returns a reference to this response.
Assigns \a other to the response and returns a reference to this response.
*/
QOcspResponse &QOcspResponse::operator=(const QOcspResponse &other)
{
if (this != &other)
*d = *other.d;
return *this;
}
QOcspResponse &QOcspResponse::operator=(const QOcspResponse &other) = default;
/*!
\since 5.13
Move-assigns \a other to this QOcspResponse instance.
*/
QOcspResponse &QOcspResponse::operator=(QOcspResponse &&other) Q_DECL_NOTHROW
{
if (this != &other)
d.swap(other.d);
QOcspResponse &QOcspResponse::operator=(QOcspResponse &&other) Q_DECL_NOTHROW = default;
return *this;
}
/*!
\fn void QOcspResponse::swap(QOcspResponse &other)
\since 5.13
Swaps this response with \a other.
*/
/*!
\since 5.13
Returns the certificate status.
\sa OcspCertificateStatus
\sa QOcspCertificateStatus
*/
OcspCertificateStatus QOcspResponse::certificateStatus() const
QOcspCertificateStatus QOcspResponse::certificateStatus() const
{
return d->certificateStatus;
}
@ -191,7 +180,7 @@ OcspCertificateStatus QOcspResponse::certificateStatus() const
Returns the reason for revocation.
*/
OcspRevocationReason QOcspResponse::revocationReason() const
QOcspRevocationReason QOcspResponse::revocationReason() const
{
return d->revocationReason;
}
@ -216,4 +205,54 @@ QSslCertificate QOcspResponse::subject() const
return d->subjectCert;
}
/*!
\fn bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
Returns \c true if \a lhs and \a rhs are the responses for the same
certificate, signed by the same responder, have the same
revocation reason and the same certificate status.
\since 5.13
\relates QOcspResponse
*/
Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
{
return lhs.d == rhs.d || *lhs.d == *rhs.d;
}
/*!
\fn bool operator != (const QOcspResponse &lhs, const QOcspResponse &rhs)
Returns \c true if \a lhs and \a rhs are responses for different certificates,
or signed by different responders, or have different revocation reasons, or different
certificate statuses.
\since 5.13
\relates QOcspResponse
*/
/*!
\fn uint qHash(const QOcspResponse &response, uint seed)
Returns the hash value for the \a response, using \a seed to seed the calculation.
\since 5.13
\relates QHash
*/
uint qHash(const QOcspResponse &response, uint seed)
{
const QOcspResponsePrivate *d = response.d.data();
Q_ASSERT(d);
QtPrivate::QHashCombine hasher;
uint hash = hasher(seed, int(d->certificateStatus));
hash = hasher(hash, int(d->revocationReason));
if (!d->signerCert.isNull())
hash = hasher(hash, d->signerCert);
if (!d->subjectCert.isNull())
hash = hasher(hash, d->subjectCert);
return hash;
}
QT_END_NAMESPACE

View File

@ -42,8 +42,9 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qobject.h>
#include <QtCore/qscopedpointer.h>
#ifndef Q_CLANG_QDOC
QT_REQUIRE_CONFIG(ssl);
@ -51,14 +52,14 @@ QT_REQUIRE_CONFIG(ssl);
QT_BEGIN_NAMESPACE
enum class OcspCertificateStatus
enum class QOcspCertificateStatus
{
Good,
Revoked,
Unknown
};
enum class OcspRevocationReason
enum class QOcspRevocationReason
{
None = -1,
Unspecified,
@ -71,8 +72,11 @@ enum class OcspRevocationReason
RemoveFromCRL
};
class QOcspResponse;
Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed = 0);
class QOcspResponsePrivate;
class QOcspResponse
class Q_NETWORK_EXPORT QOcspResponse
{
public:
@ -84,18 +88,29 @@ public:
QOcspResponse &operator = (const QOcspResponse &other);
QOcspResponse &operator = (QOcspResponse &&other) Q_DECL_NOTHROW;
OcspCertificateStatus certificateStatus() const;
OcspRevocationReason revocationReason() const;
QOcspCertificateStatus certificateStatus() const;
QOcspRevocationReason revocationReason() const;
class QSslCertificate responder() const;
QSslCertificate subject() const;
void swap(QOcspResponse &other) Q_DECL_NOTHROW { d.swap(other.d); }
private:
friend class QSslSocketBackendPrivate;
QScopedPointer<QOcspResponsePrivate> d;
friend Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs);
friend Q_NETWORK_EXPORT uint qHash(const QOcspResponse &response, uint seed);
QSharedDataPointer<QOcspResponsePrivate> d;
};
inline bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs) { return !(lhs == rhs); }
Q_DECLARE_SHARED(QOcspResponse)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QOcspResponse)
#endif // QOCSPRESPONSE_H

View File

@ -44,6 +44,9 @@
#include <qsslcertificate.h>
#include <qocspresponse.h>
#include <qshareddata.h>
//
// W A R N I N G
// -------------
@ -57,17 +60,25 @@
QT_BEGIN_NAMESPACE
class QOcspResponsePrivate
class QOcspResponsePrivate : public QSharedData
{
public:
OcspCertificateStatus certificateStatus = OcspCertificateStatus::Unknown;
OcspRevocationReason revocationReason = OcspRevocationReason::None;
QOcspCertificateStatus certificateStatus = QOcspCertificateStatus::Unknown;
QOcspRevocationReason revocationReason = QOcspRevocationReason::None;
QSslCertificate signerCert;
QSslCertificate subjectCert;
};
inline bool operator==(const QOcspResponsePrivate &lhs, const QOcspResponsePrivate &rhs)
{
return lhs.certificateStatus == rhs.certificateStatus
&& lhs.revocationReason == rhs.revocationReason
&& lhs.signerCert == rhs.signerCert
&& lhs.subjectCert == rhs.subjectCert;
}
QT_END_NAMESPACE
#endif // QOCSPRESPONSE_P_H

View File

@ -44,6 +44,7 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qlist.h>
#include <QtCore/qregexp.h>
#include <QtCore/qvector.h>
#ifndef QT_NO_SSL
# include <QtNetwork/qtcpsocket.h>
# include <QtNetwork/qsslerror.h>
@ -61,7 +62,6 @@ class QSslConfiguration;
class QSslEllipticCurve;
class QSslPreSharedKeyAuthenticator;
class QOcspResponse;
template<class> class QVector;
class QSslSocketPrivate;
class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket

View File

@ -258,29 +258,29 @@ QSslError qt_OCSP_response_status_to_QSslError(long code)
Q_UNREACHABLE();
}
OcspRevocationReason qt_OCSP_revocation_reason(int reason)
QOcspRevocationReason qt_OCSP_revocation_reason(int reason)
{
switch (reason) {
case OCSP_REVOKED_STATUS_NOSTATUS:
return OcspRevocationReason::None;
return QOcspRevocationReason::None;
case OCSP_REVOKED_STATUS_UNSPECIFIED:
return OcspRevocationReason::Unspecified;
return QOcspRevocationReason::Unspecified;
case OCSP_REVOKED_STATUS_KEYCOMPROMISE:
return OcspRevocationReason::KeyCompromise;
return QOcspRevocationReason::KeyCompromise;
case OCSP_REVOKED_STATUS_CACOMPROMISE:
return OcspRevocationReason::CACompromise;
return QOcspRevocationReason::CACompromise;
case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED:
return OcspRevocationReason::AffiliationChanged;
return QOcspRevocationReason::AffiliationChanged;
case OCSP_REVOKED_STATUS_SUPERSEDED:
return OcspRevocationReason::Superseded;
return QOcspRevocationReason::Superseded;
case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION:
return OcspRevocationReason::CessationOfOperation;
return QOcspRevocationReason::CessationOfOperation;
case OCSP_REVOKED_STATUS_CERTIFICATEHOLD:
return OcspRevocationReason::CertificateHold;
return QOcspRevocationReason::CertificateHold;
case OCSP_REVOKED_STATUS_REMOVEFROMCRL:
return OcspRevocationReason::RemoveFromCRL;
return QOcspRevocationReason::RemoveFromCRL;
default:
return OcspRevocationReason::None;
return QOcspRevocationReason::None;
}
Q_UNREACHABLE();
@ -1624,15 +1624,15 @@ bool QSslSocketBackendPrivate::checkOcspStatus()
switch (certStatus) {
case V_OCSP_CERTSTATUS_GOOD:
// This certificate was not found among the revoked ones.
dResponse->certificateStatus = OcspCertificateStatus::Good;
dResponse->certificateStatus = QOcspCertificateStatus::Good;
break;
case V_OCSP_CERTSTATUS_REVOKED:
dResponse->certificateStatus = OcspCertificateStatus::Revoked;
dResponse->certificateStatus = QOcspCertificateStatus::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;
dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate});
}