OpenSSLサーバーとSChannelクライアントを使用したTLSセッションの再開

sayuri

RFC5077TLSセッション再開を使用する必要があります。クライアントはWindowsSChannelを使用し、サーバーは通常OpenSSLを使用します。私のテストでは、次の結果。

  • OpenSSL 1.1.0(またはそれ以降)およびSChannel:常にセッションが再利用され、SChannelは以前のセッションチケットを送信します。
  • OpenSSL 1.0.2(任意のリビジョン)およびSchannel:常に新しいセッション。SChannelはセッションチケットを送信しません。
  • OpenSSLおよびOpenSSL:常にセッションが再利用されます。

だから私はそれを知りたい

  • SchannelがOpenSSL1.0.2に対してのみTLSセッション再開を使用しないのはなぜですか?
  • 1.0.2と1.1.0の違い。
  • OpenSSL 1.0.2およびSChannelでTLSセッション再開を使用するにはどうすればよいですか?

サーバーコード:シンプルなTLSサーバー

クライアントコード:Windows C ++

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define SECURITY_WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#include <sspi.h>
#include <schannel.h>
#include <stdio.h>
#include <vector>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Secur32.lib")

struct WSA {
    WSA() {
        WSADATA wsaData;
        if (auto result = WSAStartup(WINSOCK_VERSION, &wsaData))
            throw result;
    }
    ~WSA() {
        WSACleanup();
    }
};

struct Credential : CredHandle {
    Credential() {
        SCHANNEL_CRED cred = { .dwVersion = SCHANNEL_CRED_VERSION, .dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION };
        if (auto ss = AcquireCredentialsHandleW(nullptr, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, nullptr, &cred, nullptr, nullptr, this, nullptr); ss != SEC_E_OK)
            throw ss;
    }
    ~Credential() {
        FreeCredentialsHandle(this);
    }
};

struct Socket {
    SOCKET s;
    Socket(const char* target, int port) {
        SOCKADDR_IN addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(target);
        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s == INVALID_SOCKET)
            throw WSAGetLastError();
        if (connect(s, reinterpret_cast<const SOCKADDR*>(&addr), sizeof addr))
            throw WSAGetLastError();
        u_long val = 1;
        ioctlsocket(s, FIONBIO, &val);
    }
    ~Socket() {
        closesocket(s);
    }
    auto Read() {
        for (std::vector<unsigned char> result;;) {
            char buffer[2048];
            if (auto read = recv(s, buffer, sizeof buffer, 0); read == 0)
                return result;
            else if (read == SOCKET_ERROR) {
                if (auto lastError = WSAGetLastError(); lastError != WSAEWOULDBLOCK)
                    throw lastError;
                if (!empty(result))
                    return result;
                Sleep(0);
            } else
                result.insert(end(result), buffer, buffer + read);
        }
    }
    void Write(void* data, int length) {
        for (auto p = reinterpret_cast<const char*>(data); 0 < length;) {
            auto sent = send(s, p, length, 0);
            if (sent == 0)
                throw 0;
            else if (sent == SOCKET_ERROR)
                throw WSAGetLastError();
            p += sent;
            length -= sent;
        }
    }
};

