Класс QDtls
Этот класс предоставляет шифрование для UDP-сокет. Подробнее...
| Заголовок: | #include <QDtls> |
| qmake: | QT += network |
| С момента: | Qt 5.12 |
| Наследуется от: | QObject |
Этот класс был представлен в Qt 5.12.
Открытые типы
| (псевдоним) | GeneratorParameters |
| перечисление | HandshakeState { HandshakeNotStarted, HandshakeInProgress, PeerVerificationFailed, HandshakeComplete } |
Открытые функции
| QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr) | |
| виртуальный | ~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 QVector<QSslError> &errorsToIgnore) |
| bool | isConnectionEncrypted() const |
| quint16 | mtuHint() const |
| QHostAddress | peerAddress() const |
| quint16 | peerPort() const |
| QVector<QSslError> | peerVerificationErrors() const |
| QString | peerVerificationName() const |
| bool | resumeHandshake(QUdpSocket *socket) |
| QSslCipher | sessionCipher() const |
| QSsl::SslProtocol | sessionProtocol() const |
| bool | setCookieGeneratorParameters(const QDtls::GeneratorParameters ¶ms) |
| 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) |
Связанные нечлены
| перечисление классов | QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, RemoteClosedConnectionError, …, TlsNonFatalError } |
Подробное описание
Класс QDtls можно использовать для установления защищенного соединения с сетевым узлом с использованием протокола пользовательских датаграмм (UDP). Соединение DTLS по сути бессокетному UDP означает, что два узла сначала должны успешно завершить TLS-рукопожатие, вызвав doHandshake(). После завершения рукопожатия зашифрованные датаграммы могут быть отправлены узлу с помощью 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);
Соединение DTLS может быть закрыто с помощью shutdown().
DtlsClient::~DtlsClient()
{
clientDtls.shutdown(&clientSocket);
} Предупреждение: Рекомендуется вызвать shutdown() перед уничтожением объекта QDtls клиента, если вы планируете повторно использовать тот же номер порта для подключения к серверу позже. В противном случае сервер может отбрасывать входящие сообщения ClientHello, см. RFC 6347, раздел 4.2.8 для получения дополнительных подробностей и советов по реализации.
Если сервер не использует QDtlsClientVerifier, он должен настроить свои объекты QDtls, чтобы отключить процедуру проверки куки:
auto config = QSslConfiguration::defaultDtlsConfiguration(); config.setDtlsCookieVerificationEnabled(false); // Some other customization ... dtlsConnection.setDtlsConfiguration(config);
Сервер, использующий проверку cookie с параметрами генератора, отличными от стандартных, должен установить те же параметры для своего объекта QDtls перед началом рукопожатия.
Примечание: Протокол DTLS делегирует обнаружение максимального размера транспортного блока пути (PMTU) приложению. Приложение может предоставить QDtls MTU с помощью setMtuHint(). Этот подсказка влияет только на фазу рукопожатия, так как только сообщения рукопожатия могут быть фрагментированы и повторно собраны DTLS. Все остальные сообщения, отправляемые приложением, должны помещаться в один датаграмму.
Примечание: DTLS-специфичные заголовки добавляют некоторую избыточность к данным приложения, ещё более уменьшая возможный размер сообщения.
Предупреждение: Сервер, настроенный на ответ с HelloVerifyRequest, отбросит все фрагментированные сообщения ClientHello, никогда не начав рукопожатие.
Примеры сервера DTLS и клиента DTLS иллюстрируют, как использовать QDtls в приложениях.
См. также QUdpSocket, QDtlsClientVerifier, HandshakeState, QDtlsError и QSslConfiguration.
Документация типов членов
[alias] QDtls::GeneratorParameters
Это псевдоним типа для QDtlsClientVerifier::GeneratorParameters.
enum QDtls::HandshakeState
Описание текущего состояния рукопожатия DTLS.
Этот перечисление описывает текущее состояние рукопожатия DTLS для подключения QDtls.
| Константа | Значение | Описание |
|---|---|---|
QDtls::HandshakeNotStarted |
0 |
Пока ничего не сделано. |
QDtls::HandshakeInProgress |
1 |
Рукопожатие было инициировано, и пока не было обнаружено ошибок. |
QDtls::PeerVerificationFailed |
2 |
Тождество собеседника не может быть установлено. |
QDtls::HandshakeComplete |
3 |
Рукопожатие успешно завершено, и зашифрованное соединение установлено. |
Это перечисление было введено или изменено в Qt 5.12.
См. также QDtls::doHandshake() и QDtls::handshakeState().
Документация функций-членов
QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr)
Создаёт объект QDtls, parent передаётся конструктору QObject. mode это QSslSocket::SslServerMode для соединения DTLS на стороне сервера или QSslSocket::SslClientMode для соединения клиента.
См. также sslMode() и QSslSocket::SslMode.
[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().
[signal] void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator)
QDtls излучает этот сигнал, когда он согласовывает PSK-шифрование, и поэтому требуется аутентификация PSK.
При использовании PSK клиент должен отправить серверу действительную личность и действительный предварительно согласованный ключ, чтобы рукопожатие TLS продолжилось. Приложения могут предоставить эту информацию в слоте, подключенном к этому сигналу, заполнив переданный объект authenticator в соответствии со своими потребностями.
Примечание: Игнорирование этого сигнала или невозможность предоставить необходимые учетные данные приведут к неудаче рукопожатия, а следовательно, к прерыванию соединения.
Примечание: Объект authenticator принадлежит QDtls и не должен удаляться приложением.
См. также QSslPreSharedKeyAuthenticator.
[virtual] QDtls::~QDtls()
Уничтожает объект QDtls.
bool QDtls::abortHandshake(QUdpSocket *socket)
Прерывает текущее рукопожатие. Возвращает true, если оно происходило на socket; в противном случае устанавливает соответствующую ошибку и возвращает false.
См. также doHandshake() и resumeHandshake().
QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
Возвращает текущий алгоритм хеширования и секрет, либо стандартные, либо установленные ранее вызовом setCookieGeneratorParameters().
Стандартный алгоритм хеширования — QCryptographicHash::Sha256, если Qt был сконфигурирован для его поддержки, в противном случае 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 должен содержать начальное сообщение ClientHello, прочитанное из QUdpSocket. Эта функция возвращает 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.
void QDtls::ignoreVerificationErrors(const QVector<QSslError> &errorsToIgnore)
Этот метод сообщает QDtls игнорировать только ошибки, указанные в errorsToIgnore.
Например, если вы хотите подключиться к серверу, использующему самозаверенный сертификат, рассмотрите следующий фрагмент:
QList<QSslCertificate> cert = QSslCertificate::fromPath(QLatin1String("server-certificate.pem"));
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
Возвращает true, если фаза установления соединения DTLS успешно завершена.
См. также doHandshake() и handshakeState().
quint16 QDtls::mtuHint() const
Возвращает значение, ранее заданное функцией setMtuHint(). Значение по умолчанию — 0.
См. также setMtuHint().
QHostAddress QDtls::peerAddress() const
Возвращает адрес удалённого узла, установленный функцией setPeer(), или QHostAddress::Null.
См. также setPeer().
quint16 QDtls::peerPort() const
Возвращает номер порта удалённого узла, установленный функцией setPeer(), или 0.
См. также setPeer().
QVector<QSslError> QDtls::peerVerificationErrors() const
Возвращает ошибки, обнаруженные при проверке подлинности удалённого узла.
Если вы хотите продолжить подключение, несмотря на возникшие ошибки, вам необходимо вызвать ignoreVerificationErrors().
QString QDtls::peerVerificationName() const
Возвращает имя хоста, заданное функциями setPeer() или setPeerVerificationName(). Значение по умолчанию — пустая строка.
См. также setPeerVerificationName() и setPeer().
bool QDtls::resumeHandshake(QUdpSocket *socket)
Если ошибки проверки подлинности удалённого узла были проигнорированы во время установления соединения, resumeHandshake() возобновляет и завершает установку соединения и возвращает true. socket должен быть допустимым указателем. Возвращает false, если установление соединения не удалось возобновить.
См. также doHandshake(), abortHandshake(), peerVerificationErrors() и ignoreVerificationErrors().
QSslCipher QDtls::sessionCipher() const
Возвращает криптографический шифр, используемый этим соединением, или нулевой шифр, если соединение не зашифровано. Шифр сессии выбирается во время фазы установления соединения. Шифр используется для шифрования и дешифрования данных.
QSslConfiguration предоставляет функции для задания упорядоченного списка шифров, из которого фаза установления соединения в конечном итоге выберет шифр сессии. Этот упорядоченный список должен быть создан до начала фазы установления соединения.
См. также QSslConfiguration, setDtlsConfiguration() и dtlsConfiguration().
QSsl::SslProtocol QDtls::sessionProtocol() const
Возвращает версию протокола DTLS, используемую этим соединением, или UnknownProtocol, если соединение ещё не зашифровано. Протокол соединения выбирается во время фазы установления соединения.
setDtlsConfiguration() может задать предпочтительную версию до начала установления соединения.
См. также setDtlsConfiguration(), QSslConfiguration, QSslConfiguration::defaultDtlsConfiguration() и QSslConfiguration::setProtocol().
bool QDtls::setCookieGeneratorParameters(const QDtls::GeneratorParameters ¶ms)
Устанавливает алгоритм криптографического хэширования и секрет из params. Эта функция требуется только для серверного соединения QDtls. Возвращает true, если успешно.
Примечание: Эта функция должна быть вызвана до начала установления соединения.
См. также cookieGeneratorParameters(), doHandshake(), QDtlsClientVerifier и QDtlsClientVerifier::cookieGeneratorParameters().
bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
Устанавливает конфигурацию TLS соединения из configuration и возвращает 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::HandshakeNotStarted. socket должен быть допустимым указателем. Функция возвращает 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().
Связанные нечлены
перечисление QDtlsError
Описывает ошибки, которые могут быть обнаружены QDtls и QDtlsClientVerifier.
Это перечисление описывает общие и специфичные для TLS ошибки, которые могут возникнуть у объектов классов QDtlsClientVerifier и QDtls.
| Константа | Значение | Описание |
|---|---|---|
QDtls::QDtlsError::NoError |
0 |
Ошибка не произошла, последняя операция выполнена успешно. |
QDtls::QDtlsError::InvalidInputParameters |
1 |
Предоставленные вызывающей стороной входные параметры неверны. |
QDtls::QDtlsError::InvalidOperation |
2 |
Операция была предпринята в состоянии, которое её не допускало. |
QDtls::QDtlsError::UnderlyingSocketError |
3 |
QUdpSocket::writeDatagram() завершилась с ошибкой, QUdpSocket::error() и QUdpSocket::errorString() могут предоставить более подробную информацию. |
QDtls::QDtlsError::RemoteClosedConnectionError |
4 |
Получено сообщение об отключении TLS. |
QDtls::QDtlsError::PeerVerificationError |
5 |
Идентификатор удаленного узла не удалось проверить во время рукопожатия TLS. |
QDtls::QDtlsError::TlsInitializationError |
6 |
Ошибка произошла при инициализации базового TLS-бекенда. |
QDtls::QDtlsError::TlsFatalError |
7 |
Произошла критическая ошибка во время рукопожатия TLS, помимо ошибок проверки подлинности удалённого узла или инициализации TLS. |
QDtls::QDtlsError::TlsNonFatalError |
8 |
Ошибка при шифровании или дешифровании дейтаграммы, некритическая, что означает, QDtls может продолжить работу после этой ошибки. |
Это перечисление было введено или изменено в Qt 5.12.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.15/qdtls.html