“openssl s_client”コマンドでHTTPSの仕組みを理解する(TLS 1.3)

はじめに

HTTPSがどのようなプロトコルなのかは”curl —trace”でも部分的には確認できるが、より詳細にはopenssl s_clientというコマンドを使うのがよい。そこで今回はこのコマンドを用いてHTTPSの仕組みを追っていくことにする。HTTPSがセキュアであるのはSSL/TLSプロトコルに依っているが、今回はTLS1.3でどうなっているかを見る。(TLS1.2は現状まだ広く使われている。TLS1.1, TLS1.0は非推奨) TLS1.3はQUICで前提となっているプロトコルなので、今キャッチアップするならTLS1.3まで追うのがおすすめ。

--

  • TLS 1.2と1.3は結構違う
    • 鍵交換のあとにサーバー認証を行う。TLS1.2ではサーバー認証とセットで鍵交換を行う。
    • 他にも相違点は多い(フロー自体結構変わってるし)
    • ブログ記事やyoutube動画などでTLSのバージョンが明記されていないものは注意すべし。
  • HTTPS公開鍵暗号を用いて平文(やShakeHands時のメッセージ)を暗号化している」は間違い
    • 正しくは共通鍵暗号(もっと正確にはAEAD: 認証付き暗号)
    • TLS1.3ではServerHelloの後には暗号化できる状態になっている(ので、TLSのメッセージを暗号化して送る)
  • 公開鍵暗号はTLS1.3の全てを通して暗号化のために用いられていない
    • 署名の用途で用いられている。(秘密鍵sign(署名)して、公開鍵でverify(検証)する)
    • なので、「公開鍵暗号のペアを作り、秘密鍵で〇〇を暗号化する」的な説明は誤り。
  • TLS1.2でもどちらにせよ公開鍵暗号は暗号化のために用いられていない
    • 署名の用途で用いられている。(秘密鍵sign(署名)して、公開鍵でverify(検証)する)
  • 言葉の使い方が難しいですね

参考url

コマンドについて

docker run -it --rm ubuntu:22.04
apt-get update
apt-get install -y openssl
# openssl version -a
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
built on: Mon Jul  4 11:20:23 2022 UTC
platform: debian-amd64
options:  bn(64,64)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -ffile-prefix-map=/build/openssl-Q8dQt3/openssl-3.0.2=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_TLS_SECURITY_LEVEL=2 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-3"
MODULESDIR: "/usr/lib/x86_64-linux-gnu/ossl-modules"
Seeding source: os-specific
CPUINFO: OPENSSL_ia32cap=0xfeda7217cf8bffff:0x329

openssl s_clientというコマンドでSSL/TLS 通信、診断を行える(WireSharkでもできるが)。openssl s_client --helpとすると非常にたくさんのオプションがあるが、今回は下のコマンド(-trace)で確かめる。ログの後read R BLOCKで止まると思うので、HTTPリクエストをペーストすればexample.comのhtmlが出力される。

# -tls1_3でTLS1.3に制限できる(ただしサーバーが対応していることが前提)
openssl s_client -connect example.com:443 -trace -tls1_3
...
..
read R BLOCK
# ここで止まるので、gistのページのHTTPリクエスト4行をペーストすると、html含むレスポンスデータが返ってくる

全ログ含め、詳しくは https://gist.github.com/knknkn1162/391d3dcece41e0a710585164e880dbd6 を参照のこと。

今回はhttps://example.comHTTPSのやりとりをtraceしてる

プロトコルの流れ

注意) TLS1.2と結構違う。特に大きく違うのが、ServerHello完了時にDH鍵交換が終了していること。これによってAEAD(認証付き暗号、暗号技術は共通鍵暗号)を用いて3以降は暗号化され、サーバー認証が行われる。対してTLS1.2では鍵交換がサーバー認証時とセットになって行われる。

  1. (TCPによる3 way handshake)

  2. [Client → Server] ClientHello

  3. [Server → Client]ServerHello
    1. もしネゴシエーションできなかった場合はHelloRetryRequest → 1に戻る
  4. [Server → Client] EncryptedExtensions
  5. [Server → Client] CertificateRequest
    1. 今回のケースではサーバー認証のみとするので、ここはなし
  6. [Server → Client] Certify
  7. [Server → Client] CertificateVerify
  8. [Server → Client] Finished
  9. [Client → Server] Finished
  10. ([Client → Server] HTTPリクエストを送る)