int main() {
    WSA wsa;
    Credential credential;

    for (int i = 0; i < 5; i++) {
        Socket socket{ "127.0.0.1", 4433 };
        std::vector<unsigned char> read;
        auto first = true;
        CtxtHandle context;
        for (SECURITY_STATUS ss = SEC_I_CONTINUE_NEEDED; ss == SEC_I_CONTINUE_NEEDED;) {
            SecBuffer inbuf[] = {
                { .BufferType = SECBUFFER_EMPTY },
                { .BufferType = SECBUFFER_EMPTY },
            };
            if (!first) {
                auto data = socket.Read();
                read.insert(end(read), begin(data), end(data));
                inbuf[0] = { static_cast<unsigned long>(read.size()), SECBUFFER_TOKEN, read.data() };
            }
            SecBufferDesc indesc = { SECBUFFER_VERSION, 2, inbuf };
            SecBuffer outbuf = { .BufferType = SECBUFFER_TOKEN };
            SecBufferDesc outdesc = { SECBUFFER_VERSION, 1, &outbuf };
            unsigned long attr = 0;
            ss = InitializeSecurityContextW(&credential, first ? nullptr : &context, L"localhost", ISC_REQ_ALLOCATE_MEMORY, 0, SECURITY_NETWORK_DREP, &indesc, 0, &context, &outdesc, &attr, nullptr);
            if (FAILED(ss))
                throw ss;
            first = false;
            read.erase(begin(read), end(read) - (inbuf[1].BufferType == SECBUFFER_EXTRA ? inbuf[1].cbBuffer : 0));
            if (outbuf.cbBuffer != 0) {
                socket.Write(outbuf.pvBuffer, outbuf.cbBuffer);
                FreeContextBuffer(outbuf.pvBuffer);
            }
        }
        for (;;) {
            SecBuffer buffer[] = {
                { static_cast<unsigned long>(read.size()), SECBUFFER_DATA, read.data() },
                { .BufferType = SECBUFFER_EMPTY },
                { .BufferType = SECBUFFER_EMPTY },
                { .BufferType = SECBUFFER_EMPTY },
            };
            SecBufferDesc desc{ SECBUFFER_VERSION, 4, buffer };
            if (auto ss = DecryptMessage(&context, &desc, 0, nullptr); ss == SEC_I_CONTEXT_EXPIRED)
                break;
            else if (ss == SEC_E_OK) {
                if (buffer[1].BufferType == SECBUFFER_DATA && 0 < buffer[1].cbBuffer && buffer[1].pvBuffer)
                    printf("%.*s", buffer[1].cbBuffer, reinterpret_cast<const char*>(buffer[1].pvBuffer));
                read.erase(begin(read), end(read) - (buffer[3].BufferType == SECBUFFER_EXTRA ? buffer[3].cbBuffer : 0));
            } else if (ss != SEC_E_INCOMPLETE_MESSAGE)
                throw ss;
            if (auto data = socket.Read(); empty(data))
                break;
            else
                read.insert(end(read), begin(data), end(data));
        }
        if (auto ss = DeleteSecurityContext(&context); ss != SEC_E_OK)
            throw ss;
    }
}

私はftpクライアントのメンテナーです。一部のftpsサーバーでは、セキュリティのためにDATA接続でCONTROL接続のTLSセッションを再利用する必要があります。

sayuri

で、Windows Updateを10分の2019RFC7627拡張マスターシークレットが有効になっていました。RFC5077 TLSセッション再開時に、SChannelはRFC7627EMSサポートを必要とします。

OpenSSLは、1.1.0からRFC7627拡張マスターシークレットをサポートします。そのため、SChannelはOpenSSL1.0.2でTLSセッションを再利用できません。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

OpenSSLは、プロセスごとに複数のSSL_CTXを許可しますか?1つはサーバーセッションに使用され、もう1つはクライアントセッションにSSL_CTXを使用しますか?

分類Dev

Unixクライアントとサーバー間のtty / ptssshセッションを比較します

分類Dev

開発したモバイルアプリケーションの11バイトデータからBLEホイールとクランクセンサーのデータを特定したい

分類Dev

トランザクションを使用していないのに「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」というメッセージが表示される

分類Dev

トランザクションを使用していないのに「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」というメッセージが表示される

分類Dev

JoshuaDavies著の本「ImplementingSSL / TLS Using CryptographyandPKI」を使用したTLSサーバー/クライアントの実装

分類Dev

herokuアプリのWebサイトを開こうとしたときのアプリケーションエラーメッセージ

分類Dev

Docker Composeを使用したサーバーとクライアントの開発ワークフロー?

分類Dev

WebサービスとSOAPを使用したクライアント/サーバーアプリケーションでの遅延プロパティの使用

分類Dev

単一サーバーと複数のクライアントでソケットプログラミングを使用してチャットアプリケーションを開発しようとしています

分類Dev

SCHANNELが「SSLサーバーのハンドシェイクが正常に完了しました」と報告しても、「SSL / TLSのセキュリティで保護されたチャネルを作成できませんでした」。

分類Dev

カスタムCAを使用したクライアントサーバーTLS

分類Dev

Python クライアントを使用した Qt C++ SSL/TLS サーバー

分類Dev

Springサーバー/クライアントセッションと休止状態セッション

分類Dev

VNCサーバーを使用したリモートデスクトップとのユーザーインタラクションの制限

分類Dev

AWSサーバーと2つのRaspiクライアントを使用したWireguardサイト間セットアップ

分類Dev

VSTSエージェントインタラクティブモードのアクティブセッションを停止/再開します

分類Dev

サーバーはトランザクションの再開に失敗しました。説明:9800000002。(3971)(SQLEndTran) ')

分類Dev

TNS を使用したクライアントとサーバー マシン間の Oracle データベース 12c ネットワーク

