はじめに
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は結構違う
- 「HTTPSは公開鍵暗号を用いて平文(やShakeHands時のメッセージ)を暗号化している」は間違い
- 公開鍵暗号はTLS1.3の全てを通して暗号化のために用いられていない
- TLS1.2でもどちらにせよ公開鍵暗号は暗号化のために用いられていない
- 言葉の使い方が難しいですね
参考url
- プロフェッショナルSSL/TLS (付録Aが中心)
- RFC8446 https://www.rfc-editor.org/rfc/rfc8446
- IPA TLS 暗号設定ガイドライン
- 今回の全てのlog: https://gist.github.com/knknkn1162/391d3dcece41e0a710585164e880dbd6
- https://laboradian.com/issuing-ssl-certificate/#2
- マスタリングTCP/IP 第2版
- 暗号と認証 仕組みと理論がしっかりわかる教科書
コマンドについて
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.com のHTTPSのやりとりをtraceしてる
プロトコルの流れ
注意) TLS1.2と結構違う。特に大きく違うのが、ServerHello完了時にDH鍵交換が終了していること。これによってAEAD(認証付き暗号、暗号技術は共通鍵暗号)を用いて3以降は暗号化され、サーバー認証が行われる。対してTLS1.2では鍵交換がサーバー認証時とセットになって行われる。
(TCPによる3 way handshake)
[Client → Server] ClientHello
- [Server → Client]ServerHello
- もしネゴシエーションできなかった場合はHelloRetryRequest → 1に戻る
- [Server → Client] EncryptedExtensions
- [Server → Client] CertificateRequest
- 今回のケースではサーバー認証のみとするので、ここはなし
- [Server → Client] Certify
- [Server → Client] CertificateVerify
- [Server → Client] Finished
- [Client → Server] Finished
- ([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
- 後方互換性のため、TLS1.3では無視される
Received Record Header: Version = TLS 1.2 (0x303) Content Type = ChangeCipherSpec (20) Length = 1
ServerHello(サーバー → クライアント)
- 鍵交換用の公開鍵もこの時点で一緒に送っている。(key exchange)
- これを送った時点でClientとServerで鍵交換(アルゴリズムはsecp256r1)は完了する。
- TLS_AES_256_GCM_SHA384を暗号化スイートという
- 暗号スイート(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で送られてきた署名を検証する
- https://laboradian.com/issuing-ssl-certificate/#2 が詳しい
- 以下のように”-trace”で出力もされている
- ブラウザ(Google Chromeなど)のurl入力の左鍵マークをクリックすることでも確認できる
--- 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回きているのはよくわからない。
- Resumption PSK(Pre-Shared key)を取得できる
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>
補足
証明書
- https://gist.github.com/knknkn1162/391d3dcece41e0a710585164e880dbd6#file-s_client-log-L507-L547 の証明書(サーバー証明書を例にする)。別途保存してserv.crtとしている。
証明書はX.509という規格でフォーマットが決まっている
- サーバー証明書(CRTファイルともいう)は以下のコマンドで確認できる
- TLS1.3ではトランスクリプトハッシュ(プロトコルのメッセージをハッシュ化したもの)を(サーバーの)秘密鍵で署名(sign)する。これをCertificateVerifyメッセージでクライアントに送信する
# サーバー証明書は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