TLS 入門

TLS 入門

TLSは安全に通信するためのプロトコルです。OSI参照モデルのトランスポート層での通信のために使用されます。すなわち、アプリケーションレイヤーを含む、トランスポート層よりも上のレイヤーを暗号化対象とします。

TLSで実現するものとしては、大きく以下の2点が挙げられます。

  • 通信相手の認証

  • 通信の暗号化

少し別の観点で見ると、TLSでは以下の内容を実現します。

  • 機密性(Confidentiality)

  • 完全性(integrity)

  • 真正性(authenticity)

機密性については、暗号化に対応します。データが知らないうちに変わると困ります。完全性については、このようなことがないことを保証します。真正性について、これは認証に対応します。 すなわち、それぞれのリスク対策として、機密性は通信内容が他社に漏れないこと、完全性は通信内容に改ざんがあればそれに気付けること、真正性としては、通信相手、すなわち、Webサイトの運用者になりすましがあれば、すぐに気付けることが挙げられます。

SSL/TLS

そもそも、TLSはSSLとセットで語られることも多く、SSL/TLSなどと表記されることがあります。

SSLとTLSの端的な違いは、例えば、以下のことが挙げられます。

  • SSL

    • Netscape社が開発

    • POODLE攻撃の脆弱性を受ける

  • TLS

    • IETFが策定

    • よりセキュア

    • TLS拡張

      • SNI

      • NPN

      • ALPN

      • セッションチケット

      • OCSPステープリング

      • TLS False Start

SSLとTLSをそれぞれバージョンごとに特徴を挙げると以下のようになります。

  • SSL

    • SSL 1.0

      • Netscape社が商用トランザクションのセキュリティのためにの開発を始めたが、リリースされなかった

    • SSL 2.0

      • Netscape Navigator 1.1という当時支配的だったブラウザに実装

      • ただし、重大な脆弱性があり、SSL 3.0の開発を始める

    • SSL 3.0

      • スクラッチで開発。TLSの各バージョンにも受け継がれる設計を確立

      • POODLE攻撃の脆弱性を受け、TLSの利用が推進され始める

  • TLS

    • TLS 1.0

      • 標準化されたHMACによってPRFが規定

      • マスターシークレットが独自構成ではなく、PRFで生成

      • verifay_dataの値が独自構成ではなく、PRFで生成

      • 完全性の検証(MAC)で標準化されたHMACを利用

      • パディングのフォーマット変更

      • 暗号スイートからFORTEZZAを除外

    • TLS 1.1

      • CBC暗号化利用モードで、各TLSレコードに明示的なIVを利用

      • パディング攻撃対策として、bad_record_macアラートを返すことを要求。decryption_failedアラートを廃止

      • TLS拡張

    • TLS 1.2

      • AEADのサポート

      • HMAC-SHA256暗号スイートのサポート

      • IDEAおよびDES暗号スイートを除外

      • TLS拡張が主要なプロトコルの使用に組み込み

      • クライアントが新しい拡張signature_algorithmを使って受け入れを希望するハッシュと署名のアルゴリズムを通知可能

      • PRFでMD5とSHA1を組み合わせていた部分をSHA256に置き換え

      • 暗号スイートで独自のPRFを指定可能

      • デジタル署名でMD5とSHA1を組み合わせていた部分をデフォルトでSHA256に置き換え。ただし、暗号スイートでハッシュ関数を指定可能

      • Finishedメッセージのverify_data要素の長さを暗号スイートで明示的に指定可能

    • TLS 1.3

      • セキュリティ強度の高い暗号アルゴリズムを要求

      • セッションのリネゴシエーションや再開に関する脆弱性のある方式を廃止し、セッション再開については新たな方式を採用

      • ネゴシエーション (handshake) シーケンスの大幅な変更

以降は、基本的にTLS 1.2をベースとした内容で説明します。

TLSハンドシェイク

TCPの3ウェイハンドシェイクによりTCPコネクションを確立後に、TLSハンドシェイクが行われます。

TLSハンドシェイクの流れは例えば、TLS 1.2でのフルハンドシェイクでは以下のような流れになります(引用元: RFC5246)。大きく実施している内容を分類すると、接続方法のネゴシエーション、認証およびマスターシークレットの共有、完全性検証の3つに分けられます。

接続方法のネゴシエーションが行われることについて言及しましたが、これはクライアントとサーバーがそれぞれ可能な処理内容を暗号スイートを通してやりとりします。

暗号スイートにはTLSの目的を実現する手段と、その手段を実現するにあたっての情報の交換方法が書かれています。 クライアント側は自身が対応している暗号スイートを優先度順にしてリストを送ります。通常は、サーバー側は自身で対応している暗号スイートの中で、クライアントから提示されたリストの上から選択します。Server Order Preference等の設定が行われている場合は、サーバー側のリストの上から選択します。 このようにネゴシエーションが行われて、どのようにTLS通信が行われるかが決まります。

