QDtls Class

このクラスはUDPソケットの暗号化を行う。詳細...

Header: #include <QDtls>
CMake: find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(mytarget PRIVATE Qt6::Network)
qmake: QT += network
Inherits: 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(User Datagram Protocol)を使用してネットワーク・ピアとのセキュアな接続を確立するために使用できます。本質的にコネクションレスなUDP上でのDTLS接続とは、まず2つのピアがdoHandshake() をコールしてTLSハンドシェイクを成功させなければならないことを意味する。ハンドシェイクが完了すると、writeDatagramEncrypted()を使って暗号化されたデータグラムをピアに送ることができる。ピアから送られてくる暗号化されたデータグラムは、decryptDatagram ()で復号化できる。

QDtlsは、QUdpSocket で動作するように設計されています。QUdpSocket は異なるピアからのデータグラムを受信できるため、アプリケーションはデマルチプレクスを実装し、異なるピアからのデータグラムを対応するQDtlsインスタンスに転送する必要がある。ネットワーク・ピアとそのQDtlsオブジェクトの関連付けは、ピアのアドレスとポート番号を使って確立できる。ハンドシェイクを開始する前に、アプリケーションはsetPeer ()を使用してピアのアドレスとポート番号を設定する必要があります。

QDtlsはQUdpSocket からデータグラムを読み込まないため、アプリケーションはQUdpSocket::readyRead ()シグナルに接続されたスロットなどでデータグラムを読み込む必要がある。その後、これらのデータグラムはQDtlsによって処理されなければならない。

注意: QDtlsはQUdpSocket オブジェクトの所有権を持ちません

通常、ハンドシェーク・フェーズの間に、両方のピアによって複数のデータグラムが送受信される。データグラムを読み込むと、サーバーとクライアントは、何らかのエラーが発 生するか、handshakeState() がHandshakeComplete を返すまで、これらのデータグラ ムをdoHandshake() に渡さなければならない:

// 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 で検証されたものであることが期待される。

ハンドシェイク中に相手のIDを検証できない場合、アプリケーションは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);
}

警告: 警告:後で同じポート番号を再利用してサーバーに接続する場合は、クライアントのQDtlsオブジェクトを破棄する前にshutdown ()を呼び出すことを推奨する。そうしないと、サーバーは受信した 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(Path Maximum Transmission Unit)の発見をアプリケーションに任せている。アプリケーションは、setMtuHint ()を使用してQDtlsにMTUを提供することができる。ハンドシェイク・メッセージだけがDTLSによってフラグメント化され、再アセンブルされるので、このヒントはハンドシェイク・フェーズだけに影響する。アプリケーションから送信される他のすべてのメッセージは、1つのデータグラムに収まらなければならない。

注意: DTLS 固有のヘッダーはアプリケーションデータにオーバーヘッドを追加し、可能なメッセージサイズをさらに小さくする。

警告: HelloVerifyRequestで応答するように設定されたサーバーは、フラグメント化された ClientHelloメッセージをすべてドロップし、決してハンドシェイクを開始しない。

DTLSサーバーと DTLSクライアントの例は、アプリケーションでQDtlsを使用する方法を示している。

QUdpSocketQDtlsClientVerifierHandshakeStateQDtlsErrorQSslConfigurationも参照のこと

メンバー・タイプ・ドキュメント

[alias] QDtls::GeneratorParameters

enum QDtls::HandshakeState

DTLSハンドシェイクの現在の状態を記述する。

この enum はQDtls 接続の DTLS ハンドシェイクの現在の状態を記述する。

定数説明
QDtls::HandshakeNotStarted0まだ何も行われていない。
QDtls::HandshakeInProgress1ハンドシェイクが開始され、今のところエラーは見つかっていない。
QDtls::PeerVerificationFailed2相手の身元が確認できない。
QDtls::HandshakeComplete3ハンドシェイクが正常に完了し、暗号化された接続が確立された。

QDtls::doHandshake() およびQDtls::handshakeState()も参照

