QDtls Class

该类为 UDP 套接字提供加密功能。更多

头文件: #include <QDtls>
CMake: find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(mytarget PRIVATE Qt6::Network)
qmake: QT += network
继承: QObject

公共类型

GeneratorParameters
enum HandshakeState { HandshakeNotStarted, HandshakeInProgress, PeerVerificationFailed, HandshakeComplete }

公共函数

QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr)
virtual ~QDtls()
bool abortHandshake(QUdpSocket *socket)
QDtls::GeneratorParameters cookieGeneratorParameters() const
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
bool doHandshake(QUdpSocket *socket, const QByteArray &dgram = {})
QSslConfiguration dtlsConfiguration() const
QDtlsError dtlsError() const
QString dtlsErrorString() const
bool handleTimeout(QUdpSocket *socket)
QDtls::HandshakeState handshakeState() const
void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
bool isConnectionEncrypted() const
quint16 mtuHint() const
QHostAddress peerAddress() const
quint16 peerPort() const
QList<QSslError> peerVerificationErrors() const
QString peerVerificationName() const
bool resumeHandshake(QUdpSocket *socket)
QSslCipher sessionCipher() const
QSsl::SslProtocol sessionProtocol() const
bool setCookieGeneratorParameters(const QDtls::GeneratorParameters &params)
bool setDtlsConfiguration(const QSslConfiguration &configuration)
void setMtuHint(quint16 mtuHint)
bool setPeer(const QHostAddress &address, quint16 port, const QString &verificationName = {})
bool setPeerVerificationName(const QString &name)
bool shutdown(QUdpSocket *socket)
QSslSocket::SslMode sslMode() const
qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)

信号

void handshakeTimeout()
void pskRequired(QSslPreSharedKeyAuthenticator *authenticator)
enum class QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, RemoteClosedConnectionError, …, TlsNonFatalError }

详细说明

QDtls 类可用于使用用户数据报协议(UDP)与网络对等设备建立安全连接。在本质上无连接的 UDP 上建立 DTLS 连接意味着两个对等节点必须首先通过调用doHandshake() 成功完成 TLS 握手。握手完成后,加密数据报可通过writeDatagramEncrypted() 发送给对等方。来自对等方的加密数据报可通过decryptDatagram() 解密。

QDtls 可与QUdpSocket 配合使用。由于QUdpSocket 可以接收来自不同对等点的数据报,因此应用程序必须实现解复用,将来自不同对等点的数据报转发到相应的 QDtls 实例。网络对等体与其 QDtls 对象之间的关联可以使用对等体的地址和端口号来建立。在开始握手之前,应用程序必须使用setPeer() 设置对等程序的地址和端口号。

QDtls 不会从QUdpSocket 中读取数据报,而是由应用程序来读取,例如在连接到QUdpSocket::readyRead() 信号的插槽中读取。然后,这些数据报必须由 QDtls 处理。

注意: QDtls拥有QUdpSocket 对象的所有权。

通常,在握手阶段,双方都要接收和发送多个数据报。在读取数据报时,服务器和客户端必须将这些数据报传递给doHandshake() 直到发现错误或handshakeState() 返回HandshakeComplete

// A client initiates a handshake:
QUdpSocket clientSocket;
QDtls clientDtls;
clientDtls.setPeer(address, port, peerName);
clientDtls.doHandshake(&clientSocket);

// A server accepting an incoming connection; address, port, clientHello are
// read by QUdpSocket::readDatagram():
QByteArray clientHello(serverSocket.pendingDatagramSize(), Qt::Uninitialized);
QHostAddress address;
quin16 port = {};
serverSocket.readDatagram(clientHello.data(), clientHello.size(), &address, &port);

QDtls serverDtls;
serverDtls.setPeer(address, port);
serverDtls.doHandshake(&serverSocket, clientHello);

// Handshake completion, both for server and client:
void DtlsConnection::continueHandshake(const QByteArray &datagram)
{
    if (dtls.doHandshake(&udpSocket, datagram)) {
        // Check handshake status:
        if (dtls.handshakeStatus() == QDlts::HandshakeComplete) {
            // Secure DTLS connection is now established.
        }
    } else {
        // Error handling.
    }
}

对于服务器来说,首次调用doHandshake() 需要一个包含 ClientHello 消息的非空数据报。如果服务器也部署了QDtlsClientVerifier ,则第一个 ClientHello 消息应是经QDtlsClientVerifier 验证的消息。

如果在握手过程中无法验证对等方的身份,应用程序必须检查peerVerificationErrors() 返回的错误,然后要么调用ignoreVerificationErrors() 忽略错误,要么调用abortHandshake() 中止握手。如果忽略了错误,则可以通过调用resumeHandshake() 恢复握手。