すなわち、TLSハンドシェイクは様々な方法でも実現可能な仕組みのフレームワークのようなものです。

暗号スイート

暗号スイートは例えば、以下のような文字列で表します。

上記は大きく4つの要素からなり、それぞれ以下の内容を実現する方法を表しています。

  • ECDHE : 鍵交換

  • ECDSA : 認証

  • AES128 : 暗号

  • SHA256 : データ完全性

もう少し掘り下げると、それぞれ以下のとおりです。

  • 鍵交換(Key Exchange)

    • TLSハンドシェイク内で具体的にどういった方法で鍵交換を行うかの取り決め

    • TLSハンドシェイクの説明を聞くと、このRSAの説明のみをイメージしてしまっている人も多いという印象

  • 認証(Authentication)

    • 認証はTLSの目的の一つ。大事な機能で忘れちゃだめ。

  • 暗号(Cipher)

    • 機密性はTLSの目的の一つ。これが一番みんながイメージが湧きやすいところか。

  • データ完全性(Data Integrity)

    • 完全性はTLSの目的の一つ。データが改ざんされていれば気付けるようにしておくために、ハッシュ関数を使用する

    • message authentication algorithm のことを指していて、メッセージの認証に使用。OpenSSLだとMacという記載からも分かる

一般的な名称とOpenSSLでの名称

例えば、以下のようなフォーマットで先程説明したものとは異なる表記のものを見かけることもあるでしょう。

OpenSSLで以下のようなコマンドを実行すると、利用可能な暗号スイートのリストが見られます。ここに含まれていることが確認できます。その横に詳細が書かれていますが、上記暗号スイートは、TLS 1.2で、鍵交換はRSA、認証はRSA、暗号化はAES 128bit、MACはSHA256で実行することを記載したものであることがわかります。

OpenSSLでAES128-SHA256と呼ばれるものは一般的な名称でのTLS_RSA_WITH_AES_128_CBC_SHA256に対応付けられます。この名称だとパット見でどの方法で実現するかわかりやすいでしょう。tls_cipher_suite_config_20200707.pdfに記載されているような対応表も参考になるでしょう。

鍵交換

RSA鍵交換

クライアントが、プリマスターシークレットの値として48バイトの乱数を生成して、サーバーの公開鍵で暗号化してClientKeyExchangeメッセージに入れて送信します。サーバー側は自身の秘密鍵で復号することで、プリマスターシークレットの値を入手できます。

この方法の欠点としては、サーバー側の秘密鍵が流出すると、プリマスターシークレットを生成し、セッションを乗っ取ることができます。リアルタイムではなく、過去のデータも遡って見ることができてしまいます。そのたえめ、PFSの性質がありません。

なお、プリマスターシークレットからマスターシークレット生成理由としては、鍵交換方法によってプリマスターシークレットの長さが異なることが理由として挙げられます。

Diffie-Hellman鍵交換 / 楕円曲線Diffie-Hellman鍵交換

Diffie-Hellman鍵交換は、安全ではない通信路で共有鍵を生成するためのアルゴリズムです。この方法では、一方向の計算は簡単で逆方向の計算が困難である数学の性質を利用します。

まず、事前準備として、公開パラメータg,pを事前に共有しておきます。また、サーバー、クライアントはそれぞれ、事前に秘密鍵に相当するx,yという値を用意しておきます。

それぞれ、公開パラメーターから自身のDH公開鍵を以下の計算式で計算します。

サーバーがDH公開鍵を以下のように計算し、クライアントに送ります。

クライアントも同様にDH公開鍵を以下のように計算し、サーバーに送ります。

クライアントはサーバーから送られてきた公開鍵を最初にgの値に対して計算した方法と同様に、サーバーはクライアントから送られてきたDH公開鍵を最初にgの値に対して計算した方法と同様に計算します。すると、以下のように共通の値を取得することができ、このように共有鍵を生成します。

TLSでは古くはサーバー側でランダム生成されるものを使用していましたが、RFC 7919でグループパラメータとして定義されています。IPsecSSHでも同様に事前に一覧表から利用する方法を取ります。

Diffie-Hellman鍵交換にはEphemeral、Static、Anonymousの種類があります。Staticな方法は、サーバーおよりクライアントの証明書に静的にパラメータを埋め込んで利用する方法です。その結果、鍵交換の結果が常に同じ共有鍵になります。一方で、前回の鍵交換で使ったパラメータを利用しない方法はEphemeralな方法で、PFSがある状態になります。DHE(一時的Diffie-Hellman)と呼びます。 TLSでは基本的にStaticな方法もサポートされているが、使われることはなく、TLS 1.3では廃止されています。

