Класс QDtls
Этот класс обеспечивает шифрование для UDP-сокет. Подробнее...
| Заголовок: | #include <QDtls> |
| qmake: | QT += network |
| С тех пор: | Qt 5.12 |
| Наследует: | QObject |
Этот класс был представлен в Qt 5.12.
Типы public
| typedef | GeneratorParameters |
| перечисление | HandshakeState { HandshakeNotStarted, HandshakeInProgress, PeerVerificationFailed, HandshakeComplete } |
Функции public
| 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) |
Сигналы
| void | handshakeTimeout() |
| void | pskRequired(QSslPreSharedKeyAuthenticator *authenticator) |
Связанные внешние члены
| перечисление | QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, ..., TlsNonFatalError } |
Подробное описание
Класс QDtls может использоваться для создания защищенного соединения с сетевым узлом с помощью протокола UDP (User Datagram Protocol). Соединение 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.
Документация по типам членов
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 для соединения DTLS на стороне клиента.
См. также 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
Возвращает криптографическое шифрование, используемое этим соединением, или null-шифрование, если соединение не зашифровано. Шифрование для сеанса выбирается во время фазы рукопожатия. Шифрование используется для шифрования и дешифрования данных.
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 не должен быть null, multicast или broadcast. 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().
Связанные не члены
enum QDtls::QDtlsError
Описывает ошибки, которые могут быть обнаружены QDtls и QDtlsClientVerifier.
Этот перечисление описывает общие и специфичные для TLS ошибки, которые могут возникнуть у объектов классов QDtlsClientVerifier и QDtls.
| Константа | Значение | Описание |
|---|---|---|
QDtls::NoError |
0 |
Ошибка не возникла, последняя операция выполнена успешно. |
QDtls::InvalidInputParameters |
1 |
Предоставленные вызывающей стороной входные параметры были некорректны. |
QDtls::InvalidOperation |
2 |
Операция была выполнена в состоянии, которое её не допускало. |
QDtls::UnderlyingSocketError |
3 |
QUdpSocket::writeDatagram() завершился с ошибкой, QUdpSocket::error() и QUdpSocket::errorString() могут предоставить более подробную информацию. |
QDtls::RemoteClosedConnectionError |
4 |
Получено сообщение об окончании сессии TLS (shutdown alert). |
QDtls::PeerVerificationError |
5 |
Идентичность партнёра не могла быть проверена во время рукопожатия TLS. |
QDtls::TlsInitializationError |
6 |
Возникла ошибка при инициализации базового модуля TLS. |
QDtls::TlsFatalError |
7 |
Возникла фатальная ошибка во время рукопожатия TLS, помимо ошибки проверки идентичности партнёра или ошибки инициализации TLS. |
QDtls::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.13/qdtls.html