Класс QDtls
Этот класс обеспечивает шифрование для сокетов UDP. Подробнее...
| Заголовок: | #include <QDtls> |
| qmake: | QT += network |
| С момента: | Qt 5.12 |
| Наследует: | QObject |
Общие типы
| typedef | GeneratorParameters |
| Перечисление | 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 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) |
- 31 открытая функция, унаследованная от QObject
Сигналы
| void | handshakeTimeout() |
| void | pskRequired(QSslPreSharedKeyAuthenticator *authenticator) |
- 2 сигнала, унаследованных от QObject
Статические открытые члены
| const QMetaObject | staticMetaObject |
- 9 статических открытых членов, унаследованных от QObject
Связанные нечлены
| Перечисление | QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, ..., TlsNonFatalError } |
Дополнительные унаследованные члены
- 1 свойство, унаследованное от QObject
- 1 открытый слот, унаследованный от QObject
- 9 защищенных функций, унаследованных от QObject
Подробное описание
Этот класс обеспечивает шифрование для сокетов UDP.
Класс 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);
Сервер, использующий проверку куки с параметрами генератора, отличными от стандартных, обязан установить те же параметры для своего объекта QDtls перед началом рукопожатия.
Примечание: Протокол DTLS оставляет обнаружение максимального размера транспортного блока (PMTU) приложению. Приложение может предоставить QDtls MTU с помощью setMtuHint(). Этот параметр влияет только на фазу рукопожатия, поскольку только сообщения рукопожатия могут быть фрагментированы и повторно собраны DTLS. Все остальные сообщения, отправленные приложением, должны помещаться в один датаграмму.
Примечание: DTLS-специфичные заголовки добавляют некоторую избыточность к данным приложения, что еще больше уменьшает возможный размер сообщения.
Предупреждение: Сервер, настроенный для ответа с HelloVerifyRequest, отклонит все фрагментированные сообщения ClientHello, никогда не начав рукопожатие.
Примеры сервера DTLS DTLS server и клиента DTLS DTLS client демонстрируют, как использовать QDtls в приложениях.
См. также QUdpSocket, QDtlsClientVerifier, HandshakeState, QDtlsError и QSslConfiguration.
Документация по типам членов
typedef 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.
[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.
[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 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().
[signal] void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator)
QDtls излучает этот сигнал, когда он согласовывает набор шифров PSK, и поэтому требуется аутентификация PSK.
При использовании PSK клиент должен отправить серверу действительный идентификатор и действительный предварительно согласованный ключ, чтобы продолжить установку соединения TLS. Приложения могут предоставить эту информацию в слоте, подключенном к этому сигналу, заполнив переданный объект authenticator в соответствии со своими потребностями.
Примечание: Игнорирование этого сигнала или невозможность предоставить необходимые учетные данные приведет к сбою рукопожатия, а следовательно, к прерыванию соединения.
Примечание: Объект authenticator принадлежит QDtls и не должен удаляться приложением.
См. также QSslPreSharedKeyAuthenticator.
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 = {})
Устанавливает адрес, порт и имя хоста узла и возвращает 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.
| Константа | Значение | Описание |
|---|---|---|
NoError |
0 |
Ошибка не произошла, последняя операция выполнена успешно. |
InvalidInputParameters |
1 |
Предоставленные вызывающей стороной входные параметры некорректны. |
InvalidOperation |
2 |
Операция была выполнена в состоянии, которое её не допускало. |
UnderlyingSocketError |
3 |
QUdpSocket::writeDatagram() завершилась ошибкой, QUdpSocket::error() и QUdpSocket::errorString() могут предоставить более подробную информацию. |
RemoteClosedConnectionError |
4 |
Получено сообщение об окончании TLS. |
PeerVerificationError |
5 |
Идентификатор клиента не смог быть проверен во время рукопожатия TLS. |
TlsInitializationError |
6 |
Возникла ошибка при инициализации базового TLS-бекенда. |
TlsFatalError |
7 |
Произошла критическая ошибка во время TLS-рукопожатия, кроме ошибок проверки клиента или инициализации TLS. |
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.12/qdtls.html