DH鍵交換は受動的な攻撃には強いですが、攻撃者が相手のフリをして間に入り込む、いわゆるMan-In-The-Middle(MITM)攻撃には弱いです。そのため、認証と組み合わせて使用します。 TLSではDHの公開鍵に対してデジタル署名を付加することで、署名は相手が公開している公開鍵で検証し、その公開鍵の検証はデジタル証明書のルート証明書が信頼されていることを確認することで行います。

DHとは異なり、楕円曲線暗号を用いたものがECDHE(一時的楕円曲線Diffie-Hellman)です。DHパラメータとしてサーバー側で定義されたある楕円曲線を使用します。

非対称暗号化と対象暗号化

TLSでは非対称暗号化と対称暗号化を使い分けます。端的にそれぞれをまとめると以下のような内容になります。

  • 非対称暗号化

    • 名前からも分かる通り、暗号化側と復号側が異なるもので実現する内容です。

    • 処理のCPUコストが大きい

  • 対称暗号化

    • 事前に同意しておいた秘密鍵を、暗号化側と共通側で共通のものを使用

    • 複数のユーザーがいると、その組み合わせだけ共通鍵が必要になる。

    • キー配布を事前にどのように行うかの問題

鍵交換には暗号スイートのKey Exchangeで指定した対象暗号化の方法が使用されます。その後のデータのやり取りには対称暗号化が利用されます。

ではなぜ、非対称暗号化から対称暗号化に切り替えるか。それは、対称暗号化の処理に対するCPUコストが大きいため、計算に時間がかかり、サイズの大きい計算には不向きだからです。 そのため、最初の認証や共有鍵を相手とやりとりするときに対称暗号化の方法を利用し、その後のデータのやりとりには非対称暗号化が利用されます。

なお、TLSでは共通鍵として、新規コネクションごとにランダムなセッション鍵を使用します。これは侵入者が得ることができる暗号部分の量を減らすためです。仮にバレてもその部分のみしか盗み見られず、影響範囲を抑えることができます。

メッセージ詳細

フォーマット

TLSは、Recordプロトコルがコネkす本庄でやり取りされる低レベルのメッセージ転送をを行います。以下のような構成になっています。

  • メッセージ転送

    • サイズが大きい場合にはチャンクへと分割して転送

  • 暗号化および完全性の検証

    • 最初のネゴシエーションが完了後、ネゴシエーションした結果に基づいて暗号化および完全性の検証

  • 拡張性

    • データの転送や暗号化処理以外はサブプロトコルで行う。

圧縮機能はCRIME攻撃に利用されたことで、現在は利用されていません。

サブプロトコル

TLSのコアとしては以下4つのサブプロトコルが定義されています。

  • Handshakeプロトコル

  • Change Cipher Specプロトコル

  • Application Dataプロトコル

  • Alertプロトコル

Handshakeプロトコルは、実際にTLSハンドシェイクの際に、パラメーターのネゴシエーションや認証を行う際に使用されます。Handshakeプロトコルとしては以下のメッセージが定義されています。ClientKeyExchangeは実際には異なるため、カッコ書きで記載しています。

  • フルハンドシェイク

    • ClientHello

    • ServerHello

    • Certificate

    • ServerKeyExchange

    • ServerHelloDone

    • (ClientKeyExchange)

    • ChangeCipherSpec

    • Finished

  • クライアント認証

    • CertificateRequest

    • CertificateVerify

TLSハンドシェイクの一連の流れで、ChangeCipherSpecのメッセージがお互いに交換されますが、これはハンドシェイクメッセージの一部ではなく、Change Cipher Specプロトコルとして、1つだけChangeCipherSpecのメッセージというメッセージが定義されており、こちらが利用されています。そのため、ハンドシェイクの完全性検証の対象外です。

Application Dataプロトコルは、アプリケーションデータを運ぶために使用されます。これらのデータは、セキュリティのパラメータに基づいて、Recordプロトコルのレイヤーでパッケージ化、細分化、および暗号化されます。

Alertプロトコルは、もう一方の相手に例外的な状況を伝えるために使用します。エラーメッセージやclose_notifyという接続のシャットダウンに使用します。close_notifyが送られる理由としては、強制切断攻撃で、攻撃者が能動的に通信を横取りして以降のメッセージをブロックするという攻撃にさらされているのか、正常に通信が終了しているのかを明示化するためです。

RSAやDiffie-Hellmanを利用したTLSハンドシェイク

TLSハンドシェイクの方法はあくまで目的を実現するためのフレームワークのようなもので、具体的な方法は暗号化スイートを始めとするセキュリティパラメーターで決まります。

Keyless SSLの仕組み | Forward Secrecyの記事で取り上げられているRSA鍵交換やDH鍵交換によるTLSハンドシェイクの方法が参考になるでしょう。

セッション再開(Session Resumption)

