diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2018-06-04 16:42:13 +0200 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2018-08-09 03:52:02 +0000 |
commit | 4c089601d7982bb45080d57b3399ed0653f69dd1 (patch) | |
tree | 5b7349c66f514997e03744a500b79ed72d4cf718 /src/network/ssl/qdtls.cpp | |
parent | 977c8a4d18a1833c90ba1051d022434755216e0c (diff) |
Document the DTLS API
Task-number: QTBUG-68070
Change-Id: Ifd08ecb7c2c1a6dc352952a10ad56259bd1ecf10
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network/ssl/qdtls.cpp')
-rw-r--r-- | src/network/ssl/qdtls.cpp | 599 |
1 files changed, 589 insertions, 10 deletions
diff --git a/src/network/ssl/qdtls.cpp b/src/network/ssl/qdtls.cpp index afa135845a..3759662505 100644 --- a/src/network/ssl/qdtls.cpp +++ b/src/network/ssl/qdtls.cpp @@ -46,12 +46,294 @@ #include "qglobal.h" -QT_BEGIN_NAMESPACE +/*! + \class QDtlsClientVerifier + \brief This class implements server-side DTLS cookie generation and verification. + \since 5.12 + + \ingroup network + \ingroup ssl + \inmodule QtNetwork + + The QDtlsClientVerifier class implements server-side DTLS cookie generation + and verification. Datagram security protocols are highly susceptible to a + variety of Denial-of-Service attacks. According to \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1}, + these are two of the more common types of attack: + + \list + \li An attacker transmits a series of handshake initiation requests, causing + a server to allocate excessive resources and potentially perform expensive + cryptographic operations. + \li An attacker transmits a series of handshake initiation requests with + a forged source of the victim, making the server act as an amplifier. + Normally, the server would reply to the victim machine with a Certificate message, + which can be quite large, thus flooding the victim machine with datagrams. + \endlist + + As a countermeasure to these attacks, \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1} + proposes a stateless cookie technique that a server may deploy: + + \list + \li In response to the initial ClientHello message, the server sends a HelloVerifyRequest, + which contains a cookie. This cookie is a cryptographic hash and is generated using the + client's address, port number, and the server's secret (which is a cryptographically strong + pseudo-random sequence of bytes). + \li A reachable DTLS client is expected to reply with a new ClientHello message + containing this cookie. + \li When the server receives the ClientHello message with a cookie, it + generates a new cookie as described above. This new cookie is compared to the + one found in the ClientHello message. + \li In the cookies are equal, the client is considered to be real, and the + server can continue with a TLS handshake procedure. + \endlist + + \note A DTLS server is not required to use DTLS cookies. + + QDtlsClientVerifier is designed to work in pair with QUdpSocket, as shown in + the following code-excerpt: + + \snippet code/src_network_ssl_qdtlscookie.cpp 0 + + QDtlsClientVerifier does not impose any restrictions on how the application uses + QUdpSocket. For example, it is possible to have a server with a single QUdpSocket + in state QAbstractSocket::BoundState, handling multiple DTLS clients + simultaneously: + + \list + \li Testing if new clients are real DTLS-capable clients. + \li Completing TLS handshakes with the verified clients (see QDtls). + \li Decrypting datagrams coming from the connected clients (see QDtls). + \li Sending encrypted datagrams to the connected clients (see QDtls). + \endlist + + This implies that QDtlsClientVerifier does not read directly from a socket, + instead it expects the application to read an incoming datagram, extract the + sender's address, and port, and then pass this data to verifyClient(). + To send a HelloVerifyRequest message, verifyClient() can write to the QUdpSocket. + + \note QDtlsClientVerifier does not take ownership of the QUdpSocket object. + + By default QDtlsClientVerifier obtains its secret from a cryptographically + strong pseudorandom number generator. + + \note The default secret is shared by all objects of the classes QDtlsClientVerifier + and QDtls. Since this can impose security risks, RFC 6347 recommends to change + the server's secret frequently. Please see \l {https://tools.ietf.org/html/rfc6347}{RFC 6347, section 4.2.1} + for hints about possible server implementations. Cookie generator parameters + can be set using the class QDtlsClientVerifier::GeneratorParameters and + setCookieGeneratorParameters(): + + \snippet code/src_network_ssl_qdtlscookie.cpp 1 + + The \l{secureudpserver}{DTLS server} example illustrates how to use + QDtlsClientVerifier in a server application. + + \sa QUdpSocket, QAbstractSocket::BoundState, QDtls, verifyClient(), + GeneratorParameters, setCookieGeneratorParameters(), cookieGeneratorParameters(), + QDtls::setCookieGeneratorParameters(), + QDtls::cookieGeneratorParameters(), + QCryptographicHash::Algorithm, + QDtlsError, dtlsError(), dtlsErrorString() +*/ + +/*! + \class QDtlsClientVerifier::GeneratorParameters + \brief This class defines parameters for DTLS cookie generator. + \since 5.12 + + \ingroup network + \ingroup ssl + \inmodule QtNetwork + + An object of this class provides the parameters that QDtlsClientVerifier + will use to generate DTLS cookies. They include a cryptographic hash + algorithm and a secret. + + \note An empty secret is considered to be invalid by + QDtlsClientVerifier::setCookieGeneratorParameters(). + + \sa QDtlsClientVerifier::setCookieGeneratorParameters(), + QDtlsClientVerifier::cookieGeneratorParameters(), + QDtls::setCookieGeneratorParameters(), + QDtls::cookieGeneratorParameters(), + QCryptographicHash::Algorithm +*/ + +/*! + \enum QDtlsError + \brief Describes errors that can be found by QDtls and QDtlsClientVerifier. + \relates QDtls + \since 5.12 + + \ingroup network + \ingroup ssl + \inmodule QtNetwork + + This enum describes general and TLS-specific errors that can be encountered + by objects of the classes QDtlsClientVerifier and QDtls. + + \value NoError No error occurred, the last operation was successful. + \value InvalidInputParameters Input parameters provided by a caller were + invalid. + \value InvalidOperation An operation was attempted in a state that did not + permit it. + \value UnderlyingSocketError QUdpSocket::writeDatagram() failed, QUdpSocket::error() + and QUdpSocket::errorString() can provide more specific information. + \value RemoteClosedConnectionError TLS shutdown alert message was received. + \value PeerVerificationError Peer's identity could not be verified during the + TLS handshake. + \value TlsInitializationError An error occurred while initializing an underlying + TLS backend. + \value TlsFatalError A fatal error occurred during TLS handshake, other + than peer verification error or TLS initialization error. + \value TlsNonFatalError A failure to encrypt or decrypt a datagram, non-fatal, + meaning QDtls can continue working after this error. +*/ + +/*! + \class QDtls + \brief This class provides encryption for UDP sockets. + \since 5.12 + + \ingroup network + \ingroup ssl + \inmodule QtNetwork + + The QDtls class can be used to establish a secure connection with a network + peer using User Datagram Protocol (UDP). DTLS connection over essentially + connectionless UDP means that two peers first have to successfully complete + a TLS handshake by calling doHandshake(). After the handshake has completed, + encrypted datagrams can be sent to the peer using writeDatagramEncrypted(). + Encrypted datagrams coming from the peer can be decrypted by decryptDatagram(). + + QDtls is designed to work with QUdpSocket. Since QUdpSocket can receive + datagrams coming from different peers, an application must implement + demultiplexing, forwarding datagrams coming from different peers to their + corresponding instances of QDtls. An association between a network peer + and its QDtls object can be established using the peer's address and port + number. Before starting a handshake, the application must set the peer's + address and port number using setPeer(). + + QDtls does not read datagrams from QUdpSocket, this is expected to be done by + the application, for example, in a slot attached to the QUdpSocket::readyRead() + signal. Then, these datagrams must be processed by QDtls. + + \note QDtls does \e not take ownership of the QUdpSocket object. + + Normally, several datagrams are to be received and sent by both peers during + the handshake phase. Upon reading datagrams, server and client must pass these + datagrams to doHandshake() until some error is found or handshakeState() + returns HandshakeComplete: + + \snippet code/src_network_ssl_qdtls.cpp 0 + + For a server, the first call to doHandshake() requires a non-empty datagram + containing a ClientHello message. If the server also deploys QDtlsClientVerifier, + the first ClientHello message is expected to be the one verified by QDtlsClientVerifier. + + In case the peer's identity cannot be validated during the handshake, the application + must inspect errors returned by peerVerificationErrors() and then either + ignore errors by calling ignoreVerificationErrors() or abort the handshake + by calling abortHandshake(). If errors were ignored, the handshake can be + resumed by calling resumeHandshake(). + + After the handshake has been completed, datagrams can be sent to and received + from the network peer securely: + + \snippet code/src_network_ssl_qdtls.cpp 2 + + A DTLS connection may be closed using shutdown(). + + \snippet code/src_network_ssl_qdtls.cpp 3 + + \warning It's recommended to call shutdown() before destroying the client's QDtls + object if you are planning to re-use the same port number to connect to the + server later. Otherwise, the server may drop incoming ClientHello messages, + see \l{https://tools.ietf.org/html/rfc6347#page-25}{RFC 6347, section 4.2.8} + for more details and implementation hints. + + If the server does not use QDtlsClientVerifier, it \e must configure its + QDtls objects to disable the cookie verification procedure: + + \snippet code/src_network_ssl_qdtls.cpp 4 + + A server that uses cookie verification with non-default generator parameters + \e must set the same parameters for its QDtls object before starting the handshake. + + \note The DTLS protocol leaves Path Maximum Transmission Unit (PMTU) discovery + to the application. The application may provide QDtls with the MTU using + setMtuHint(). This hint affects only the handshake phase, since only handshake + messages can be fragmented and reassembled by the DTLS. All other messages sent + by the application must fit into a single datagram. + \note DTLS-specific headers add some overhead to application data further + reducing the possible message size. + \warning A server configured to reply with HelloVerifyRequest will drop + all fragmented ClientHello messages, never starting a handshake. + + The \l{secureudpserver}{DTLS server} and \l{secureudpclient}{DTLS client} + examples illustrate how to use QDtls in applications. + + \sa QUdpSocket, QDtlsClientVerifier, HandshakeState, QDtlsError, QSslConfiguration +*/ + +/*! + \fn void QDtls::handshakeTimeout() -namespace -{ + Packet loss can result in timeouts during the handshake phase. In this case + QDtls emits a handshakeTimeout() signal. Call handleTimeout() to retransmit + the handshake messages: + + \snippet code/src_network_ssl_qdtls.cpp 1 + + \sa handleTimeout() +*/ + +/*! + \fn void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator) + + QDtls emits this signal when it negotiates a PSK ciphersuite, and therefore + a PSK authentication is then required. + + When using PSK, the client must send to the server a valid identity and a + valid pre shared key, in order for the TLS handshake to continue. + Applications can provide this information in a slot connected to this + signal, by filling in the passed \a authenticator object according to their + needs. + + \note Ignoring this signal, or failing to provide the required credentials, + will cause the handshake to fail, and therefore the connection to be aborted. + + \note The \a authenticator object is owned by QDtls and must not be deleted + by the application. + + \sa QSslPreSharedKeyAuthenticator +*/ -bool isDtlsProtocol(QSsl::SslProtocol protocol) +/*! + \enum QDtls::HandshakeState + \brief Describes the current state of DTLS handshake. + \since 5.12 + + \ingroup network + \ingroup ssl + \inmodule QtNetwork + + This enum describes the current state of DTLS handshake for a QDtls + connection. + + \value HandshakeNotStarted Nothing done yet. + \value HandshakeInProgress Handshake was initiated and no errors were found so far. + \value PeerVerificationFailed The identity of the peer can't be established. + \value HandshakeComplete Handshake completed successfully and encrypted connection + was established. + + \sa QDtls::doHandshake(), QDtls::handshakeState() +*/ + + +QT_BEGIN_NAMESPACE + +static bool isDtlsProtocol(QSsl::SslProtocol protocol) { switch (protocol) { case QSsl::DtlsV1_0: @@ -64,8 +346,6 @@ bool isDtlsProtocol(QSsl::SslProtocol protocol) } } -} - QSslConfiguration QDtlsBasePrivate::configuration() const { auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration); @@ -118,6 +398,41 @@ bool QDtlsBasePrivate::setCookieGeneratorParameters(QCryptographicHash::Algorith return true; } +static QString msgUnsupportedMulticastAddress() +{ + return QDtls::tr("Multicast and broadcast addresses are not supported"); +} + +/*! + Default constructs GeneratorParameters object with QCryptographicHash::Sha1 + as its algorithm and an empty secret. + + \sa QDtlsClientVerifier::setCookieGeneratorParameters(), + QDtlsClientVerifier::cookieGeneratorParameters(), + QDtls::setCookieGeneratorParameters(), + QDtls::cookieGeneratorParameters() + */ +QDtlsClientVerifier::GeneratorParameters::GeneratorParameters() +{ +} + +/*! + Constructs GeneratorParameters object from \a algorithm and \a secret. + + \sa QDtlsClientVerifier::setCookieGeneratorParameters(), + QDtlsClientVerifier::cookieGeneratorParameters(), + QDtls::setCookieGeneratorParameters(), + QDtls::cookieGeneratorParameters() + */ +QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash::Algorithm algorithm, const QByteArray &secret) + : hash(algorithm), secret(secret) +{ +} + +/*! + Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's + constructor. +*/ QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent) : QObject(*new QDtlsClientVerifierOpenSSL, parent) { @@ -132,6 +447,16 @@ QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent) d->setConfiguration(conf); } +/*! + Sets the secret and cryptographic hash algorithm that this QDtlsClientVerifier + will use to generate cookies. If the new secret has size zero, this function + returns \c false and does not change the previous generator parameters. + + \note The secret is supposed to be a cryptographically secure sequence of bytes. + + \sa QDtlsClientVerifier::GeneratorParameters, cookieGeneratorParameters(), + QCryptographicHash::Algorithm +*/ bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters ¶ms) { Q_D(QDtlsClientVerifier); @@ -139,6 +464,16 @@ bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters return d->setCookieGeneratorParameters(params.hash, params.secret); } +/*! + Returns the current secret and hash algorithm used to generate cookies. + The default hash algorithm is QCryptographicHash::Sha256 if Qt was configured + to support it, QCryptographicHash::Sha1 otherwise. The default secret is + obtained from the backend-specific cryptographically strong pseudorandom + number generator. + + \sa QCryptographicHash::Algorithm, QDtlsClientVerifier::GeneratorParameters, + setCookieGeneratorParameters() +*/ QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorParameters() const { Q_D(const QDtlsClientVerifier); @@ -146,11 +481,20 @@ QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorPar return {d->hashAlgorithm, d->secret}; } -static QString msgUnsupportedMulticastAddress() -{ - return QDtls::tr("Multicast and broadcast addresses are not supported"); -} +/*! + \a socket must be a valid pointer, \a dgram must be a non-empty datagram, + \a address cannot be null, broadcast, or multicast. This function returns + \c true if \a dgram contains a ClientHello message with a valid cookie. + If no matching cookie is found, verifyClient() will send a HelloVerifyRequest + message using \a socket and will return \c false. + The following snippet shows how a server application may check for errors: + + \snippet code/src_network_ssl_qdtlscookie.cpp 2 + + \sa QHostAddress::isNull(), QHostAddress::isBroadcast(), QHostAddress::isMulticast(), + setCookieGeneratorParameters(), cookieGeneratorParameters() +*/ bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port) { @@ -171,6 +515,12 @@ bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgr return d->verifyClient(socket, dgram, address, port); } +/*! + Convenience function. Returns the last ClientHello message that was successfully + verified, or an empty QByteArray if no verification has completed. + + \sa verifyClient() +*/ QByteArray QDtlsClientVerifier::verifiedHello() const { Q_D(const QDtlsClientVerifier); @@ -178,6 +528,11 @@ QByteArray QDtlsClientVerifier::verifiedHello() const return d->verifiedClientHello; } +/*! + Returns the last error that occurred or QDtlsError::NoError. + + \sa QDtlsError, dtlsErrorString() +*/ QDtlsError QDtlsClientVerifier::dtlsError() const { Q_D(const QDtlsClientVerifier); @@ -185,6 +540,11 @@ QDtlsError QDtlsClientVerifier::dtlsError() const return d->errorCode; } +/*! + Returns a textual description of the last error, or an empty string. + + \sa dtlsError() + */ QString QDtlsClientVerifier::dtlsErrorString() const { Q_D(const QDtlsBase); @@ -192,6 +552,13 @@ QString QDtlsClientVerifier::dtlsErrorString() const return d->errorDescription; } +/*! + Creates a QDtls object, \a parent is passed to the QObject constructor. + \a mode is QSslSocket::SslServerMode for a server-side DTLS connection or + QSslSocket::SslClientMode for a client. + + \sa sslMode(), QSslSocket::SslSocket +*/ QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent) : QObject(*new QDtlsPrivateOpenSSL, parent) { @@ -201,6 +568,13 @@ QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent) setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration()); } +/*! + Sets the peer's address, \a port, and host name. \a address must not be + null, multicast, or broadcast. \a verificationName is the host name used + for the certificate validation. + + \sa peerAddress(), peerPort(), peerVerificationName() + */ bool QDtls::setPeer(const QHostAddress &address, quint16 port, const QString &verificationName) { @@ -233,6 +607,12 @@ bool QDtls::setPeer(const QHostAddress &address, quint16 port, return true; } +/*! + Sets the host name that will be used for the certificate validation. + \note This function must be called before the handshake starts. + + \sa peerVerificationName(), setPeer() +*/ bool QDtls::setPeerVerificationName(const QString &name) { Q_D(QDtls); @@ -249,6 +629,11 @@ bool QDtls::setPeerVerificationName(const QString &name) return true; } +/*! + Returns the peer's address, set by setPeer(), or QHostAddress::Null. + + \sa setPeer() +*/ QHostAddress QDtls::peerAddress() const { Q_D(const QDtls); @@ -256,6 +641,11 @@ QHostAddress QDtls::peerAddress() const return d->remoteAddress; } +/*! + Returns the peer's port number, set by setPeer(), or 0. + + \sa setPeer() +*/ quint16 QDtls::peerPort() const { Q_D(const QDtlsBase); @@ -263,6 +653,12 @@ quint16 QDtls::peerPort() const return d->remotePort; } +/*! + Returns the host name set by setPeer() or setPeerVerificationName(). + The default value is an empty string. + + \sa setPeerVerificationName(), setPeer() +*/ QString QDtls::peerVerificationName() const { Q_D(const QDtls); @@ -270,6 +666,12 @@ QString QDtls::peerVerificationName() const return d->peerVerificationName; } +/*! + Returns QSslSocket::SslServerMode for a server-side connection and + QSslSocket::SslClientMode for a client. + + \sa QDtls(), QSslSocket::SslMode +*/ QSslSocket::SslMode QDtls::sslMode() const { Q_D(const QDtls); @@ -277,6 +679,12 @@ QSslSocket::SslMode QDtls::sslMode() const return d->mode; } +/*! + \a mtuHint is the maximum transmission unit (MTU), either discovered or guessed + by the application. The application is not required to set this value. + + \sa mtuHint(), QAbstractSocket::PathMtuSocketOption + */ void QDtls::setMtuHint(quint16 mtuHint) { Q_D(QDtls); @@ -284,6 +692,11 @@ void QDtls::setMtuHint(quint16 mtuHint) d->mtuHint = mtuHint; } +/*! + Returns the value previously set by setMtuHint(). The default value is 0. + + \sa setMtuHint() + */ quint16 QDtls::mtuHint() const { Q_D(const QDtls); @@ -291,6 +704,15 @@ quint16 QDtls::mtuHint() const return d->mtuHint; } +/*! + Sets the cryptographic hash algorithm and the secret. This function is only + needed for a server-side QDtls connection. + + \note This function must be called before the handshake starts. + + \sa cookieGeneratorParameters(), doHandshake(), QDtlsClientVerifier, + QDtlsClientVerifier::cookieGeneratorParameters() +*/ bool QDtls::setCookieGeneratorParameters(const GeneratorParameters ¶ms) { Q_D(QDtls); @@ -298,6 +720,17 @@ bool QDtls::setCookieGeneratorParameters(const GeneratorParameters ¶ms) return d->setCookieGeneratorParameters(params.hash, params.secret); } +/*! + Returns the current hash algorithm and secret, either default ones or previously + set by a call to setCookieGeneratorParameters(). + + The default hash algorithm is QCryptographicHash::Sha256 if Qt was + configured to support it, QCryptographicHash::Sha1 otherwise. The default + secret is obtained from the backend-specific cryptographically strong + pseudorandom number generator. + + \sa QDtlsClientVerifier, cookieGeneratorParameters() +*/ QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const { Q_D(const QDtls); @@ -305,6 +738,13 @@ QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const return {d->hashAlgorithm, d->secret}; } +/*! + Sets the connection's TLS configuration from \a configuration. + + \note This function must be called before the handshake starts. + + \sa dtlsConfiguration(), doHandshake() +*/ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration) { Q_D(QDtls); @@ -324,6 +764,12 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration) return false; } +/*! + Returns either the default DTLS configuration or the configuration set by an + earlier call to setDtlsConfiguration(). + + \sa setDtlsConfiguration(), QSslConfiguration::defaultDtlsConfiguration() +*/ QSslConfiguration QDtls::dtlsConfiguration() const { Q_D(const QDtls); @@ -331,6 +777,11 @@ QSslConfiguration QDtls::dtlsConfiguration() const return d->configuration(); } +/*! + Returns the current handshake state for this QDtls. + + \sa doHandshake(), QDtls::HandshakeState + */ QDtls::HandshakeState QDtls::handshakeState()const { Q_D(const QDtls); @@ -338,6 +789,25 @@ QDtls::HandshakeState QDtls::handshakeState()const return d->handshakeState; } +/*! + Starts or continues a DTLS handshake. \a socket must be a valid pointer. + When starting a server-side DTLS handshake, \a dgram must contain the initial + ClientHello message read from QUdpSocket. This function returns \c true if + no error was found. Handshake state can be tested using handshakeState(). + \c false return means some error occurred, use dtlsError() for more + detailed information. + + \note If the identity of the peer can't be established, the error is set to + QDtlsError::PeerVerificationError. If you want to ignore verification errors + and continue connecting, you must call ignoreVerificationErrors() and then + resumeHandshake(). If the errors cannot be ignored, you must call + abortHandshake(). + + \snippet code/src_network_ssl_qdtls.cpp 5 + + \sa handshakeState(), dtlsError(), ignoreVerificationErrors(), resumeHandshake(), + abortHandshake() +*/ bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram) { Q_D(QDtls); @@ -352,6 +822,9 @@ bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram) return false; } +/*! + \internal +*/ bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram) { Q_D(QDtls); @@ -382,6 +855,14 @@ bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram) return d->startHandshake(socket, datagram); } +/*! + If a timeout occures during the handshake, the handshakeTimeout() signal + is emitted. The application must call handleTimeout() to retransmit handshake + messages; handleTimeout() returns \c true if a timeout has occurred, false + otherwise. \a socket must be a valid pointer. + + \sa handshakeTimeout() +*/ bool QDtls::handleTimeout(QUdpSocket *socket) { Q_D(QDtls); @@ -394,6 +875,9 @@ bool QDtls::handleTimeout(QUdpSocket *socket) return d->handleTimeout(socket); } +/*! + \internal +*/ bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram) { Q_D(QDtls); @@ -413,6 +897,12 @@ bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram) return d->continueHandshake(socket, datagram); } +/*! + If peer verification errors were ignored during the handshake, resumeHandshake() + resumes and completes the handshake. \a socket must be a valid pointer. + + \sa doHandshake(), abortHandshake() peerVerificationErrors(), ignoreVerificationErrors() +*/ bool QDtls::resumeHandshake(QUdpSocket *socket) { Q_D(QDtls); @@ -431,6 +921,12 @@ bool QDtls::resumeHandshake(QUdpSocket *socket) return d->resumeHandshake(socket); } +/*! + Aborts the handshake in case peer verification errors could not be ignored. + \a socket must be a valid pointer. + + \sa doHandshake(), resumeHandshakeAfterError() + */ bool QDtls::abortHandshake(QUdpSocket *socket) { Q_D(QDtls); @@ -450,6 +946,13 @@ bool QDtls::abortHandshake(QUdpSocket *socket) return true; } +/*! + Sends an encrypted shutdown alert message and closes the DTLS connection. + Handshake state changes to QDtls::HandshakeNotStarted. \a socket must be a + valid pointer. This function returns \c true on success. + + \sa doHandshake() + */ bool QDtls::shutdown(QUdpSocket *socket) { Q_D(QDtls); @@ -470,6 +973,11 @@ bool QDtls::shutdown(QUdpSocket *socket) return true; } +/*! + Returns \c true if DTLS handshake completed successfully. + + \sa doHandshake(), handshakeState() + */ bool QDtls::isConnectionEncrypted() const { Q_D(const QDtls); @@ -477,6 +985,18 @@ bool QDtls::isConnectionEncrypted() const return d->connectionEncrypted; } +/*! + Returns the cryptographic \l {QSslCipher} {cipher} used by this connection, + or a null cipher if the connection isn't encrypted. The cipher for the + session is selected during the handshake phase. The cipher is used to encrypt + and decrypt data. + + QSslConfiguration provides functions for setting the ordered list of ciphers + from which the handshake phase will eventually select the session cipher. + This ordered list must be in place before the handshake phase begins. + + \sa QSslConfiguration, setDtlsConfiguration(), dtlsConfiguration() +*/ QSslCipher QDtls::sessionCipher() const { Q_D(const QDtls); @@ -484,6 +1004,16 @@ QSslCipher QDtls::sessionCipher() const return d->sessionCipher; } +/*! + Returns the DTLS protocol version used by this connection, or UnknownProtocol + if the connection isn't encrypted yet. The protocol for the connection is selected + during the handshake phase. + + setDtlsConfiguration() can set the preferred version before the handshake starts. + + \sa setDtlsConfiguration(), QSslConfiguration, QSslConfiguration::defaultDtlsConfiguration(), + QSslConfiguration::setProtocol() +*/ QSsl::SslProtocol QDtls::sessionProtocol() const { Q_D(const QDtls); @@ -491,6 +1021,14 @@ QSsl::SslProtocol QDtls::sessionProtocol() const return d->sessionProtocol; } +/*! + Encrypts \a dgram and writes the encrypted data into \a socket. Returns the + number of bytes written, or -1 in case of error. The handshake must be completed + before writing encrypted data. \a socket must be a valid + pointer. + + \sa doHandshake(), handshakeState(), connectionEncrypted(), dtlsError() +*/ qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) { Q_D(QDtls); @@ -509,6 +1047,12 @@ qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram return d->writeDatagramEncrypted(socket, dgram); } +/*! + Decrypts \a dgram and returns its contents as plain text. The handshake must + be completed before datagrams can be decrypted. Depending on the type of the + TLS message the connection may write into \a socket, which must be a valid + pointer. +*/ QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) { Q_D(QDtls); @@ -530,6 +1074,11 @@ QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) return d->decryptDatagram(socket, dgram); } +/*! + Returns the last error encountered by the connection or QDtlsError::NoError. + + \sa dtlsErrorString(), QDtlsError +*/ QDtlsError QDtls::dtlsError() const { Q_D(const QDtls); @@ -537,6 +1086,12 @@ QDtlsError QDtls::dtlsError() const return d->errorCode; } +/*! + Returns a textual description for the last error encountered by the connection + or empty string. + + \sa dtlsError() +*/ QString QDtls::dtlsErrorString() const { Q_D(const QDtls); @@ -544,6 +1099,12 @@ QString QDtls::dtlsErrorString() const return d->errorDescription; } +/*! + Returns errors found while establishing the identity of the peer. + + If you want to continue connecting despite the errors that have occurred, + you must call ignoreVerificationErrors(). +*/ QVector<QSslError> QDtls::peerVerificationErrors() const { Q_D(const QDtls); @@ -551,6 +1112,24 @@ QVector<QSslError> QDtls::peerVerificationErrors() const return d->tlsErrors; } +/*! + This method tells QDtls to ignore only the errors given in \a errors. + + If, for instance, you want to connect to a server that uses a self-signed + certificate, consider the following snippet: + + \snippet code/src_network_ssl_qdtls.cpp 6 + + You can also call this function after doHandshake() encountered the + QDtlsError::PeerVerificationError error, and then resume the handshake by + calling resumeHandshake(). + + Later calls to this function will replace the list of errors that were + passed in previous calls. You can clear the list of errors you want to ignore + by calling this function with an empty list. + + \sa doHandshake(), resumeHandshake(), QSslError +*/ void QDtls::ignoreVerificationErrors(const QVector<QSslError> &errorsToIgnore) { Q_D(QDtls); |