握手完成后,数据报就可以安全地发送和接收了:

// Sending an encrypted datagram:
dtlsConnection.writeDatagramEncrypted(&clientSocket, "Hello DTLS server!");

// Decryption:
QByteArray encryptedMessage(dgramSize);
socket.readDatagram(encryptedMessage.data(), dgramSize);
const QByteArray plainText = dtlsConnection.decryptDatagram(&socket, encryptedMessage);

可以使用shutdown() 关闭 DTLS 连接。

DtlsClient::~DtlsClient()
{
    clientDtls.shutdown(&clientSocket);
}

警告: 如果打算以后重新使用相同的端口号连接服务器,建议在销毁客户端的 QDtls 对象之前调用shutdown() 。否则,服务器可能会丢弃传入的 ClientHello 消息,更多详情和实施提示请参阅RFC 6347 第 4.2.8 节

如果服务器不使用QDtlsClientVerifier ,则必须配置其 QDtls 对象以禁用 cookie 验证程序:

auto config = QSslConfiguration::defaultDtlsConfiguration();
config.setDtlsCookieVerificationEnabled(false);
// Some other customization ...
dtlsConnection.setDtlsConfiguration(config);

使用非默认生成器参数进行 Cookie 验证的服务器必须在开始握手之前为其 QDtls 对象设置相同的参数。

注: DTLS 协议将路径最大传输单元(PMTU)的发现留给了应用程序。应用程序可使用setMtuHint() 向 QDtls 提供 MTU。此提示只影响握手阶段,因为 DTLS 只能对握手报文进行分片和重新组装。应用程序发送的所有其他报文都必须包含在一个数据报中。

注意: 特定于 DTLS 的报文头会给应用程序数据增加一些开销,从而进一步减小可能的报文大小。

警告 配置为回复 HelloVerifyRequest 的服务器将丢弃所有零散的 ClientHello 消息,永远不会开始握手。

DTLS 服务器DTLS 客户端示例说明了如何在应用程序中使用 QDtls。

另请参阅 QUdpSocket,QDtlsClientVerifier,HandshakeState,QDtlsErrorQSslConfiguration

成员类型文档

[alias] QDtls::GeneratorParameters

enum QDtls::HandshakeState

描述 DTLS 握手的当前状态。

该枚举描述QDtls 连接的 DTLS 握手的当前状态。

常量描述
QDtls::HandshakeNotStarted0尚未完成。
QDtls::HandshakeInProgress1已开始握手,目前未发现任何错误。
QDtls::PeerVerificationFailed2无法确定对方身份。
QDtls::HandshakeComplete3握手成功完成,加密连接已建立。

另请参阅 QDtls::doHandshake() 和QDtls::handshakeState()。

成员函数文档

[explicit] QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr)

mode 创建 QDtls 对象,parent 传递给QObject 构造函数。对于服务器端 DTLS 连接,QSslSocket::SslServerMode ;对于客户端连接,QSslSocket::SslClientMode

另请参阅 sslMode() 和QSslSocket::SslMode

[virtual noexcept] QDtls::~QDtls()

销毁QDtls 对象。

bool QDtls::abortHandshake(QUdpSocket *socket)

终止正在进行的握手。如果socket 上正在进行握手,则返回 true;否则,设置适当的错误并返回 false。

另请参阅 doHandshake() 和resumeHandshake()。

QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const

返回当前的哈希算法和密文,可以是默认的,也可以是调用setCookieGeneratorParameters() 之前设置的。

如果 Qt XML 被配置为支持哈希算法,则默认哈希算法为QCryptographicHash::Sha256 ,否则为QCryptographicHash::Sha1 。默认密文是从后端特定的强加密伪随机数生成器中获取的。

另请参阅 setCookieGeneratorParameters(),QDtlsClientVerifier, 和 cookieGeneratorParameters()。

QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)

解密dgram 并将其内容作为纯文本返回。数据报解密前必须完成握手。根据 TLS 报文的类型,连接可能会写入socket ,而 必须是一个有效指针。

bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram = {})

开始或继续 DTLS 握手。socket 必须是有效指针。在启动服务器端 DTLS 握手时,dgram 必须包含从QUdpSocket 读取的初始 ClientHello 消息。如果没有发现错误,则返回true 。可使用handshakeState() 测试握手状态。false 返回表示发生了错误,可使用dtlsError() 获取更多详细信息。

