SSL通信の仕組みを深堀してみた

## はじめに
最近、SSLの仕組みについて考えることが増えてきました。
様々な情報があり、なかなか整理できないと思っていたら、非常に良い本に出会いましたので、知識のアウトプットも込めて記事にしたいと思います。

https://www.sbcr.jp/product/4797396805/


## 対象者
この記事は下記のような人を対象にしています。

- セキュリティに携わるエンジニアさん
- プログラミング学習者さん

## 構成
SSLの通信の流れは、さまざまな技術が絡んできます。しかし大きく分けると

・事前準備
・暗号化データ通信

の二つに分かれます。
そのため本記事では

①前提知識
➁SSL/TLS通信の流れ～事前準備編
③SSL/TLS通信の流れ～暗号化データ通信

という構成でお書きします。

## 前提知識

### SSL/TSLの存在理由
そもそもSSL/TLSの存在理由としては、**「盗聴」「改ざん」「なりすまし」の脅威から守ること**となります。

盗聴：暗号化
改ざん：ハッシュ化
なりすまし：デジタル証明書

上記のように、SSL/TSLにはそれぞれの脅威に対応する技術が使用されています。

### プロトコルとしての立ち位置
SSL/TLSはHTTPSとしてよく使用されがちですが、ほかのアプリケーションプロトコルにも対応しています。
例えばFTPやSMTPなどです。HTTP「S」のように最後に「S」が付きますね。
FTP→FTPS
SMTP→SMTPS

SSL/TLSはトランスポート層で動作しますが、TCPを使用しますのでイメージとしては4.5層にいるととらえるとよいかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/0e250e3b-9f83-145b-68f4-2648e9824054.png)


### 暗号化、復号化

**暗号化、復号化は盗聴に対応する技術**です。これらのプロセスを理解するために、まず「鍵」、「計算アルゴリズム」、「平文」という用語を理解する必要があります。

1. **鍵 (Key)**: 暗号化や復号化を行う際に使われるデータです。これは、一連の命令に基づいて情報を変換するために使用されます。鍵は公開鍵（誰でもアクセス可能）と秘密鍵（秘匿された鍵）の二種類があります。

2. **計算アルゴリズム (Algorithm)**: 暗号化や復号化のプロセスで使用される数学的手順です。このアルゴリズムは、平文を暗号化されたテキストに変換したり、その逆を行ったりします。

3. **平文 (Plaintext)**: 暗号化されていない、つまり通常の読める形式のテキストです。これは暗号化プロセスによって暗号化される元のメッセージです。

#### 暗号化プロセス
1. **平文の準備**: 情報（例えば、メッセージ）は平文として存在します。

2. **暗号化**: 平文は特定の暗号化アルゴリズムと鍵を使用して暗号化されます。このプロセスにより、平文は読み取り可能な形式から読み取り不可能な形式（暗号文）に変換されます。

3. **暗号文の生成**: 暗号化プロセスの結果として、平文は暗号文に変換されます。この暗号文は、鍵を持っていない人には理解できない形式です。

#### 復号化プロセス
1. **暗号文の受信**: 暗号化された情報（暗号文）を受け取ります。

2. **復号化**: 受信した暗号文は、適切な鍵（通常は秘密鍵）と同じ暗号化アルゴリズムを使用して復号化されます。

3. **平文の復元**: 復号化プロセスにより、暗号文は元の平文の形式に戻ります。

要するに、「鍵」「計算アルゴリズム」を用いて、平文を暗号化するor復号化する。
と認識しておくとよいかと思います。

### ハッシュ化
ハッシュ化は**改ざんに対応する技術で、決められた計算に基づいて固定長のデータを作り出します。**
例えば、
①送信者がアプリケーションデータをハッシュ化
➁アプリケーションデータとハッシュ値を受信者に送信
③受信者がアプリケーションデータとハッシュ値を受信