TLSのハンドシェイクは負荷の大きい処理です。そのため、フルハンドシェイクを実行後は、マスターシークレットの値をキャッシュして再利用する方法があります。

  • セッションID

    • クライアントとサーバーの両方でセッションのセキュリティパラメータを保持しておきます。サーバーがセッションをキャッシュしておき、クライアントからClientHelloで対応するセッションIDが提示される場合、対応するセッション識別子を返します。

  • セッションチケット

    • サーバーは、すべてのセッションデータを収集し、暗号化してから、チケットの形式でクライアントに返します。それ以降の接続では、クライアントがサーバーにそのチケットを送信します。次に、サーバーがチケットの整合性をチェックして内容を復号化し、その情報を使用してセッションを再開します。

    • このように実現することで、サーバー側ではデータを保持しておく必要がありません。

    • TLS拡張機能の一つ

ただし、TLS 1.3では、ハンドシェイク完了後にサーバはクライアントに対して新しいセッションチケットを送るようにします。このクライアントに対するチケットは、以前のセッションIDのように鍵を探すデータベースとして利用することができます。このデータは、前の接続に対応し、自身で暗号化、認証された値とすることができます。つまり、サーバは状態を持つ必要がありません。

ELBについては、種類別に以下のものに対応しています。ALBとCLBは、複数のノードで構成されますが、ノードが変わる場合にはSession Resumptionの機能がりようできず、フルハンドシェイクが行われます。

  • NLB : セッションチケット (ロードバランサーレベル)

  • ALB : セッションチケット + セッションID (ノードレベル)

  • CLB : セッションID (ノードレベル)

ALBに対して、以下のように実行することで、セッションIDおよびセッションチケットに対応していることが分かります。

-no_ticketオプションを付与して、セッションチケットを利用しない場合、セッションチケットは利用していないことが確認できます。

再ネゴシエーション

再ネゴシエーションの挙動を確認するためには、以下のコマンドを実行後、Rを入力します。

NLB/ALBでは再ネゴシエーションが無効化されていますが、CLBでは有効化されています。そのため、無効化状態である必要がある場合には、NLB/ALBを利用する必要があります。

NLBの場合は、以下のような結果が返ってきます。

ALBの場合は、以下のとおりです。

CLBの場合は、以下のとおりです。

SSL証明書

SSL証明書とは

そもそもSSL証明書とは、例えば、以下の特徴が挙げられます。

  • あるエンティティ(ここでは、サーバーの運営者)が特定の公開鍵に対応する秘密鍵を保有していることを保証するためのもの

  • X.509 v3 デジタル証明書が主流のフォーマット

  • PEM 形式で扱われることが多い : バイナリ形式(DER)の証明書を Base64 エンコード+αしたもの

一つ目の特徴を実現するにあたって、PKIの仕組みを利用します。PKI(Public Key Infrastructure)とは、信頼できる第三者機関(認証局、CA)を介することで、不特定多数の相手と事前に個別の手続きを行うことなく相手の識別と認証を実現させる仕組みです。 TLSの文脈では、ユーザーがドメイン名を利用してWebサーバーにアクセスしているとき、そのWebサーバーが当該ドメイン名を管理しているエンティティにより提供されていることを認証して確かめる仕組みとなります。

ASN.1というデータ構造やオブジェクトの定義等の方法を定めたものでデータを表現し、DERの方法でエンコーディングを行い、Base64エンコーディングでASCII形式で表現したものがPEMです。

パブリックな証明書はパブリックな認証局によって運用されています。一方でプライベート証明書はプライベート認証局で管理します。

パブリック証明書による認証は、以下の2つの段階で構成されます。

  1. PKIの仕組みにより、証明書が信頼されたCAから発行されているか検証

  2. 検証が成功した証明書を使って、TLS ハンドシェイク中に Web サーバーを認証

すなわち、2つめの段階で、Web サーバーが証明書の所有者であることを確かめます。

認証局が予めルート証明書をブラウザベンダーやOSプロバイダーに発行しておきます。 そして、CAのルート証明書はブラウザのアプリケーションやOSの一部として配布されます。

Webサーバーの運営者は、証明書署名リクエストを認証局に行います。すると、認証局はWebサーバーに対して署名付きの証明書を渡します。

ここまでユーザーがWebサーバーにリクエストを送るまでに整っている必要があります。その後、ユーザーがWebサーバーに対してリクエストを送ると、TLSハンドシェイクの過程でWebサーバーはSSL証明書を渡します。その際、Webサーバー側は証明書に対応する秘密鍵で署名したデータもユーザーに送ります。ユーザーはその後、PKIによる証明書の検証後に、証明書の公開鍵で署名されたデータを検証することで認証が完了します。その後、TLSのセッションが確立します。