Handshakeプロトコル

ClientHello(クライアント → サーバー)

  • Serverとセキュリティパラメータを合意する(ServerHelloでセキュリティパラメータが一致していれば合意できたことになる)
Sent Record
Header:
  # legacy_record_versionなのでTLS 1.3では実際には使われていない
  # ただし互換性を考慮して、一番最初に送信される ClientHello だけでは 0x0301(TLS 1.0 を表す値)を利用される場合がある。
  Version = TLS 1.0 (0x301)
  Content Type = Handshake (22)
  Length = 240
    ClientHello, Length=236
      # ここは固定
      client_version=0x303 (TLS 1.2)
      # 毎回のハンドシェイクを一位にするための32bitランダム値(リプレイ攻撃の防止)
      Random:
        gmt_unix_time=0x35DD6BF8
        random_bytes (len=28): F03CB39FC11DFF87492CC9E7DF398790A866BF4BEABD621267E8041E
      session_id (len=32): 31681F7735E44982BCADCA2B7BE8884BA073BBF79CF0456B1A859BFFBFA27FE9
      # クライアントがネゴシエーションを試みる暗号スイート
      cipher_suites (len=8)
        {0x13, 0x02} TLS_AES_256_GCM_SHA384
        {0x13, 0x03} TLS_CHACHA20_POLY1305_SHA256
        {0x13, 0x01} TLS_AES_128_GCM_SHA256
        {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      # 常に圧縮なし
      compression_methods (len=1)
        No Compression (0x00)
      # 多くのフィールド指定を拡張で扱うようになった
      extensions, length = 155
        extension_type=server_name(0), length=16
          0000 - 00 0e 00 00 0b 65 78 61-6d 70 6c 65 2e 63 6f   .....example.co
          000f - 6d                                             m
        extension_type=ec_point_formats(11), length=4
          uncompressed (0)
          ansiX962_compressed_prime (1)
          ansiX962_compressed_char2 (2)
        # 対応している鍵交換のグループ
        extension_type=supported_groups(10), length=22
          ecdh_x25519 (29)
          secp256r1 (P-256) (23)
          ecdh_x448 (30)
          secp521r1 (P-521) (25)
          secp384r1 (P-384) (24)
          ffdhe2048 (256)
          ffdhe3072 (257)
          ffdhe4096 (258)
          ffdhe6144 (259)
          ffdhe8192 (260)
        # クライアントはセッションチケットによる再開に対応
        extension_type=session_ticket(35), length=0
        extension_type=encrypt_then_mac(22), length=0
        extension_type=extended_master_secret(23), length=0
        # ハンドシェイク中にサーバが利用できるアルゴリズム
        extension_type=signature_algorithms(13), length=30
          ecdsa_secp256r1_sha256 (0x0403)
          ecdsa_secp384r1_sha384 (0x0503)
          ecdsa_secp521r1_sha512 (0x0603)
          ed25519 (0x0807)
          ed448 (0x0808)
          rsa_pss_pss_sha256 (0x0809)
          rsa_pss_pss_sha384 (0x080a)
          rsa_pss_pss_sha512 (0x080b)
          rsa_pss_rsae_sha256 (0x0804)
          rsa_pss_rsae_sha384 (0x0805)
          rsa_pss_rsae_sha512 (0x0806)
          rsa_pkcs1_sha256 (0x0401)
          rsa_pkcs1_sha384 (0x0501)
          rsa_pkcs1_sha512 (0x0601)
        # 本当のTLSのバージョン番号
        extension_type=supported_versions(43), length=3
          TLS 1.3 (772)
        # 認証に利用する(署名に利用する)証明書もしくは事前共有鍵(pre-shared keys)。サーバー認証を簡略化するために使われる。
        extension_type=psk_key_exchange_modes(45), length=2
          # PFS(完全前方秘匿性)が有効になるオプション(DHEだけでなくECDHEによる鍵交換にも対応
          # PSK: preshared key
          psk_dhe_ke (1)
        # 鍵交換アルゴリズムに必要な情報
        extension_type=key_share(51), length=38
            NamedGroup: ecdh_x25519 (29)
            key_exchange:  (len=32): 02DAD738070BD5F9337F280C223D3ABADF8D3420149B0847721503D0945A7348

HelloRetryRequest(サーバー → クライアント)

  • ServerHelloと書いてあるが、
    • 0xCF21AD74E59A6111BE1D8C021E65B891C2A211167ABB8C5E079E09E2C8A8339C というメッセージを受け取った場合はクライアントはHelloRetryRequest メッセージとして扱う
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 88
    # HelloRetryRequestとあるが下の理由からHelloRetryRequestになる
    ServerHello, Length=84
      server_version=0x303 (TLS 1.2)
      Random:
        # この特別な値の場合はHelloRetryRequestになる。
        gmt_unix_time=0xCF21AD74
        random_bytes (len=28): E59A6111BE1D8C021E65B891C2A211167ABB8C5E079E09E2C8A8339C
      # クライアントからの値をそのまま返しているだけ
      session_id (len=32): 31681F7735E44982BCADCA2B7BE8884BA073BBF79CF0456B1A859BFFBFA27FE9
      cipher_suite {0x13, 0x02} TLS_AES_256_GCM_SHA384
      compression_method: No Compression (0x00)
      # ServerHelloには最低限必要なサーバ拡張のみを含める
      extensions, length = 12
        # 本当のTLSのバージョン番号
        extension_type=supported_versions(43), length=2
            TLS 1.3 (772)
        # 鍵交換アルゴリズムに必要な情報
        # 鍵交換アルゴリズムがecdh_x25519(Curve25519を利用して実現されるDHE)と違うので、1回目のネゴシエーションは失敗。サーバー側はECDHE(P256)[ECDSA]を要求してる
        extension_type=key_share(51), length=2
            NamedGroup: secp256r1 (P-256) (23)

ChangeCipherSpec

  • これは後方互換性で残ってるだけなので気にしなくて良い
# if the client sends a non-empty session ID, the server MUST send the change_cipher_spec as described in thi appendix.
# 後方互換性を維持するため
# TLS 1.3では無視される
Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ChangeCipherSpec (20)
  Length = 1
    change_cipher_spec (1)

ClientHello(クライアント → サーバー)

  • HelloRetryRequestを受けて、もう一度送る。今回は鍵交換アルゴリズムがsecp256r1(ECDHE(P256))に変更されている
  • 鍵交換用の公開鍵もこの時点で一緒に送っている。(key exchange)
Sent Record
Header:
  # legacy_record_versionなのでTLS 1.3では実際には使われていない
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 273
    ClientHello, Length=269
      client_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0x35DD6BF8
        random_bytes (len=28): F03CB39FC11DFF87492CC9E7DF398790A866BF4BEABD621267E8041E
      session_id (len=32): 31681F7735E44982BCADCA2B7BE8884BA073BBF79CF0456B1A859BFFBFA27FE9
      cipher_suites (len=8)
        {0x13, 0x02} TLS_AES_256_GCM_SHA384
        {0x13, 0x03} TLS_CHACHA20_POLY1305_SHA256
        {0x13, 0x01} TLS_AES_128_GCM_SHA256
        {0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
      compression_methods (len=1)
        No Compression (0x00)
      extensions, length = 188
        extension_type=server_name(0), length=16
          0000 - 00 0e 00 00 0b 65 78 61-6d 70 6c 65 2e 63 6f   .....example.co
          000f - 6d                                             m
        extension_type=ec_point_formats(11), length=4
          uncompressed (0)
          ansiX962_compressed_prime (1)
          ansiX962_compressed_char2 (2)
        extension_type=supported_groups(10), length=22
          ecdh_x25519 (29)
          secp256r1 (P-256) (23)
          ecdh_x448 (30)
          secp521r1 (P-521) (25)
          secp384r1 (P-384) (24)
          ffdhe2048 (256)
          ffdhe3072 (257)
          ffdhe4096 (258)
          ffdhe6144 (259)
          ffdhe8192 (260)
        extension_type=session_ticket(35), length=0
        extension_type=encrypt_then_mac(22), length=0
        extension_type=extended_master_secret(23), length=0
        extension_type=signature_algorithms(13), length=30
          ecdsa_secp256r1_sha256 (0x0403)
          ecdsa_secp384r1_sha384 (0x0503)
          ecdsa_secp521r1_sha512 (0x0603)
          ed25519 (0x0807)
          ed448 (0x0808)
          rsa_pss_pss_sha256 (0x0809)
          rsa_pss_pss_sha384 (0x080a)
          rsa_pss_pss_sha512 (0x080b)
          rsa_pss_rsae_sha256 (0x0804)
          rsa_pss_rsae_sha384 (0x0805)
          rsa_pss_rsae_sha512 (0x0806)
          rsa_pkcs1_sha256 (0x0401)
          rsa_pkcs1_sha384 (0x0501)
          rsa_pkcs1_sha512 (0x0601)
        extension_type=supported_versions(43), length=3
          TLS 1.3 (772)
        extension_type=psk_key_exchange_modes(45), length=2
          psk_dhe_ke (1)
        # 鍵交換アルゴリズムに必要な情報
        # 2回目のClientHelloではECDHE(P256)[ECDSA]に合わせにきた
        extension_type=key_share(51), length=71
            NamedGroup: secp256r1 (P-256) (23)
            key_exchange:  (len=65): 04992A612FA63842BD66B63A64A523C1D9A5B506D7C33BC98663C10134B5262FF91E017D36543BA962F6B948EB706F9F4868B23B45409CE5498A91530D22039E46

ChangeCipherSpec

Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ChangeCipherSpec (20)
  Length = 1

ServerHello(サーバー → クライアント)

  • 鍵交換用の公開鍵もこの時点で一緒に送っている。(key exchange)
    • 今回はECDHE(P256)が鍵交換アルゴリズム
    • この時点では中間者攻撃に脆弱だが、続くCertificate, CertificateVerifyのサーバー認証でドメインが自分が指定した通り正しいのかのかがわかるので、中間者攻撃を防ぐことができる
  • これを送った時点でClientとServerで鍵交換(アルゴリズムはsecp256r1)は完了する。
  • TLS_AES_256_GCM_SHA384を暗号化スイートという
    • AES_256_GCM(AEAD)を使って暗号化する
    • 鍵交換で得たClientとServerの共有鍵はそのまま使われずにHKDF(HMAC-based Key Derivation Function)で演算されて使用される。このアルゴリズムがSHA384(HKDF ハッシュ)
    • (TLS1.3 の暗号スイートでは、TLS1.2 までの暗号スイートの組から「鍵交換」と「署名」が外され、「暗号化_ハッシュ関数」だけの構成に変更されている)
  • 暗号スイート(TLSv1.3)の一覧はこちら。
# openssl ciphers -V | grep TLSv1.3
          0x13,0x02 - TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(256)            Mac=AEAD
          0x13,0x03 - TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any      Au=any   Enc=CHACHA20/POLY1305(256) Mac=AEAD
          0x13,0x01 - TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any      Au=any   Enc=AESGCM(128)            Mac=AEAD
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = Handshake (22)
  Length = 155
    ServerHello, Length=151
      server_version=0x303 (TLS 1.2)
      Random:
        gmt_unix_time=0xA749AB6C
        random_bytes (len=28): 14CC657380A00CB3B8F963AEB18C8DB57F6F5B98184DEC8C8BA002BB
      session_id (len=32): 31681F7735E44982BCADCA2B7BE8884BA073BBF79CF0456B1A859BFFBFA27FE9
      cipher_suite {0x13, 0x02} TLS_AES_256_GCM_SHA384
      compression_method: No Compression (0x00)
      # ServerHelloには最低限必要なサーバ拡張のみを含める
      extensions, length = 79
        extension_type=supported_versions(43), length=2
            TLS 1.3 (772)
        # クライアントとサーバー側で鍵交換アルゴリズムの情報共有が完了した
        extension_type=key_share(51), length=69
            NamedGroup: secp256r1 (P-256) (23)
            key_exchange:  (len=65): 04F607ED2AB82332065CECC7DE39FF900C89E5201D885461AFE2FAB809101BB6E0976F74ECBF048F61042CC79B6DD7097CA9A44077BEEF3B5D6D8808DDB6317651

EncryptedExtensions(サーバー → クライアント)

  • ServerHelloには最低限必要なサーバ拡張のみを含めるので、EncryptedExtensionsで追加の拡張をクライアントに知らせる。今回の場合は特になし。
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 23
  Inner Content Type = Handshake (22)
    EncryptedExtensions, Length=2
      No extensions

CertificateRequest

  • オプション
  • クライアント認証を要求する場合、サーバは CertificateRequest メッセージを送信する。普通はサーバー認証のみでいい。今回の場合も不要なので、なにもない

Certificate(サーバー → クライアント)

  • 後続のCertificateVerifyと合わせて、鍵共有した相手が本物かどうかを認証する(サーバー認証)
  • 証明書チェーンを送る
    • サーバー証明書は先頭にある必要があるが、それ以外は順不同で良い(TLS1.2の場合はチェーンの順番の通りにおくる)
    • 証明書については長くなったので補足に書いた
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 3120
  Inner Content Type = Handshake (22)
    Certificate, Length=3099
      context (len=0):
      certificate_list, length=3095
        ASN.1Cert, length=1867
------details-----
# 省略..

CertificateVerify + Finished(サーバー → クライアント)

  • サーバーが自分が指定した通りの正しいドメインなのかを示す(真正性)
  • 今回の場合はクライアント認証を行わないので、サーバー側のFiinshedは即座に行われる。
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 281
  Inner Content Type = Handshake (22)
    CertificateVerify, Length=260
      # ClientHelloのsignature_algorithmsでrsa_pss_rsae_sha256は候補にあるので、サーバーはverifyできる
      Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
      # 証明書の秘密鍵で署名(sign)
      # 署名の内容は
      ## 64個のスペースからなる文字列
      ## 署名の目的を表す文字列
      ## 1バイトのゼロ
      ## トランスクリプトハッシュをhash化したもの
      Signature (len=256): 07976A96BBC8B94F392774D57C7F4E72163AD5014D9452BA1CA8EC843F6A76E50238E1647C054ABBDA63A2545A3858265DE33DE6FA6EFAC61CD76D922C31A1669F9B847721ECA4E04F25A65232130FBF658386ABF8A03B3EA495E29C9738F3942D1D595D3834693630B226C9D64A315039DC67CD0AA9D552C655722FB35FBF181FCFB1824D4AF9F24B76CEADCF7D5F982C189E5B0CA399D1772BD942A94DE425B70E530629D2932AD798AEBDF5E5BF54E4103DC1DDE5D902C9320606B4125ED0374BAB9F872A37EE3AD8986594622A4E848A51CEA51B48AC26E013279F6F0D95E7BF7CAD3F5C391C12FC5B3E9182D97EE713E4AE69A65BA89147561C223276FD

Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 69
  Inner Content Type = Handshake (22)
    Finished, Length=48
            # Client Hello,ServerHello, Certificate, CertificateVerifyメッセージのハッシュ(トランスクリプトハッシュ)から計算したHMAC値
      verify_data (len=48): 4D9C3D7D0E6D2F8D086EEE21BF996C111F9D7F231A131612005892F8A0ABB77176FFBECDDE582483D33DB7005753F8F3

Certificate(クライアント → サーバー)

  • クライアント認証しないのでなし

CertificateVerify(クライアント → サーバー)

  • クライアント認証しないのでなし

Finished(クライアント → サーバー)

  • このメッセージを送る前にCertificateVerifyで送られてきた署名を検証する
    ---
    Certificate chain
     0 s:C = US, ST = California, L = Los Angeles, O = Internet\C2\A0Corporation\C2\A0for\C2\A0Assigned\C2\A0Names\C2\A0and\C2\A0Numbers, CN = www.example.org
       i:C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
       a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
       v:NotBefore: Mar 14 00:00:00 2022 GMT; NotAfter: Mar 14 23:59:59 2023 GMT
     1 s:C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
       i:C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
       a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
       v:NotBefore: Apr 14 00:00:00 2021 GMT; NotAfter: Apr 13 23:59:59 2031 GMT
- サーバーからの証明書チェーンを検証すると最終的にrootCAのルート証明書の公開鍵で検証することになる。rootCAはmacだとキーチェーンアクセス.appを開いて左のシステムルートを見ればあるよ。
Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 69
  Inner Content Type = Handshake (22)
    Finished, Length=48
      # トランスクリプトハッシュから計算したHMAC値
      verify_data (len=48): A3A130777F6918332209C60FAE85663D7DCBBDCB14BD7125840E6DE5DDCDC59F66B126D015522661570EA26E9AFA66BB

結果

  • 鍵交換はServerHelloで既に終わっているが、中間者攻撃を防ぐためサーバー認証をCertificate, CertificateVerifyで行った。クライアントでFinishedが出たので、これでセキュアな通信が実現できている。
    • この結果は単に標準出力されてるだけ
  • New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
    • AES_256_GCM(AEAD), SHA384(HKDF(HMAC-based key derivation function(KDFは鍵導出関数の意味)))
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: ECDH, prime256v1, 256 bits
---
SSL handshake has read 3772 bytes and written 603 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
# ルート証明書がOpenSSLコマンドが参照しているルート証明書のリストに存在してないためエラーが発生する
# 今回の場合ubuntu:22.04のコンテナで試しているためと思われる
# macで改めてやるとVerify return code: 0 (ok)とでた。
Verify return code: 20 (unable to get local issuer certificate)

NewSessionTicket(サーバー, クライアント)

  • TLS 1.3ではPSK(Pre-Shared key)を使って、次回からサーバー認証が省略できる
    • Resumption PSK(Pre-Shared key)を取得できる
      • openssl s_client -connect [example.com:443](http://example.com:443/) -sess_out sess.pemでnew session ticketの情報が取得できる。情報を見るにはopenssl sess_id -text -noout -in sess_out.txtとすればよい。
      • openssl s_client -connect [example.com:443](http://example.com:443/) -trace -tls1_3 -psk_session sess.pemとやってもServerHelloの際にpre_shared_key拡張がないので、サーバー側でPSKに関する設定が設定されていないようだ。(結局証明書を用いてサーバー認証することになる)
    • サーバーから2回きているのはよくわからない。
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 234
  Inner Content Type = Handshake (22)
    NewSessionTicket, Length=213
        ticket_lifetime_hint=7200
        ticket_age_add=1739279873
        # ハンドシェイクでやり取りするメッセージと、チケッ トの中の ticket_nonce を使って、事前共有鍵を計算
        ticket_nonce (len=8): 0000000000000000
        ticket (len=192): 31AB6443AF14A4998F9A7867BD68EF494C9D4D0FA212F3067E3612341DA50570DE3A2555AC9D437CEFF27E413FD728FA591C8A3BA2CB4BAF1FDE24D981D87C32079AB7BB55D2B291FE44E51CB6B4DC1B9734FB486A7782BFF73161EA298A95B3C7775527F391AF281F7D3D6EDF440440550B2C9F0F2D8C466050697E1C89B9F017AFB15177549E2579190C221EF28C0E2BFB189512305A5AC6A35E65B7F11074022E8B37CA16E6710698F3D04F2B7142AFD5844A858498F400FD6122938D230C
        No extensions
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 49B1BDD536A49D7B469798BE1908620E50DC5C73E5CFA40F22FA78DFCFABF96A
    Session-ID-ctx:
    Resumption PSK: 4CC1B6A46111BDB5F3903D2C7B73B5D56CC432C14CA4D776AD369B03438434888B3E5893091BB2F2A21D3D21A8555813
# .. New Session Ticketの情報: 省略
read R BLOCK
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 250
  Inner Content Type = Handshake (22)
    NewSessionTicket, Length=229
        ticket_lifetime_hint=7200
        ticket_age_add=2813208477
        ticket_nonce (len=8): 0000000000000001
        ticket (len=208): 31AB6443AF14A4998F9A7867BD68EF49AA308BB09C4E6D31B5AFCF811BA48BCBA8B8FA5E4365F3AA83C594A8B850BFDCDE2F7821A8B9CFEFF3F4C3E52C340249B9A1D4523605B0ED375F88F8C6DA7BCF4045E881E6F459ABF9344DBF24B98B25BD4B9C7D981AA48C6512A1B7BE3FB8469B7397FE906E9EE191FD6FF21EEB4E3DFB3952BEDCA8A3350EECAE0457924A3446F1CEFFFD25AF512617A8E09AF065FD43CCE448A1EAF70A00C5CA7C9BB0F706656709CFE47BF371109D8000494EA3555C3EB4EF3E5974BC9A53BD23B7C7871E
        No extensions
# New Session Ticketの情報: 省略

HTTPリクエストの送信、レスポンスの受信

  • これで平文を暗号化して安全にデータを送れる
    • AES_256_GCM(AEAD(認証付き暗号: 暗号は共通鍵暗号))で暗号化
read R BLOCK
# ここで入力待ちになるので、改行含め以下の4行をペーストする
GET / HTTP/1.1
Host: example.com
user-agent: openssltest

Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 32
  Inner Content Type = ApplicationData (23)
Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 35
  Inner Content Type = ApplicationData (23)
Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 41
  Inner Content Type = ApplicationData (23)
Sent Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 18
  Inner Content Type = ApplicationData (23)
Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 352
  Inner Content Type = ApplicationData (23)
HTTP/1.1 200 OK
Age: 465503
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Tue, 20 Sep 2022 12:19:19 GMT
Etag: "3147526947+ident"
Expires: Tue, 27 Sep 2022 12:19:19 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (sab/5740)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

Received Record
Header:
  Version = TLS 1.2 (0x303)
  Content Type = ApplicationData (23)
  Length = 1273
  Inner Content Type = ApplicationData (23)
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    </style>
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

補足

証明書

# サーバー証明書はbase64形式になっているので、それをデコードしてパースするコマンドは次の通り。
# openssl x509 -text -noout -in serv.crt
Certificate:
    Data:
        Version: 3 (0x2)
        # 証明書の識別番号
        Serial Number:
            0f:aa:63:10:93:07:bc:3d:41:48:92:64:0c:cd:4d:9a
        Signature Algorithm: sha256WithRSAEncryption
        # 発行者
        Issuer: C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
        Validity
            Not Before: Mar 14 00:00:00 2022 GMT
            Not After : Mar 14 23:59:59 2023 GMT
        # 証明書の所有者の名前
        Subject: C = US, ST = California, L = Los Angeles, O = Internet\C2\A0Corporation\C2\A0for\C2\A0Assigned\C2\A0Names\C2\A0and\C2\A0Numbers, CN = www.example.org
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:95:5d:96:63:9a:e5:1a:7d:5f:a7:0b:ee:06:18:
                    f4:9d:50:5c:37:10:b1:90:75:06:fe:92:46:e0:7b:
                    da:25:e9:fb:60:86:75:98:b7:3b:fc:fe:2c:9c:e2:
                    59:88:47:f0:58:54:e2:90:73:5b:71:40:9c:62:22:
                    86:f0:99:05:79:b6:4e:60:c7:35:53:d3:e2:12:d5:
                    56:19:4e:24:b9:8b:b1:89:7a:43:f2:83:0f:8a:7d:
                    41:d1:28:2b:17:b8:0a:7c:ed:7f:fc:8d:b0:78:97:
                    40:52:38:19:b9:70:42:3c:09:61:cf:61:27:1d:d7:
                    73:5d:4b:70:9b:d5:ee:38:b3:bf:63:a2:c0:4d:53:
                    2c:6e:9f:3f:95:79:df:a3:f6:d7:d1:48:09:ec:2d:
                    1a:56:a3:ae:d3:b0:34:56:be:8e:90:fc:70:5a:63:
                    af:17:77:11:2a:15:42:33:b5:38:07:9d:4a:2b:e2:
                    2c:59:12:e6:f1:c5:56:d4:86:97:8f:08:46:cd:6e:
                    c1:47:a1:08:de:cc:42:43:85:a7:73:a1:d5:3d:28:
                    26:a2:62:d6:59:69:08:18:53:c0:c1:c5:94:07:83:
                    42:d7:6c:a1:08:ee:62:5b:f7:71:34:c5:8d:2c:c4:
                    55:b6:76:40:ca:ae:85:a5:9f:30:14:ae:a3:e0:e3:
                    30:33
                Exponent: 65537 (0x10001)
        # 追加的な属性
        X509v3 extensions:
            # 証明書の署名を検証するために使用する公開鍵の識別子
            X509v3 Authority Key Identifier:
                B7:6B:A2:EA:A8:AA:84:8C:79:EA:B4:DA:0F:98:B2:C5:95:76:B9:F4
            # 
            X509v3 Subject Key Identifier:
                F7:2A:09:D0:24:5B:11:71:EE:BA:BE:F4:3E:1C:3D:56:12:88:16:BB
            X509v3 Subject Alternative Name:
                DNS:www.example.org, DNS:example.net, DNS:example.edu, DNS:example.com, DNS:example.org, DNS:www.example.com, DNS:www.example.edu, DNS:www.example.net
            # 用途
            # criticalの意味: これを解釈できなかった場合はこの証明書を破棄する
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            # CRL: 証明書失効リスト
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl
                Full Name:
                  URI:http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl
            # 証明書の利用目的に応じたポリシー
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.2.2
                  CPS: http://www.digicert.com/CPS
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1-1.crt
            X509v3 Basic Constraints:
                CA:FALSE
            # SCT: Signed Certificate Timestamp
            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : E8:3E:D0:DA:3E:F5:06:35:32:E7:57:28:BC:89:6B:C9:
                                03:D3:CB:D1:11:6B:EC:EB:69:E1:77:7D:6D:06:BD:6E
                    Timestamp : Mar 14 22:48:46.197 2022 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:44:02:20:31:78:F3:53:EB:46:7F:BD:32:53:3D:5A:
                                F2:88:6C:D7:AC:BC:42:34:94:2A:B5:E5:0B:92:0B:81:
                                10:C6:C6:FE:02:20:47:74:30:BC:82:C9:21:60:14:7E:
                                F4:9F:25:0F:F3:32:6A:AB:D8:90:DA:9D:61:3C:BB:36:
                                C2:E0:45:9B:73:00
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 35:CF:19:1B:BF:B1:6C:57:BF:0F:AD:4C:6D:42:CB:BB:
                                B6:27:20:26:51:EA:3F:E1:2A:EF:A8:03:C3:3B:D6:4C
                    Timestamp : Mar 14 22:48:46.204 2022 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:44:02:20:3B:29:4F:1C:24:50:1A:44:A1:E0:3E:22:
                                89:4D:63:03:8A:97:D6:31:9B:09:3C:D7:AC:9D:D0:ED:
                                88:24:F6:5C:02:20:15:F1:35:A1:A0:E2:E2:8A:A1:8A:
                                9D:8D:36:09:D7:06:5C:EC:C0:CC:2E:ED:4F:A9:BB:3A:
                                D2:C0:92:ED:BE:58
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : B3:73:77:07:E1:84:50:F8:63:86:D6:05:A9:DC:11:09:
                                4A:79:2D:B1:67:0C:0B:87:DC:F0:03:0E:79:36:A5:9A
                    Timestamp : Mar 14 22:48:46.215 2022 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:45:02:20:29:1E:EA:C0:F2:D0:6F:A5:13:DB:E4:BB:
                                C3:BB:90:B1:BB:03:65:F6:55:5F:F8:3C:16:40:6D:02:
                                5B:5A:4E:90:02:21:00:CB:76:D7:9D:44:D1:8D:86:EC:
                                D8:A4:1E:A0:98:10:72:76:1B:52:42:2E:58:64:BB:29:
                                16:F6:95:1E:97:96:D7
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        aa:9f:be:5d:91:1b:ad:e4:4e:4e:cc:8f:07:64:44:35:b4:ad:
        3b:13:3f:c1:29:d8:b4:ab:f3:42:51:49:46:3b:d6:cf:1e:41:
        83:e1:0b:57:2f:83:69:79:65:07:6f:59:03:8c:51:94:89:18:
        10:3e:1e:5c:ed:ba:3d:8e:4f:1a:14:92:d3:2b:ff:d4:98:cb:
        a7:93:0e:bc:b7:1b:93:a4:42:42:46:d9:e5:b1:1a:6b:68:2a:
        9b:2e:48:a9:2f:1d:2a:b0:e3:f8:20:94:54:81:50:2e:ee:d7:
        e0:20:7a:7b:2e:67:fb:fa:d8:17:a4:5b:dc:ca:00:62:ef:23:
        af:7a:58:f0:7a:74:0c:bd:4d:43:f1:8c:02:87:dc:e3:ae:09:
        d2:f7:fa:37:3c:d2:4b:ab:04:e5:43:a5:d2:55:11:0e:41:87:
        5f:38:a8:e5:7a:5e:4c:46:b8:b6:fa:3f:c3:4b:cd:40:35:ff:
        e0:a4:71:74:0a:c1:20:8b:e3:54:47:84:d5:18:bd:51:9b:40:
        5d:dd:42:30:12:d1:3a:a5:63:9a:af:90:08:d6:1b:d1:71:0b:
        06:71:90:eb:ae:ad:af:ba:5f:c7:db:6b:1e:78:a2:b4:d1:06:
        23:a7:63:f3:b5:43:fa:56:8c:50:17:7b:1c:1b:4e:10:6b:22:
        0e:84:52:94