注意: 如果无法确定对等方的身份,则会将错误设置为QDtlsError::PeerVerificationError 。如果想忽略验证错误并继续连接,则必须调用ignoreVerificationErrors() 然后再调用resumeHandshake() 。如果无法忽略错误,则必须调用abortHandshake() 。

if (!dtls.doHandshake(&socket, dgram)) {
    if (dtls.dtlsError() == QDtlsError::PeerVerificationError)
        dtls.abortAfterError(&socket);
}

另请参阅 handshakeState()、dtlsError()、ignoreVerificationErrors()、resumeHandshake() 和abortHandshake()。

QSslConfiguration QDtls::dtlsConfiguration() const

返回默认 DTLS 配置或之前调用setDtlsConfiguration() 时设置的配置。

另请参阅 setDtlsConfiguration() 和QSslConfiguration::defaultDtlsConfiguration()。

QDtlsError QDtls::dtlsError() const

返回连接或QDtlsError::NoError 遇到的最后一个错误。

另请参阅 dtlsErrorString() 和QDtlsError

QString QDtls::dtlsErrorString() const

返回连接最后一次出错的文字描述或空字符串。

另请参阅 dtlsError()。

bool QDtls::handleTimeout(QUdpSocket *socket)

如果握手过程中发生超时,则会发出handshakeTimeout() 信号。应用程序必须调用 handleTimeout() 重新传输握手消息;如果发生超时,handleTimeout() 返回true ,否则返回 false。socket 必须是有效指针。

另请参阅 handshakeTimeout().

QDtls::HandshakeState QDtls::handshakeState() const

返回QDtls 的当前握手状态。

另请参阅 doHandshake() 和QDtls::HandshakeState

[signal] void QDtls::handshakeTimeout()

丢包会导致握手阶段超时。在这种情况下,QDtls 会发出 handshakeTimeout() 信号。调用handleTimeout() 重传握手信息:

DtlsClient::DtlsClient()
{
    // Some initialization code here ...
    connect(&clientDtls, &QDtls::handshakeTimeout, this, &DtlsClient::handleTimeout);
}

void DtlsClient::handleTimeout()
{
    clientDtls.handleTimeout(&clientSocket);
}

另请参阅 handleTimeout().

void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)

该方法告诉QDtls 只忽略errorsToIgnore 中给出的错误。

例如,如果您想连接到使用自签名证书的服务器,请考虑以下代码段:

QList<QSslCertificate> cert = QSslCertificate::fromPath("server-certificate.pem"_L1);
QSslError error(QSslError::SelfSignedCertificate, cert.at(0));
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);

QDtls dtls;
dtls.ignoreVerificationErrors(expectedSslErrors);
dtls.doHandshake(udpSocket);

您也可以在doHandshake() 遇到QDtlsError::PeerVerificationError 错误后调用此函数,然后调用resumeHandshake() 继续握手。

以后对该函数的调用将替换之前调用时传递的错误列表。您可以使用空列表调用该函数,清除要忽略的错误列表。

另请参阅 doHandshake()、resumeHandshake() 和QSslError

bool QDtls::isConnectionEncrypted() const

如果 DTLS 握手成功,则返回true

另请参阅 doHandshake() 和handshakeState()。

quint16 QDtls::mtuHint() const

返回之前由setMtuHint() 设置的值。默认值为 0。

另请参见 setMtuHint()。

QHostAddress QDtls::peerAddress() const

返回由setPeer() 或QHostAddress::Null 设置的对等地址。

另请参阅 setPeer()。

quint16 QDtls::peerPort() const

返回setPeer() 设置的对等端口号或 0。

另请参阅 setPeer()。

QList<QSslError> QDtls::peerVerificationErrors() const

返回在建立对等设备身份时发现的错误。

如果想在发生错误的情况下继续连接,必须调用ignoreVerificationErrors() 。

QString QDtls::peerVerificationName() const

返回setPeer() 或setPeerVerificationName() 设置的主机名。默认值为空字符串。

另请参阅 setPeerVerificationName() 和setPeer()。

[signal] void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator)

QDtls 当协商 PSK 密码套件时,服务器会发出该信号,因此需要进行 PSK 验证。

使用 PSK 时,客户端必须向服务器发送有效的身份信息和有效的预共享密钥,才能继续进行 TLS 握手。应用程序可以根据自己的需要,通过填写传递的authenticator 对象,在与该信号相连的插槽中提供这些信息。

注: 忽略此信号或未提供所需凭证将导致握手失败,从而中止连接。

注意: authenticator 对象归QDtls 所有,应用程序不得删除。

另请参阅 QSslPreSharedKeyAuthenticator

bool QDtls::resumeHandshake(QUdpSocket *socket)