一言でまとめると、TLS通信を行う際にサーバー証明書とルート証明書、中間証明書は以下の箇所に保存されます。

  • ルート証明書: ローカルの信頼ストア

  • 中間証明書: Webサーバー(ロードバランサー、CDN 等)

  • サーバー証明書: Webサーバー(ロードバランサー、CDN 等)

なお、TLSネゴシエーションの際に、サーバー証明書と合わせて複数の中間証明書(証明書チェーン)が送られることもあります。このとき、TLS通信を行うクライアントでは証明書の検証にあたって複数の信頼パスを利用することが可能な状態になります。 このとき、検証でどの信頼パス、すなわち、どのルート証明書を選択するかは、Webブラウザーなどのクライアント側の実装に依存する動作になります。適切な信頼パスが選ばれない場合は、ルート証明書がインストールされているか等確認する必要があります。

証明書ストアの場所

ユーザーがWebアプリケーションにアクセスする際に参照されるルート証明書がどこに保存されているものを参照するかはブラウザ等のアプリケーションによります。

Webブラウザ

例えば、Firefoxでは独自の証明書ストアをブラウザ内に持っています。一方で、Chromeでは現状利用しているOSによって提供されている証明書ストアを利用します。ただし、ChromeもFirefoxに似た形で、iOS版を除いて独自のルート証明書プログラムへの移行を予定しているようです(参照: Chrome Root Program)。 ChromeやFirefoxで利用している証明書ストアはそれぞれ以下の方法で確認できます。

  • Chrome

    • Settings > Private and security > Securityをクリックすると、Manage certificatesを選択すると、Keychain Accessのアプリケーションが開きます。System Rootsを選択すると、MacOSにインストールされているルート証明書を確認できます。

  • Firefox

    • Settings > Private & Securityをクリックすると、Certificatesの項目でView Certificates...が選択できます。その後、Authotiesタブを選択すると、Firefoxにインストールされているルート証明書を確認できます。

OpenSSL

macOSでは/private/etc/ssl/cert.pem、Amazon Linux2では/etc/pki/tls/cert.pemに格納されます。

以下のようにOPENSSLDIRの値を参考にできます。

curl

内部的にはOpenSSLなどを利用しているので、それに応じて確認する必要があります。たとえば、以下のように確認できます。

プログラミング言語

Javaの場合は、/etc/pki/ca-trust/extracted/java/cacerts/etc/ssl/certs/java/cacertsなどが利用されます。例えば、ルート証明書の一覧は以下のように確認します。

ルート証明書をインポートする場合は以下のように実行します。

ルート証明書を削除する場合は以下のように実行します。

SSL証明書の中身

実際のSSL証明書は以下のようなファイルになります。

証明書ファイルの中身は、大きく証明書本体と署名アルゴリズムと署名データの3つに分けられます。

証明書ファイルの中身は、大きく証明書本体と署名アルゴリズムと署名データの3つに分けられます。

証明書本体には公開鍵をはじめとする主要な情報が含まれており、TLSで認証に使用します。署名データは本体を署名アルゴリズムに従って暗号学的に生成したデータです。検証には3つすべてのデータを使用します。

先程、PEM形式とは、ASN.1というデータ構造やオブジェクトの定義等の方法を定めたものでデータを表現し、DERの方法でエンコーディングを行い、Base64エンコーディングでASCII形式で表現したものであることを説明しました。実際に、ASN.1の形式でパースすると、以下のような内容が含まれていることが分かります。最初のSEQUENCEからはしばらく証明書本体の中身に相当するものが続き、最後のSEQUENCERからは証明書アルゴリズムが続きます。最後に、BIT STRINGで署名された値になります。

もっとわかりやすい形で確認していきましょう。以下のコマンドを実行することで確認できます。手元に証明書ファイルがある場合は、openssl x509 -in cert.pem -noout -textのように実行することで確認できます。

自己署名証明書の情報を確認します。ここでは、拡張情報は確認できないことが分かります。

最初にDataという証明書本体の中身があり、最後にSignature Algorithmで証明アルゴリズムとそれを利用したデジタル署名があることが確認できます。デジタル署名の部分にはData部を認証局の秘密鍵を使って計算したものが入ります。ただし時間の短縮のため、ダイジェスト方式が用いられます。 これにより、証明書のデジタル署名の部分には、上記のDataの部分を MD5などのハッシュ関数を用いてハッシュ値(メッセージダイジェスト)を得て、それを秘密鍵で暗号化したものがデジタル署名のところに入ります。

Data以降ではしばらく証明書本体の中身が続きます。項目をまとめると以下の内容になります。

  • 基本情報

    • バージョン : Version

    • シリアル番号 : Serial Number

    • 有効期限 : Validity

    • 署名方式 : Signature

    • 発行者 : Issuer

    • 所有者 : Subject

    • 公開鍵 : Subject Public Key Info

  • 拡張情報

    • 機関鍵識別子 : Authority Key Identifier

    • 所有者鍵識別子 : Subject Key Identifier

    • 鍵用途 : Key Usage

    • 拡張鍵用途 : Extended Key Usage

    • 所有者別名 : Subject Alternative Name

    • 失効リスト配布点 : CRL Distribution Points

    • 機関情報アクセス : Authority Information Access