というシナリオがあったとします。
その場合は**受信者が受信したハッシュ値と、自らアプリケーションデータをハッシュ化したハッシュ値を比べることで、アプリケーションデータの改ざんの有無を調べる**ことができます。
SSL/TLSでは**メッセージ認証コード**というセキュリティ的な要素をさらに加えています。
これは**アプリケーションデータと暗号化・復号化で使用する共通鍵を混ぜてハッシュ値を計算する**という考えです。

実際のSSL/TLSでは以下のようにして、改ざんの有無を把握できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/17c80943-02ff-64ab-f002-a4ff071886a1.png)

### デジタル証明書
デジタル証明書はなりすましに対応する技術です。
いくら通信の安全性を確保しても、送信先が悪意のあるサーバだった場合は、元も子もありません。
送信先サーバが、悪意のないサーバであることを証明するため、デジタル証明書という技術は使用されます。
デジタル証明書以下で構成されています。

・署名前証明書
・デジタル署名のアルゴリズム
・デジタル署名

第三者である**認証局**が「そのサーバAが本当にサーバAであること」をデジタル署名という形で認めてもらっています。
なお、デジタル署名とは**署名前証明書をハッシュ化し、認証局の秘密鍵で暗号化したもの**となります。
このデジタル証明書をあらかじめサーバから共有されることで、「そのサーバAが本当にサーバAであること」をクライアント端末側で確かめることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/bfe677e7-dd56-0cd6-4496-220c903eb8af.png)

クライアント端末が、デジタル証明書の改ざんの有無を確認するためには
①共有されたデジタル証明書に含まれているデジタル署名を、認証局の公開鍵で復号し、ハッシュ値を確認する
➁共有されたデジタル証明書に含まれている署名前証明書をハッシュ化して、ハッシュ値を算出する
③上記のハッシュ値を比較する
上記のステップで確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/6e6532d8-2fa1-1bf5-7ef6-614fb9e0898b.png)



### SSL/TLSで使用される暗号化方式
先ほど暗号化と復号化のプロセスについて説明しました。
ここからは、SSL/TLSと暗号化がどのように関わってくるのか、深堀します。

SSL/TLSで使用される暗号化方式は**ハイブリット暗号化方式**です。
「ハイブリット暗号化方式」とは、後述する以下の暗号化方式の良いとこどりをした暗号化方式になります。

#### 共通暗号化方式
**「共通鍵暗号方式」とは、暗号化にも復号化にも同じ鍵を使用する方式**です。
送信者と受信者は前もって、鍵を共有し、同じ鍵で暗号化と復号化を行います。
処理速度が速いのがメリットですが、配送中鍵を盗まれてしまったらアウトというデメリットを持っています。

#### 公開鍵暗号化方式
**公開鍵暗号方式とは、暗号鍵と復号鍵の異なる鍵を用いる暗号化方式**です。
受信側が「秘密鍵」と「公開鍵」を作成し、「公開鍵」を公開します。
データの送信側が公開されている「公開鍵」を用いてデータを暗号化することで、「秘密鍵」を持つ受信側のみがデータの中身を確認することができます。
これにより、鍵の配送問題は解決します。
しかし、使用するアルゴリズムが複雑であるため、処理に時間がかかるといったデメリットも存在します。

#### ハイブリット暗号化方式
上記の2つのいいとこ取りをしたのが、ハイブリット暗号化方式です。
**公開暗号化方式を用いて、共通鍵を交換し、それ以降のデータのやり取りは、共通鍵を用いる**という暗号化方式です。
これにより、それぞれが抱えていた以下のデメリットを解消できます。
・共通鍵暗号化方式：鍵の配送問題
・公開暗号化方式：処理が重い問題

順序としては
①受信側が「公開鍵」と「秘密鍵」を作成
➁受信側が「公開鍵」を共有
③送信側が以降の通信で使用する「共通鍵」を「公開鍵」を用いて暗号化し、受信側と共有
④受信側が共有された「共通鍵」を自身の「秘密鍵」で復号化
これ以降は、「共通鍵」を用いて、データの暗号化・復号化が実施されます。