如果在握手过程中忽略了对等验证错误,resumeHandshake() 会恢复并完成握手,并返回truesocket 必须是有效指针。如果无法恢复握手,则返回false

另请参阅 doHandshake()、abortHandshake()、peerVerificationErrors() 和ignoreVerificationErrors()。

QSslCipher QDtls::sessionCipher() const

返回此连接使用的加密cipher ,如果连接未加密,则返回空密码。会话的密码在握手阶段选择。密码用于加密和解密数据。

QSslConfiguration 加密狗提供了用于设置有序密码列表的函数,握手阶段最终将从列表中选择会话密码。该有序列表必须在握手阶段开始前准备就绪。

另请参阅 QSslConfigurationsetDtlsConfiguration() 和dtlsConfiguration()。

QSsl::SslProtocol QDtls::sessionProtocol() const

返回此连接使用的 DTLS 协议版本,如果连接尚未加密,则返回 UnknownProtocol。连接的协议在握手阶段选择。

setDtlsConfiguration() 可以在握手开始前设置首选版本。

另请参阅 setDtlsConfiguration()、QSslConfigurationQSslConfiguration::defaultDtlsConfiguration() 和QSslConfiguration::setProtocol()。

bool QDtls::setCookieGeneratorParameters(const QDtls::GeneratorParameters &params)

设置加密哈希算法和来自params 的密文。只有服务器端QDtls 连接才需要此函数。如果成功,则返回true

注意: 必须在握手开始前调用此函数。

另请参阅 cookieGeneratorParameters()、doHandshake()、QDtlsClientVerifierQDtlsClientVerifier::cookieGeneratorParameters()。

bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)

configuration 开始设置连接的 TLS 配置,如果成功则返回true

注意: 必须在握手开始前调用此函数。

另请参阅 dtlsConfiguration() 和doHandshake()。

void QDtls::setMtuHint(quint16 mtuHint)

mtuHint 是最大传输单元 (MTU),由应用程序发现或猜测。应用程序无需设置该值。

另请参阅 mtuHint() 和QAbstractSocket::PathMtuSocketOption

bool QDtls::setPeer(const QHostAddress &address, quint16 port, const QString &verificationName = {})

port true address 不得为空、多播或广播。 是用于证书验证的主机名。verificationName

另请参阅 peerAddress()、peerPort() 和peerVerificationName()。

bool QDtls::setPeerVerificationName(const QString &name)

设置用于证书验证的主机name ,如果成功则返回true

注意: 必须在握手开始前调用此函数。

另请参阅 peerVerificationName() 和setPeer()。

bool QDtls::shutdown(QUdpSocket *socket)

发送加密的关闭警报消息并关闭 DTLS 连接。握手状态更改为QDtls::HandshakeNotStartedsocket 必须是有效指针。该函数成功时返回true

另请参阅 doHandshake()。

QSslSocket::SslMode QDtls::sslMode() const

服务器端连接返回QSslSocket::SslServerMode ,客户端连接返回QSslSocket::SslClientMode

另请参阅 QDtls() 和QSslSocket::SslMode

qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)

加密dgram 并将加密数据写入socket 。返回已写入的字节数,如果出错则返回-1。socket 必须是有效指针。

另请参阅 doHandshake()、handshakeState()、isConnectionEncrypted() 和dtlsError()。

相关非成员

enum class QDtlsError

描述了QDtlsQDtlsClientVerifier 可能发现的错误。

该枚举描述了QDtlsClientVerifierQDtls 类对象可能遇到的一般错误和特定于 TLS 的错误。

常量说明
QDtls::QDtlsError::NoError0没有错误发生,最后一次操作成功。
QDtls::QDtlsError::InvalidInputParameters1调用者提供的输入参数无效。
QDtls::QDtlsError::InvalidOperation2在不允许操作的状态下尝试操作。
QDtls::QDtlsError::UnderlyingSocketError3QUdpSocket::writeDatagram() 失败,QUdpSocket::error() 和QUdpSocket::errorString() 可以提供更具体的信息。
QDtls::QDtlsError::RemoteClosedConnectionError4收到 TLS 关闭警报消息。
QDtls::QDtlsError::PeerVerificationError5在 TLS 握手过程中无法验证对等方身份。
QDtls::QDtlsError::TlsInitializationError6初始化底层 TLS 后端时发生错误。
QDtls::QDtlsError::TlsFatalError7TLS 握手过程中发生致命错误,对等验证错误或 TLS 初始化错误除外。
QDtls::QDtlsError::TlsNonFatalError8数据报加密或解密失败,非致命错误,这意味着QDtls 在出错后仍可继续工作。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.