検証

上記、証明書本体の中身のうち、検証の段階では以下のデータを使用します。

  • 基本情報

    • 発行者 : Issuer

    • 所有者 : Subject

    • 公開鍵 : Subject Public Key Info

  • 拡張情報

    • 機関鍵識別子 : Authority Key Identifier

    • 所有者鍵識別子 : Subject Key Identifier

発行者(Issuer)には証明書を発行した認証局の名前が入ります。発行機関と証明する内容などについては、C=JP, ST=Tokyo, L=Shinagawa, O=AWS, OU=SE, CN=alb.test.hayashier.com/emailAddress=xxxxxx@xxx.xxx ように書かれていますが、これはディレクトリシステムの仕様X.500に基づいた表現です。

所有者(Subject)には証明書の所有者の名前が入ります。ACMの場合はWebサーバーが使用するドメイン名が入ります。

公開鍵は、サーバー証明書の場合、Web サーバーが使う秘密鍵と対応する公開鍵が入ります。

上位の認証局の証明書とサーバー証明書の情報は関係性を持ちます。

上位の認証局の証明書の所有者(Subject)は、サーバー証明書の発行者(Issuer)と同じ値です。 上位の認証局の証明書の所有者鍵識別子(SKI)は、サーバー証明書の機関鍵識別子(AKI)と同じ値です。

上位の認証局の証明書およびサーバー証明書の所有者鍵識別子(SKI)は、上位の認証局の証明書の公開鍵に対する一意の識別子で、通常ハッシュ値が使用されます。

サーバー証明書の署名は、上位の認証局の証明書の秘密鍵とサーバー証明書から計算します。すなわち、検証する際は、上位の認証局の証明書の公開鍵とサーバー証明書で行います。

認証

認証の段階では、証明書本体の中身のうち、公開鍵(認証局の証明書の公開鍵のみ)もしくは所有者別名(SAN)を使用します。

  • 基本情報

    • 公開鍵 : Subject Public Key Info

  • 拡張情報

    • 所有者別名 : Subject Alternative Name

認証にはデジタル署名を活用します。アクセスしている相手が、サーバー証明書の公開鍵に対応する秘密鍵を持っていることで確かめます。

有効性

証明書の有効性の確認も行われます。その際、証明書本体の中身のうち、以下の情報を利用します。

  • 基本情報

    • 有効期限 : Validity

  • 拡張情報

    • 鍵用途 : Key Usage

    • 拡張鍵用途 : Extended Key Usage

    • 失効リスト配布点 : CRL Distribution Points

    • 機関情報アクセス : Authority Information Access

CRLとOCSPは証明書の失効状況確認に使用します。実際にこちらを活用して、失効状況の確認を行うかはクライアントに依存します。

CRLとは有効期限よりも前に失効させたデジタル証明書の一覧です。例えば、証明書の誤発行や証明書の秘密鍵紛失で悪用されるのを回避するために利用されます。デジタル証明書の受け取り側は、デジタル証明書とCRLを照合することで証明書が現在も有効であるかを確認できます。CRLは認証局から定期的に最新情報が配布されます。クライアントは、Webサイトなどから受信したサーバ証明書のシリアル番号とCRLに登録された証明書のシリアル番号を照合して有効性を確認できます。

OCSPはX.509公開鍵証明書の失効状態を取得するための通信プロトコルです。CRLの手法の代替手段として策定された実装です。OCSPクライアントがOCSPサーバ(OCSPレスポンダ)に対してデジタル証明書の有効性を確認します。

サーバー証明書の種類

  • DV証明書 : ドメイン認証

    • 認証局の人は対象ドメインを管理する権限があるかのみを確認

  • OV証明書 : 企業認証

    • ドメインの管理権に加え、運営組織の実在性などを電話などにより確認

  • EV証明書

    • OV証明書と同様の確認を行うが、確認方法が国際的な認定基準に基づいて行われる

証明書の検証の仕組み

サーバー証明書発行時

サーバー証明書を発行するにあたって、以下の流れで対応します。

  1. ルート認証局と中間認証局は、それぞれ自身の証明書に対応する秘密鍵と公開鍵を持っています。

  2. ユーザーは証明書作成のために、公開鍵と秘密鍵のペアを作成します。

  3. その鍵ペアを使って、CSR(署名要求) を作成します。作成したCSRで、電子証明書の発行依頼を中間認証局に行う

  4. 中間認証局はCSRの記載事項が正しいことを確認する。

  5. 中間認証局はCSRを使って電子証明書の発行を行う