## SSL/TLS通信の流れ～事前準備編
では、今まで紹介してきた前提知識がどのようにSSL/TLSと関わってくるか確認していきます。
ざっくりまとめると、以下のようになります。
※受信側にはすでにデジタル証明書がインストールされているものとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/f18cbbd3-38bb-7b06-447a-a0bfa4504e4a.png)

TCPの3ウェイハンドシェイクの後、上記の事前準備が起こります。これをSSLハンドシェイクと呼びます。
SSLハンドシェイクは
・アルゴリズムの提示
・鍵の交換
・通信相手の証明
・最終確認

上記のステップで構成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/6525d18f-f571-07ad-4f03-f12513066c88.png)

#### アルゴリズムの提示
このステップでクライアントがサポートしているアルゴリズムを共有します。
「暗号化する」「ハッシュ化」する、といってもたくさんの技術が使用されているため、この「Client Hello」で**暗号化アルゴリズムやハッシュ関数を提示**します。
また、後続のステップで「共通鍵の交換」とありますが、実際に交換するのは「共通鍵の素」になります。
そのために必要な**client random**もこのステップで共有します。

#### 通信相手の証明
このステップでは、本物のサーバと通信しているかを、サーバ証明書で確認します。
「server Hello」「Certificate」「Server Hello Done」のステップで構成されています。

**Server Hello**では「Client Hello」で受け取った暗号スイート（暗号化アルゴリズムとハッシュ関数の組み合わせ）と、自分の暗号スイートリストを参照し、最も優先度の高いものを選択し、クライアントに送ります。
また、共通鍵の作成に必要な**server rondam**も共有します。

**Certificate**ではデジタル証明書を送信側に共有します。送信側のブラウザには、多くの場合、信頼されたルート証明書が予めインストールされており、これを「信頼されたルート認証局リスト」と呼びます。

**Server Hello Done**では受信側は必要な情報をすべて共有し終わったことを通知します。

#### 共通鍵の交換
こちらのステップではざっくり
・共通鍵の交換
※実際には**プリマスターシークレット**と呼ばれる共通鍵の素が共有されます。
・マスターシークレットの作成
・MAC鍵とセッション鍵の作成

が行われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/53ebae56-5fef-db0e-e479-80614b9bc5f6.png)

上の図を細かく見ていきましょう。
①送信側は「プリマスターシークレット」を作成する
➁「プリマスターシークレット」を公開鍵を用いて暗号化し、受信側に送る
※公開鍵は、サーバ証明書の構成要素である、「署名前証明書」に含まれています。
③送信側と受信側は、以下の要素をまぜこぜにして「マスターシークレット」を作成する
・プリマスターシークレット
・client random
・server random
④マスターシークレットから「MAC鍵」と「セッション鍵」を作成する

#### 最終確認
以下2ステップで、送信側と受信側でメッセージ暗号化に使用する暗号化アルゴリズムを宣言します。
・Change Cipher Spec
・Finished

ここまででSSLハンドシェイクは終了です。

## SSL/TLS通信の流れ～暗号化データ通信
いよいよアプリケーションデータの暗号化通信開始です。
基本的な理解は**マスターシークレットをもとに作成した「MAC鍵」「セッション鍵」を用いて通信をする**で問題ありません。
送信する際は、アプリケーションデータとMAC値を、セッション鍵で暗号化して送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/18f2c554-e7e4-d049-7724-2485ca15f889.png)

#### SSLセッションの再利用
SSLハンドシェイクにはさまざまな技術がかかわり、処理に時間がかかります。
そのため、ハンドシェイクが成立した後はセッションIDを用いて暗号化通信が継続されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2666121/a2bc2845-7793-333d-1d7d-70f7b056f446.png)


#### SSLセッションのクローズ
最後に、SSLセッションクローズについて触れます。
といっても、クローズしたい側から「close_notify」が走り、そのあとTCP4ウェイハンドシェイクが走るのみです。

## おわりに
SSL/TLSについてまとめてみました。
本当はクライアント認証についても書きたかったのですが、ボリュームが多くなってしまったので、別の機会に書こうと思います。