萌えハッカーニュースリーダー

2025/03/21 21:28 TLS Handshake on Sockets (C++)

hakase
博士

やあ、ロボ子。今日はC++でTLS handshakeを実装する方法について話すのじゃ。

roboko
ロボ子

TLS handshakeですか、博士。なんだか難しそうですね。

hakase
博士

難しくないぞ!要は、クライアントとサーバーが安全に通信するための儀式みたいなものじゃ。特に、TLS_RSA_WITH_AES_128_CBC_SHA cipherをTLSv1.2上で実装する例を見ていくのじゃ。

roboko
ロボ子

なるほど。そのcipherを使うんですね。具体的にはどんな流れになるんですか?

hakase
博士

まずはHello stageじゃ。クライアントがサーバーに挨拶して、サーバーの公開証明書を受け取るのじゃ。

roboko
ロボ子

公開証明書を受け取るんですね。それで、その証明書をどう使うんですか?

hakase
博士

次にKey exchange stageじゃ。クライアントがAES鍵を生成するために必要なデータを、サーバーの公開証明書で暗号化して送るのじゃ。

roboko
ロボ子

AES鍵を暗号化して送るんですね。セキュリティのためには当然ですね。

hakase
博士

そうじゃ。ちなみに、今回の例ではapi.binance.comを使うぞ。でも、CloudFront上でホストされててIPアドレスが変わる可能性があるから、動作確認が必要じゃ。

roboko
ロボ子

IPアドレスが変わるんですか。それは注意が必要ですね。確認はどのようにすれば良いんですか?

hakase
博士

`host api.binance.com`で確認できるぞ。あと、`curl`でホストがアクティブか、`nmap`でcipherが対応してるか確認するのも大事じゃ。

roboko
ロボ子

なるほど、コマンドで確認するんですね。ありがとうございます。

hakase
博士

Hello stageでは、クライアントは`client_hello`(32バイトのランダムバッファ)と`hostname`(api.binance.com)を送るのじゃ。`hostname`はCloudFrontがサービスを識別するために必要じゃぞ。

roboko
ロボ子

`client_hello`はランダムな値なんですね。`hostname`は必須なんですね。

hakase
博士

そうじゃ。サーバーからは`server_random`が返ってくるから、それを抽出するのじゃ。それと、サーバーの公開RSA証明書も取得するぞ。

roboko
ロボ子

`server_random`と公開証明書ですね。これらは何に使うんですか?

hakase
博士

AES鍵を計算するために使うのじゃ!クライアントは`premaster_secret`を生成して、`master_secret`をPRF(Pseudo-random function)で計算するのじゃ。

roboko
ロボ子

`premaster_secret`と`master_secret`ですか。なんだか秘密めいた名前ですね。

hakase
博士

`master_secret = PRF(premaster_secret, "master secret" + client_random + server_random)[:48]`で計算できるぞ。そして、AES鍵を`master_secret`からマッピングするのじゃ。

roboko
ロボ子

複雑な計算式ですね。でも、これでAES鍵が生成できるんですね。

hakase
博士

`client_write_key = master_secret[40:40+16]`がクライアントからサーバーへの暗号化に使われる鍵で、`server_write_key = master_secret[56:56+16]`がサーバーからクライアントへの暗号化に使われる鍵じゃ。

roboko
ロボ子

それぞれ別の鍵を使うんですね。これで通信の安全性が高まるんですね。

hakase
博士

Key Exchange stageでは、RSAで暗号化された`premaster_secret`を送るのじゃ。その後、Change Cipher Specで以降のメッセージが暗号化されることを示すフラグを設定するぞ。

roboko
ロボ子

`premaster_secret`を暗号化して送るんですね。Change Cipher Specは重要なフラグですね。

hakase
博士

最後に、Client Handshake Finishedで、以前のTLS handshakeメッセージのハッシュを計算して`verify_data`を生成し、暗号化して送るのじゃ。

roboko
ロボ子

`verify_data`はハッシュ値を暗号化したものなんですね。これで改ざんを検知できるんですね。

hakase
博士

そうじゃ!TLS handshakeが終わったら、Application dataを送受信できるぞ。AES CBCを使って暗号化するんだけど、Initialization Vector (IV)を使うのを忘れずにの。

roboko
ロボ子

IVを使うんですね。IVがないと、同じ平文が同じ暗号文になってしまいますもんね。

hakase
博士

その通り!暗号化前に16バイトのランダムバッファを生成してパケットに挿入するのじゃ。パディングも忘れずに処理するぞ。ContentTypeは0x17を使うのじゃ。

roboko
ロボ子

ランダムバッファとパディング、ContentTypeですね。細かいけど重要なポイントですね。

hakase
博士

`tls_connection.cpp`の`connect()`関数に実装して、`send()`/`recv()`関数でデータの送受信をするのじゃ。api.binance.comにリクエストを送って、HTTP 200 OKとJSON形式のデータが返ってきたら成功じゃ!

roboko
ロボ子

なるほど、`connect()`関数と`send()`/`recv()`関数ですね。HTTP 200 OKが返ってくるのが目標ですね。博士、今日はありがとうございました!

hakase
博士

どういたしまして。最後に一つ、TLS handshakeは、まるで恋人同士が初めて会う時のように、お互いを確かめ合う大切な儀式なのじゃ。でも、たまにサーバーが「ごめん、今日は機嫌が悪いから通信できない」って400 Bad Requestを返してくることもあるから、注意が必要じゃぞ!

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search