ACMの場合、秘密鍵の生成、CSR生成、証明書の発行をマネージドに提供します。3つめの証明書の正しいことの確認は、DNS検証やEメール検証をします。

信頼チェーン(Chain of Trust)

検証するにあたっては、サーバー証明書からルート証明書までの証明書パスを探します。この信頼チェーンを通して、ルート証明書は既にローカルで信頼できるものとして認識しているので、サーバー証明書を確認することで、検証が可能になります。

サーバー証明書発行時に、以下の仕組みができています。この仕組みを利用して検証します。

  1. ルート認証局の秘密鍵を使って、自身のルート証明書に署名(自己署名)することでルート認証局が自身を正しいことを保証するものとする

  2. ルート認証局の秘密鍵を使って中間証明書に署名することで中間認証局が正しいことを保証

  3. 中間認証局の秘密鍵を使ってデジタル証明書に署名することでデジタル証明書に書かれたホスト名の機器は中間認証局が正しいことを保証

これによって、検証時は以下の流れで信頼チェーンを探すことができます。

  1. 中間認証局の公開鍵を使って、サーバー証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証

  2. ルート証明書の公開鍵を使って、中間証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証

  3. ルート証明書の公開鍵を使って、ルート証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証

証明書パスを見つけるにあたって以下の方法があります。

  • ローカルの信頼ストア

  • サーバーから送信される証明書チェーン

  • 証明書のAKI

中間証明書は、サーバー証明書をインストールする際に、サーバー証明書と中間証明書を一つのファイルとしてつなげることで、 中間証明書も一緒にインストールするのが一般的です。ルート証明書のように信頼ストアにインストールされていることも多いですが、そうではないこともよくあることが理由です。

そのため、上記理由でローカルの信頼ストアはあまり使われず、サーバーから送信される証明書チェーンが基本的に使われます。

キーペアの中身

RSAの場合におけるキーペアの確認を確認します。

公開鍵の場合は以下のような内容になります。

公開鍵の場合は以下のような内容になります。

ルート認証局と中間認証局が分かれている理由

信頼されたルート証明書は一度その秘密鍵が漏れてしまうと世界中のクライアントに影響が出てしまいます。その場合は速やかにそのルート証明書を失効し、新たな証明書を生成し、クライアントに配布する必要があります。

2階層だった場合、証明書を発行した上位認証局の証明書はルート証明書であるため、こちらを無効化することになりますが、それを実行した場合、発行した全ての証明書が無効になります。これでは影響範囲が大きいため、間に中間認証局を挟み、3階層にします。

ルート認証局はオフラインで構築しておき、別途構築した複数の中間認証局へ、それぞれ中間証明書を発行します。

自己証明書

ルート認証局が証明した証明書がある一方で、自己証明証明書とは所有者自身で署名した証明書になります。

前者がパブリック向けの使用に適しているのに対して、後者はクローズドな環境のみの利用に適しています。 前者であれば、信頼ストアにルート証明書を持っている、もしくはOSの信頼ストアを利用しているブラウザで基本的に信頼されていますが、後者では公開鍵を手動でインポートするまで信頼されません。 これに伴い、ルート認証局が署名した証明書では証明書の更新や修正はブラウザ側の変更は必要ありませんが、自己署名証明では更新や修正があるごとに新しい証明書をインポートし直す必要があります。

自己署名証明書は以下のように作成できます。

公開鍵を作成する場合は以下

ACMにインポートする場合は、以下の手順で実行します。

クロス証明書

ルート証明書から発行されたサーバ証明書を別のルート証明書が設定されているクライアントでも利用できるようにする仕組みです。

サーバー証明書と合わせて複数の中間証明書(証明書チェーン)が送信される場合もあります。これにより、TLS通信を行うクライアントでは証明書の検証にあたって複数の信頼パスを利用できます。このとき、検証でどの信頼パスもしくはルート証明書を選択するかは、Webブラウザーなどのクライアントに依存します。必要なルート証明書がインストールされていない場合や、不要な証明書チェーンが含まれている場合、提供されている証明書パスを利用するように証明書チェーンを再構築していない場合などに、意図しないルート証明書を選択することもあります。

例えば、新しい認証局を立ち上げる場合やルート証明書の移行、古くからあるルート証明書しか使えないクライアントに対して証明書を利用できるようにするといった場合に使用します。

ある証明書に対して、検証先の上位の証明書が分岐している場合、その証明書のIssuerと一致するSubjectおよびAKIと一致するSKIを持つ証明書が複数あります。すなわち、それらの証明書のSubjectやSKI(もしくは公開鍵)は同じ値を持ちます。Issuerは異なります。

Topics

トラブルシューティング