メンバー関数ドキュメント

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

QDtls オブジェクトを作成します。parentQObject コンストラクタに渡されます。mode は、サーバー側 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 がそれをサポートするように設定されている場合は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 returnは何らかのエラーが発生したことを意味する。より詳細な情報はdtlsError()を使用する。

注: ピアの ID を確立できない場合、エラーは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)

このメソッドは、errorsToIgnore で指定されたエラーのみを無視するようにQDtls に指示する。

例えば、自己署名証明書を使用するサーバに接続したい場合、以下のスニペットを考 慮してほしい:

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

相手の ID を確立する際に見つかったエラーを返します。

エラーが発生したにもかかわらず接続を続行する場合は、ignoreVerificationErrors() を呼び出す必要があります。

QString QDtls::peerVerificationName() const

setPeer() またはsetPeerVerificationName() で設定されたホスト名を返します。デフォルト値は空文字列である。

setPeerVerificationName() およびsetPeer()も参照

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

QDtls は、PSK 暗号スイートをネゴシエートする際にこのシグナルを発行する。

PSKを使用する場合、TLSハンドシェイクを継続するために、クライアントは有効なIDと有効な事前共有鍵をサーバーに送信しなければならない。アプリケーションは、このシグナルに接続されたスロットに、渡されたauthenticator オブジェクトを必要に応じて入力することで、この情報を提供することができる。

注: このシグナルを無視したり、必要な認証情報を提供しなかったりすると、ハンドシェイクが失敗し、接続が中断される。

注意 authenticator オブジェクトはQDtls が所有しており、アプリケーションによって削除されてはならない。

QSslPreSharedKeyAuthenticatorも参照のこと

bool QDtls::resumeHandshake(QUdpSocket *socket)

ハンドシェーク中にピア検証エラーが無視された場合、resumeHandshake() はハンドシェークを再開して完了し、true を返す。socket は有効なポインタでなければならない。ハンドシェークを再開できなかった場合はfalse を返す。

doHandshake()、abortHandshake()、peerVerificationErrors()、ignoreVerificationErrors()も参照のこと

QSslCipher QDtls::sessionCipher() const

この接続で使用されている暗号cipher を返すか、接続が暗号化されていない場合は NULL 暗号を返す。セッションの暗号はハンドシェーク時に選択される。暗号はデータの暗号化と復号に使用されます。

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()、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、マルチキャスト、またはブロードキャストであってはならない。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 class QDtlsError

QDtls およびQDtlsClientVerifier で見つかるエラーについて記述する。

この列挙型は、QDtlsClientVerifier およびQDtls クラスのオブジェクトが遭遇する可能性のある、一般的なエラーと TLS 固有のエラーについて記述します。

定数説明
QDtls::QDtlsError::NoError0エラーは発生せず、最後の操作は成功した。
QDtls::QDtlsError::InvalidInputParameters1呼び出し元が提供した入力パラメータが無効でした。
QDtls::QDtlsError::InvalidOperation2操作が許可されていない状態で操作を試みた。
QDtls::QDtlsError::UnderlyingSocketError3QUdpSocket::writeDatagram()は失敗した。QUdpSocket::error()およびQUdpSocket::errorString()は、より詳細な情報を提供できる。
QDtls::QDtlsError::RemoteClosedConnectionError4TLSシャットダウン警告メッセージを受信した。
QDtls::QDtlsError::PeerVerificationError5TLSハンドシェイク中にピアの身元を確認できなかった。
QDtls::QDtlsError::TlsInitializationError6基盤となるTLSバックエンドの初期化中にエラーが発生した。
QDtls::QDtlsError::TlsFatalError7TLSハンドシェイク中に致命的なエラーが発生した(ピア検証エラーまたはTLS初期化エラー以外)。
QDtls::QDtlsError::TlsNonFatalError8データグラムの暗号化または復号化に失敗した。致命的なエラーではないので、このエラーの後でもQDtls は動作し続けることができる。

本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。