分類Dev

NGINX 1.16サーバーでTLS1.3のセッション再開と初期データが機能しないのはなぜですか?

分類Dev

java:HTTPサーバーとクライアント間のHTTPセッション

分類Dev

.NETおよびXamarinを使用したサーバークライアントアプリケーション

分類Dev

VB.NETを使用したクライアント/サーバーアプリケーション

分類Dev

opensslを使用したクライアント/サーバーでのDES暗号化/復号化

分類Dev

iOS 8ユニバーサルアプリのアセットカタログとサイジングクラスを使用した画像サイズ?

分類Dev

Pythonを使用したセンサーデータとコマンド送信のためのクライアントサーバープロトコル

分類Dev

アウトラインのセクションとサブセクションを再帰的に印刷する

分類Dev

GoとMySQLを使用したフォールトトレランスを備えたサーバーのセットアップ(フェイルオーバー)

分類Dev

警告の取得:SQLエラー:1205、SQLState:41000エラー:ロック待機タイムアウトを超えました。トランザクションを再開してください。Hibernateを使用してレコードを保存する

Related 関連記事

  1. 1

    OpenSSLは、プロセスごとに複数のSSL_CTXを許可しますか?1つはサーバーセッションに使用され、もう1つはクライアントセッションにSSL_CTXを使用しますか?

  2. 2

    Unixクライアントとサーバー間のtty / ptssshセッションを比較します

  3. 3

    開発したモバイルアプリケーションの11バイトデータからBLEホイールとクランクセンサーのデータを特定したい

  4. 4

    トランザクションを使用していないのに「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」というメッセージが表示される

  5. 5

    トランザクションを使用していないのに「ロック待機タイムアウトを超えました。トランザクションを再開してみてください」というメッセージが表示される

  6. 6

    JoshuaDavies著の本「ImplementingSSL / TLS Using CryptographyandPKI」を使用したTLSサーバー/クライアントの実装

  7. 7

    herokuアプリのWebサイトを開こうとしたときのアプリケーションエラーメッセージ

  8. 8

    Docker Composeを使用したサーバーとクライアントの開発ワークフロー?

  9. 9

    WebサービスとSOAPを使用したクライアント/サーバーアプリケーションでの遅延プロパティの使用

  10. 10

    単一サーバーと複数のクライアントでソケットプログラミングを使用してチャットアプリケーションを開発しようとしています

  11. 11

    SCHANNELが「SSLサーバーのハンドシェイクが正常に完了しました」と報告しても、「SSL / TLSのセキュリティで保護されたチャネルを作成できませんでした」。

  12. 12

    カスタムCAを使用したクライアントサーバーTLS

  13. 13

    Python クライアントを使用した Qt C++ SSL/TLS サーバー

  14. 14

    Springサーバー/クライアントセッションと休止状態セッション

  15. 15

    VNCサーバーを使用したリモートデスクトップとのユーザーインタラクションの制限

  16. 16

    AWSサーバーと2つのRaspiクライアントを使用したWireguardサイト間セットアップ

  17. 17

    VSTSエージェントインタラクティブモードのアクティブセッションを停止/再開します

  18. 18

    サーバーはトランザクションの再開に失敗しました。説明:9800000002。(3971)(SQLEndTran) ')

  19. 19

    TNS を使用したクライアントとサーバー マシン間の Oracle データベース 12c ネットワーク

  20. 20

    NGINX 1.16サーバーでTLS1.3のセッション再開と初期データが機能しないのはなぜですか?

  21. 21

    java:HTTPサーバーとクライアント間のHTTPセッション

  22. 22

    .NETおよびXamarinを使用したサーバークライアントアプリケーション

  23. 23

    VB.NETを使用したクライアント/サーバーアプリケーション

  24. 24

    opensslを使用したクライアント/サーバーでのDES暗号化/復号化

  25. 25

    iOS 8ユニバーサルアプリのアセットカタログとサイジングクラスを使用した画像サイズ?

  26. 26

    Pythonを使用したセンサーデータとコマンド送信のためのクライアントサーバープロトコル

  27. 27

    アウトラインのセクションとサブセクションを再帰的に印刷する

  28. 28

    GoとMySQLを使用したフォールトトレランスを備えたサーバーのセットアップ(フェイルオーバー)

  29. 29

    警告の取得:SQLエラー:1205、SQLState:41000エラー:ロック待機タイムアウトを超えました。トランザクションを再開してください。Hibernateを使用してレコードを保存する

ホットタグ

アーカイブ