以上を踏まえて、TLSハンドシェイクに失敗する理由としては、例えば以下のようなものが挙げられます。TLS接続関連の問題のトラブルシューティングの際には参考になるかもしれません。

  • ネゴシエーションエラー

    • サーバー側の暗号スイートがクライアント側になく一致しない

      • サーバー側の暗号スイートのリストが新しく、クライアント側が保持しているリストが古い場合

    • プロトコルミスマッチ

  • 証明書の問題(サーバー証明書、クライアント証明書)

    • CN、ドメインの不一致

      • 親ドメインのワイルドカード指定は、親ドメインとは一致しない

    • 失効している

    • 有効でない

      • 自己証明証明書

      • CRL

      • OCSP

    • 信頼パス

      • ルート証明書がインストールされていない

      • 中間証明書が正しくない場合

    • 間違った証明書(そもそもアップロードができないこともある)

      • 秘密鍵

        • 暗号化(パスワードやパスフレーズで保護)された秘密鍵

        • フォーマットがおかしい

      • 公開鍵

        • 無効なフォーマット

          • X.509。PEMフォーマットでない

        • 証明書チェーンが無効

          • チェーンにユーザーの公開鍵が含まれてはいけない

          • 順序が間違っている

      • 証明書、秘密鍵、証明書チェーンがPEMエンコードされていない

      • 証明書チェーンにサーバー証明書自体が含まれている

      • チェーン内の中間証明書が正しい順序

        • チェーンの最初の証明書はサーバー証明書を発行したCAの証明書でないといけない

  • SNI対応

    • クライアントがSNI未対応(ALBの場合デフォルト証明書が選ばれる)

    • openssl s_client-servernameオプションの未指定

  • 相互認証

    • NLB/ALB/CLBでは未サポート

  • SMTPやPostgresなどのプロトコル

    • クライアントのClientHelloの前にいくつかのプロトコル変換が行われる

    • ELBはこれに対応していない

      • TCPリスナーを使用し、バックエンドインスタンス側で対応する必要がある

  • 環境問題

    • クライアントなどのネットワークの環境が貧弱

TLS通信の解読

TLS通信解読の方法は状況に応じていくつか方法があります。いずれの場合も第三者から通信を容易に読み取られるといった類のものではなく、デバッグなどの用途に使用するものです。

SSLKKEYLOGFILE変数を用いた方法

この方法はクライアント側で準備をしておくことにより、自身が行ったTLS通信の中身を確認するものです。このとき、SSL証明書の秘密鍵等は事前に準備する必要はありません。

以下のようにSSLKEYLOGFILE環境変数でログの出力先を指定したあとに、実際に解読対象の通信を行う。すると、変数に指定したログにデータが書き込まれる。

Wiresharkで、Preferences... > Protocols > TLS の画面を開き、(Pre)-Master-Secret log filenameで上記ファイルを指定。 TLS debug fileはデバッグログ出力するログのパス。うまくキャプチャできない場合に活用できる。

すると、TLSの通信も以下のように中身が見られるようになります。

次にtsharkにおける実行方法にも触れます。

tsharkをインストールするため、Macの場合は以下のようにWireshark付属の形でインストールします。

tsharkの場合は以下のように実行します。GUIで既に解読している場合は設定を解除しておいてください。GUIの方で設定していると特にキーログファイルを指定しなくても解読されます。

すると、以下のように通信が見られるようになります。

RSA秘密鍵を登録する方法

SSL証明書の秘密鍵等は事前に準備できる場合に、利用できる方法です。

この場合もいくつか方法がありますが、たとえば、以下の3つの方法で秘密鍵を登録することができます。

  • Wireshark > Preferences... > RSA Keys を選択後、Add new keyfile...

  • Wireshark > Preferences... > Protocols > TLSを選択後、RSA Keys list

  • 対象のTLS通信のパケットを右クリック > Protocol Preferences > Transport Layer Security > RSA keys list....

以下の記事で上記3つの方法のうち、最後の方法を利用した解説をしています。

Topics (In-Progress)

TLS拡張

SNI

複数の異なるサービスを一つのエントリーポイントでホスティングするような状況を仮想ホスティングと呼びます。 どの仮想ホストグループに対して、リクエストをルーティングするかを決める必要がある。

HTTP/1.1ではHostヘッダー、HTTP/2では:authorityヘッダー、TCP接続では、TLSのSNIを使用できます。

HTTPS接続が作成されるとき、クライアントはまず、どのサービスに到達しようとしているか、TLSハンドシェイクの一部であるClientHelloを使用して特定する。ここでTLS拡張のSNIを利用して、正しい証明書を提示し、正しいサービスにルーティングでます。

接続テスト

SNIが利用できない場合は、SANを利用したり、リスナーやロードバランサーを分ける等の対応が必要になります。

NPN

ALPN

TLS False Start

TLS 再ネゴシエーション

OCSPステープリング

セッションチケット

Certificate Transparency

Public Key Pinning

Last updated