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の利用が推進され始める
- SSL 1.0
- 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.0
以降は、基本的にTLS 1.2をベースとした内容で説明します。
- References
TLSハンドシェイク
TCPの3ウェイハンドシェイクによりTCPコネクションを確立後に、TLSハンドシェイクが行われます。
TLSハンドシェイクの流れは例えば、TLS 1.2でのフルハンドシェイクでは以下のような流れになります(引用元: RFC5246)。大きく実施している内容を分類すると、接続方法のネゴシエーション、認証およびマスターシークレットの共有、完全性検証の3つに分けられます。
接続方法のネゴシエーションが行われることについて言及しましたが、これはクライアントとサーバーがそれぞれ可能な処理内容を暗号スイートを通してやりとりします。
暗号スイートにはTLSの目的を実現する手段と、その手段を実現するにあたっての情報の交換方法が書かれています。 クライアント側は自身が対応している暗号スイートを優先度順にしてリストを送ります。通常は、サーバー側は自身で対応している暗号スイートの中で、クライアントから提示されたリストの上から選択します。Server Order Preference等の設定が行われている場合は、サーバー側のリストの上から選択します。 このようにネゴシエーションが行われて、どのようにTLS通信が行われるかが決まります。
すなわち、TLSハンドシェイクは様々な方法でも実現可能な仕組みのフレームワークのようなものです。
- References
暗号スイート
暗号スイートは例えば、以下のような文字列で表します。
ECDHE-ECDSA-AES128-SHA256
上記は大きく4つの要素からなり、それぞれ以下の内容を実現する方法を表しています。
- ECDHE : 鍵交換
- ECDSA : 認証
- AES128 : 暗号
- SHA256 : データ完全性
もう少し掘り下げると、それぞれ以下のとおりです。
- 鍵交換(Key Exchange)
- TLSハンドシェイク内で具体的にどういった方法で鍵交換を行うかの取り決め
- TLSハンドシェイクの説明を聞くと、このRSAの説明のみをイメージしてしまっている人も多いという印象
- 認証(Authentication)
- 認証はTLSの目的の一つ。大事な機能で忘れちゃだめ。
- 暗号(Cipher)
- 機密性はTLSの目的の一つ。これが一番みんながイメージが湧きやすいところか。
- データ完全性(Data Integrity)
- 完全性はTLSの目的の一つ。データが改ざんされていれば気付けるようにしておくために、ハッシュ関数を使用する
- message authentication algorithm のことを指していて、メッセージの認証に使用。OpenSSLだとMacという記載からも分かる
一般的な名称とOpenSSLでの名称
例えば、以下のようなフォーマットで先程説明したものとは異なる表記のものを見かけることもあるでしょう。
AES128-SHA256
OpenSSLで以下のようなコマンドを実行すると、利用可能な暗号スイートのリストが見られます。ここに含まれていることが確認できます。その横に詳細が書かれていますが、上記暗号スイートは、TLS 1.2で、鍵交換はRSA、認証はRSA、暗号化はAES 128bit、MACはSHA256で実行することを記載したものであることがわかります。
$ openssl ciphers -v
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
:
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
:
PSK-AES128-CBC-SHA256 TLSv1 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA256
PSK-AES128-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA1
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公開鍵を以下のように計算し、クライアントに送ります。
A = g^x mod p
クライアントも同様にDH公開鍵を以下のように計算し、サーバーに送ります。
B = g^y mod p
クライアントはサーバーから送られてきた公開鍵を最初にgの値に対して計算した方法と同様に、サーバーはクライアントから送られてきたDH公開鍵を最初にgの値に対して計算した方法と同様に計算します。すると、以下のように共通の値を取得することができ、このように共有鍵を生成します。
K = A^y mod p = B^x mod p (= (g^x)^y mod p = (g^y)^x mod p )
TLSでは古くはサーバー側でランダム生成されるものを使用していましたが、RFC 7919でグループパラメータとして定義されています。IPsecやSSHでも同様に事前に一覧表から利用する方法を取ります。
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パラメータとしてサーバー側で定義されたある楕円曲線を使用します。
- References
非対称暗号化と対象暗号化
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およびセッションチケットに対応していることが分かります。
$ openssl s_client -connect alb.test.hayashier.com:443 -reconnect
:
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Session-ID-ctx:
Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
TLS session ticket lifetime hint: 43200 (seconds)
TLS session ticket:
0000 - xx xx xx xx xx xx xx xx-xx xx xx xx xx xx xx xx ....x.x.x....,..
0010 - xx xx xx xx xx xx xx xx-xx xx xx xx xx xx xx xx ..y...y......,..
:
00a0 - xx xx xx xx xx xx xx xx-xx xx xx xx xx xx xx xx ....z.z.z....,..
-no_ticket
オプションを付与して、セッションチケットを利用しない場合、セッションチケットは利用していないことが確認できます。
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Session-ID-ctx:
Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Start Time: 1638592362
Timeout : 7200 (sec)
Verify return code: 0 (ok)
- References
再ネゴシエーション
-
再ネゴシエーションは、セッションを維持したまま暗号方式を変更するために利用します。
-
再ネゴシエーションは、既に確立しているセッションを使って、サーバからクライアントへのHelloRequestと呼ばれる要請のメッセージか、クライアントからの初期ネゴシエーションと同様のClientHelloのメッセージが送られることによって開始する。
-
今現在は一部の特殊なユースケース等を除き、多くのユースケースでは必要とすることはないでしょう。
-
Reference
再ネゴシエーションの挙動を確認するためには、以下のコマンドを実行後、R
を入力します。
$ openssl s_client -connect alb.test.hayashier.com:443
NLB/ALBでは再ネゴシエーションが無効化されていますが、CLBでは有効化されています。そのため、無効化状態である必要がある場合には、NLB/ALBを利用する必要があります。
NLBの場合は、以下のような結果が返ってきます。
RENEGOTIATING
write:errno=54
ALBの場合は、以下のとおりです。
RENEGOTIATING
4495674988:error:140040E5:SSL routines:CONNECT_CR_SRVR_HELLO:ssl handshake failure:/AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-47.140.1/libressl-2.8/ssl/ssl_pkt.c:585:
CLBの場合は、以下のとおりです。
RENEGOTIATING
depth=4 C = US, O = "Starfield Technologies, Inc.", OU = Starfield Class 2 Certification Authority
verify return:1
depth=3 C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
verify return:1
depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
verify return:1
depth=1 C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
verify return:1
depth=0 CN = *.test.hayashier.com
verify return:1
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つの段階で構成されます。
- PKIの仕組みにより、証明書が信頼されたCAから発行されているか検証
- 検証が成功した証明書を使って、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
の値を参考にできます。
$ openssl version -a
LibreSSL 2.8.3
built on: date not available
platform: information not available
options: bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: information not available
OPENSSLDIR: "/private/etc/ssl"
curl
内部的にはOpenSSLなどを利用しているので、それに応じて確認する必要があります。たとえば、以下のように確認できます。
$ curl --version
curl 7.79.1 (x86_64-koji-linux-gnu) libcurl/7.79.1 OpenSSL/1.0.2k-fips zlib/1.2.7 libidn2/2.3.0 libssh2/1.4.3 nghttp2/1.41.0 OpenLDAP/2.4.44
Release-Date: 2021-09-22
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB SPNEGO SSL UnixSockets
プログラミング言語
Javaの場合は、/etc/pki/ca-trust/extracted/java/cacerts
や/etc/ssl/certs/java/cacerts
などが利用されます。例えば、ルート証明書の一覧は以下のように確認します。
# keytool -v -list -keystore /etc/pki/ca-trust/extracted/java/cacerts
ルート証明書をインポートする場合は以下のように実行します。
# keytool -import -trustcacerts -alias YOUR_ALIAS -keystore /etc/pki/ca-trust/extracted/java/cacerts -file YOUR_CERTS_FILE
ルート証明書を削除する場合は以下のように実行します。
# keytool -delete -noprompt -alias YOUR_ALIAS -keystore /etc/pki/ca-trust/extracted/java/cacerts -storepass YOUR_PASSWORD
- References
SSL証明書の中身
実際のSSL証明書は以下のようなファイルになります。
-----BEGIN CERTIFICATE-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END CERTIFICATE-----
証明書ファイルの中身は、大きく証明書本体と署名アルゴリズムと署名データの3つに分けられます。
証明書ファイルの中身は、大きく証明書本体と署名アルゴリズムと署名データの3つに分けられます。
証明書本体には公開鍵をはじめとする主要な情報が含まれており、TLSで認証に使用します。署名データは本体を署名アルゴリズムに従って暗号学的に生成したデータです。検証には3つすべてのデータを使用します。
先程、PEM形式とは、ASN.1というデータ構造やオブジェクトの定義等の方法を定めたものでデータを表現し、DERの方法でエンコーディングを行い、Base64エンコーディングでASCII形式で表現したものであることを説明しました。実際に、ASN.1の形式でパースすると、以下のような内容が含まれていることが分かります。最初のSEQUENCEからはしばらく証明書本体の中身に相当するものが続き、最後のSEQUENCERからは証明書アルゴリズムが続きます。最後に、BIT STRINGで署名された値になります。
$ openssl asn1parse -i -in cert.pem
0:d=0 hl=4 l= 932 cons: SEQUENCE
4:d=1 hl=4 l= 652 cons: SEQUENCE
8:d=2 hl=2 l= 9 prim: INTEGER :CA2E336678056462
19:d=2 hl=2 l= 13 cons: SEQUENCE
21:d=3 hl=2 l= 9 prim: OBJECT :sha512WithRSAEncryption
32:d=3 hl=2 l= 0 prim: NULL
34:d=2 hl=3 l= 147 cons: SEQUENCE
37:d=3 hl=2 l= 11 cons: SET
39:d=4 hl=2 l= 9 cons: SEQUENCE
41:d=5 hl=2 l= 3 prim: OBJECT :countryName
46:d=5 hl=2 l= 2 prim: PRINTABLESTRING :JP
50:d=3 hl=2 l= 14 cons: SET
52:d=4 hl=2 l= 12 cons: SEQUENCE
54:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
59:d=5 hl=2 l= 5 prim: UTF8STRING :Tokyo
66:d=3 hl=2 l= 18 cons: SET
68:d=4 hl=2 l= 16 cons: SEQUENCE
70:d=5 hl=2 l= 3 prim: OBJECT :localityName
75:d=5 hl=2 l= 9 prim: UTF8STRING :Shinagawa
86:d=3 hl=2 l= 12 cons: SET
88:d=4 hl=2 l= 10 cons: SEQUENCE
90:d=5 hl=2 l= 3 prim: OBJECT :organizationName
95:d=5 hl=2 l= 3 prim: UTF8STRING :AWS
100:d=3 hl=2 l= 11 cons: SET
102:d=4 hl=2 l= 9 cons: SEQUENCE
104:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
109:d=5 hl=2 l= 2 prim: UTF8STRING :SE
113:d=3 hl=2 l= 31 cons: SET
115:d=4 hl=2 l= 29 cons: SEQUENCE
117:d=5 hl=2 l= 3 prim: OBJECT :commonName
122:d=5 hl=2 l= 22 prim: UTF8STRING :alb.test.hayashier.com
146:d=3 hl=2 l= 36 cons: SET
148:d=4 hl=2 l= 34 cons: SEQUENCE
150:d=5 hl=2 l= 9 prim: OBJECT :emailAddress
161:d=5 hl=2 l= 21 prim: IA5STRING :xxxxxx@xxx.xxx
184:d=2 hl=2 l= 30 cons: SEQUENCE
186:d=3 hl=2 l= 13 prim: UTCTIME :211015152029Z
201:d=3 hl=2 l= 13 prim: UTCTIME :211016152029Z
216:d=2 hl=3 l= 147 cons: SEQUENCE
219:d=3 hl=2 l= 11 cons: SET
221:d=4 hl=2 l= 9 cons: SEQUENCE
223:d=5 hl=2 l= 3 prim: OBJECT :countryName
228:d=5 hl=2 l= 2 prim: PRINTABLESTRING :JP
232:d=3 hl=2 l= 14 cons: SET
234:d=4 hl=2 l= 12 cons: SEQUENCE
236:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
241:d=5 hl=2 l= 5 prim: UTF8STRING :Tokyo
248:d=3 hl=2 l= 18 cons: SET
250:d=4 hl=2 l= 16 cons: SEQUENCE
252:d=5 hl=2 l= 3 prim: OBJECT :localityName
257:d=5 hl=2 l= 9 prim: UTF8STRING :Shinagawa
268:d=3 hl=2 l= 12 cons: SET
270:d=4 hl=2 l= 10 cons: SEQUENCE
272:d=5 hl=2 l= 3 prim: OBJECT :organizationName
277:d=5 hl=2 l= 3 prim: UTF8STRING :AWS
282:d=3 hl=2 l= 11 cons: SET
284:d=4 hl=2 l= 9 cons: SEQUENCE
286:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
291:d=5 hl=2 l= 2 prim: UTF8STRING :SE
295:d=3 hl=2 l= 31 cons: SET
297:d=4 hl=2 l= 29 cons: SEQUENCE
299:d=5 hl=2 l= 3 prim: OBJECT :commonName
304:d=5 hl=2 l= 22 prim: UTF8STRING :alb.test.hayashier.com
328:d=3 hl=2 l= 36 cons: SET
330:d=4 hl=2 l= 34 cons: SEQUENCE
332:d=5 hl=2 l= 9 prim: OBJECT :emailAddress
343:d=5 hl=2 l= 21 prim: IA5STRING :xxxxxx@xxx.xxx
366:d=2 hl=4 l= 290 cons: SEQUENCE
370:d=3 hl=2 l= 13 cons: SEQUENCE
372:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
383:d=4 hl=2 l= 0 prim: NULL
385:d=3 hl=4 l= 271 prim: BIT STRING
660:d=1 hl=2 l= 13 cons: SEQUENCE
662:d=2 hl=2 l= 9 prim: OBJECT :sha512WithRSAEncryption
673:d=2 hl=2 l= 0 prim: NULL
675:d=1 hl=4 l= 257 prim: BIT STRING
もっとわかりやすい形で確認していきましょう。以下のコマンドを実行することで確認できます。手元に証明書ファイルがある場合は、openssl x509 -in cert.pem -noout -text
のように実行することで確認できます。
$ openssl s_client -connect alb.test.hayashier.com:443 < /dev/null 2> /dev/null | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0b:cc:80:45:cd:fc:74:45:ad:b3:40:28:a8:cb:ac:5c
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Amazon, OU=Server CA 1B, CN=Amazon
Validity
Not Before: Dec 1 00:00:00 2021 GMT
Not After : Dec 29 23:59:59 2022 GMT
Subject: CN=*.test.hayashier.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:dd:db:5d:e0:d4:93:aa:f9:08:74:12:15:11:27:
af:7c:ee:2a:43:f7:a2:2c:5e:93:2e:50:c4:7b:3f:
2e:70:f8:6a:a3:9d:75:e6:ea:93:30:ec:24:8b:63:
d7:03:51:3e:17:80:61:ce:ed:51:2a:a8:29:b8:9f:
3c:c0:97:8a:b7:10:53:1d:18:dd:42:62:3e:b0:16:
0a:9f:6e:ba:a2:2d:f9:6f:12:16:e3:3e:72:f8:36:
5b:95:c4:01:a7:65:7f:64:d4:66:4c:e7:df:fd:11:
cd:fe:53:3c:59:41:3f:8d:a2:0c:9a:d6:86:08:4b:
18:86:52:01:82:22:75:a1:0b:11:8b:3c:11:33:41:
ef:50:f6:01:06:84:c7:79:8a:f6:24:91:67:f5:06:
03:6d:78:fc:e3:5f:a9:39:f1:ef:8b:f8:cb:fe:f1:
71:5f:3d:be:b3:93:bd:ce:d3:07:a6:24:7c:82:07:
5b:22:03:40:3a:cf:1a:da:b2:46:3f:e6:2a:59:4d:
ff:df:b8:a5:77:dc:ff:ca:b7:4a:9f:6d:d8:9a:a6:
c0:79:73:89:6e:70:54:1b:69:39:04:fd:59:c8:06:
87:40:23:0c:c9:36:ef:38:ae:d5:86:3a:e8:3b:28:
18:66:c8:c3:bc:55:cc:20:a6:54:12:b1:16:b2:15:
91:ab
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:59:A4:66:06:52:A0:7B:95:92:3C:A3:94:07:27:96:74:5B:F9:3D:D0
X509v3 Subject Key Identifier:
96:04:82:AB:B4:83:C8:97:65:4F:48:9E:F1:29:3A:0C:5B:64:87:4C
X509v3 Subject Alternative Name:
DNS:*.test.hayashier.com, DNS:test.hayashier.com
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.sca1b.amazontrust.com/sca1b-1.crl
X509v3 Certificate Policies:
Policy: 2.23.140.1.2.1
Authority Information Access:
OCSP - URI:http://ocsp.sca1b.amazontrust.com
CA Issuers - URI:http://crt.sca1b.amazontrust.com/sca1b.crt
X509v3 Basic Constraints: critical
CA:FALSE
1.3.6.1.4.1.11129.2.4.2:
...j.h.v.)y...99!.Vs.c.w..W}.`
........}sX.......G0E. '...&..!Ig'.......7."x..m...OU...!....c...3u.....*.x;......6...W..x.v.A...."FJ...:.B.^N1.....K.h..b......}sX.c.........I*.3.Q..&..!.....-.G"...;.#h@PDi..*.....?K..G
Signature Algorithm: sha256WithRSAEncryption
6a:b0:93:0b:79:c2:60:90:8f:a5:6e:0f:de:e0:66:63:32:6e:
42:b9:69:6a:80:43:27:1c:d4:b5:59:81:40:c1:c8:9e:7a:4a:
62:e8:47:4b:7c:df:f7:a0:a9:5a:02:a8:d4:61:79:00:4a:7c:
31:da:17:94:be:b9:d3:67:e2:56:84:17:6d:5c:ae:a3:8a:91:
ba:b8:26:ae:0c:f3:c2:f2:84:fe:0e:87:a9:8f:be:db:34:62:
02:3f:1b:3c:55:ec:7d:d9:ea:ef:53:ae:8d:74:50:d2:99:4b:
85:12:fa:08:61:01:51:6a:43:bf:01:40:4c:25:08:9a:20:55:
1d:54:d1:4d:6a:c8:e1:a7:f0:d9:6e:88:d3:11:01:29:af:39:
0c:d7:64:71:38:e8:ff:99:b8:8b:98:d5:3f:d4:4f:15:32:85:
25:9b:6d:16:c2:a2:b4:f5:92:42:06:68:c0:11:0c:38:6b:85:
e5:aa:52:9e:e2:f2:4a:3c:79:87:34:88:27:f6:1e:9d:52:41:
d1:11:b2:90:f6:ca:1a:76:6b:2f:46:d3:8c:71:66:76:30:cd:
b2:a3:2a:57:e4:03:cc:fb:27:7d:e7:0d:16:c7:f5:ef:9d:33:
94:00:f2:99:f2:7b:26:a4:9a:a6:30:55:2d:3f:ec:cb:08:d9:
26:1d:6b:63
自己署名証明書の情報を確認します。ここでは、拡張情報は確認できないことが分かります。
$ openssl s_client -connect alb.test.hayashier.com:443 < /dev/null 2> /dev/null | openssl x509 -noout -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 17654627072782306786 (0xf501d5c8d32f0de2)
Signature Algorithm: sha512WithRSAEncryption
Issuer: C=JP, ST=Tokyo, L=Shinagawa, O=AWS, OU=SE, CN=alb.test.hayashier.com/emailAddress=xxxxxx@xxx.xxx
Validity
Not Before: Oct 15 16:38:49 2021 GMT
Not After : Oct 16 16:38:49 2021 GMT
Subject: C=JP, ST=Tokyo, L=Shinagawa, O=AWS, OU=SE, CN=alb.test.hayashier.com/emailAddress=xxxxxx@xxx.xxx
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c7:7f:97:df:b0:dd:a8:0d:db:b0:47:c1:7e:5c:
97:95:5b:7f:4b:88:0b:af:2d:5a:0a:5e:8f:87:cd:
29:39:18:90:f7:7a:26:c0:23:f0:1a:12:a5:e9:d9:
20:56:62:d2:c7:02:38:65:33:6f:ed:73:1a:2e:cc:
04:51:e3:27:aa:bb:e5:e0:59:8e:ea:e6:3b:fe:6b:
8d:07:c3:8d:7a:ab:5e:2e:2f:ea:52:3a:a8:09:3c:
3d:95:6c:36:f9:c0:cc:8c:25:16:65:d2:3d:79:03:
34:12:22:bb:2f:4d:e5:81:a4:0e:0d:9b:47:ea:f4:
b9:e2:65:a6:d6:a7:38:d0:26:da:4f:b9:ea:f8:9f:
9c:96:92:70:ba:f1:9a:c5:ce:61:60:1c:a1:c2:27:
9a:91:ac:48:21:39:4f:b1:17:ac:a0:3b:75:27:c8:
39:7a:03:cf:89:70:d9:4d:e6:1a:6a:7c:c4:db:07:
82:ea:aa:b2:cb:4c:3a:c2:b0:01:fe:e3:20:8c:c5:
13:b6:70:a4:4d:5c:b3:8e:75:bc:66:aa:af:e3:a9:
35:50:9f:ca:e7:f8:a7:35:fc:b9:ff:44:16:9f:23:
4f:d1:2f:d2:ad:83:86:39:c0:0e:1c:6b:83:cc:e1:
ef:ec:74:a3:e0:e3:e2:5b:76:f5:ca:b7:73:df:ac:
de:45
Exponent: 65537 (0x10001)
Signature Algorithm: sha512WithRSAEncryption
65:08:dc:fd:2d:8f:df:92:bf:49:07:ec:9b:8a:71:0b:78:e0:
e2:36:6d:80:33:e1:fe:6d:ef:2b:44:5c:8f:c6:cb:7e:16:8d:
ff:ca:5c:68:ec:af:85:f9:a4:42:4a:1a:11:d4:0d:4f:04:0c:
fd:d9:13:fa:39:e7:94:a8:c0:d2:6a:7a:1c:4a:1d:16:e7:c8:
99:39:59:5e:8c:80:7a:59:71:56:23:14:08:fd:33:d6:2d:bf:
0e:4f:64:53:e8:12:7e:93:f1:f1:7f:03:9c:ee:bf:be:e7:b0:
53:38:d6:ec:6a:a8:a7:b0:90:b0:95:30:6a:7b:05:ff:f1:e0:
4d:e7:5a:40:d9:1d:e7:d8:45:03:4c:cb:3b:bf:90:58:58:51:
7b:d1:28:be:60:dc:62:c5:15:f4:8f:ad:06:34:3f:d2:df:19:
af:8d:92:34:e2:6c:ca:8e:63:ca:32:82:c9:6f:8f:68:72:18:
11:af:16:f8:00:90:e7:d8:fe:25:88:14:75:1b:a1:96:74:29:
3d:57:bd:7a:e9:7c:fd:6c:68:f3:a8:e8:b2:83:34:b9:d6:2b:
02:e7:5c:45:90:f3:98:01:4f:f5:e3:86:83:b8:18:38:d5:b8:
0e:27:89:c8:f0:22:ea:a3:71:8b:ae:29:83:6b:95:86:03:96:
d3:a2:51:58
最初に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
-
References
検証
上記、証明書本体の中身のうち、検証の段階では以下のデータを使用します。
- 基本情報
- 発行者 : 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証明書と同様の確認を行うが、確認方法が国際的な認定基準に基づいて行われる
-
References
証明書の検証の仕組み
サーバー証明書発行時
サーバー証明書を発行するにあたって、以下の流れで対応します。
- ルート認証局と中間認証局は、それぞれ自身の証明書に対応する秘密鍵と公開鍵を持っています。
- ユーザーは証明書作成のために、公開鍵と秘密鍵のペアを作成します。
- その鍵ペアを使って、CSR(署名要求) を作成します。作成したCSRで、電子証明書の発行依頼を中間認証局に行う
- 中間認証局はCSRの記載事項が正しいことを確認する。
- 中間認証局はCSRを使って電子証明書の発行を行う
ACMの場合、秘密鍵の生成、CSR生成、証明書の発行をマネージドに提供します。3つめの証明書の正しいことの確認は、DNS検証やEメール検証をします。
信頼チェーン(Chain of Trust)
検証するにあたっては、サーバー証明書からルート証明書までの証明書パスを探します。この信頼チェーンを通して、ルート証明書は既にローカルで信頼できるものとして認識しているので、サーバー証明書を確認することで、検証が可能になります。
サーバー証明書発行時に、以下の仕組みができています。この仕組みを利用して検証します。
- ルート認証局の秘密鍵を使って、自身のルート証明書に署名(自己署名)することでルート認証局が自身を正しいことを保証するものとする
- ルート認証局の秘密鍵を使って中間証明書に署名することで中間認証局が正しいことを保証
- 中間認証局の秘密鍵を使ってデジタル証明書に署名することでデジタル証明書に書かれたホスト名の機器は中間認証局が正しいことを保証
これによって、検証時は以下の流れで信頼チェーンを探すことができます。
- 中間認証局の公開鍵を使って、サーバー証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証
- ルート証明書の公開鍵を使って、中間証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証
- ルート証明書の公開鍵を使って、ルート証明書の電子署名を復号し、実際のデジタル証明書のハッシュ値を計算したものと比較し、正当性を確認することで検証
証明書パスを見つけるにあたって以下の方法があります。
- ローカルの信頼ストア
- サーバーから送信される証明書チェーン
- 証明書のAKI
中間証明書は、サーバー証明書をインストールする際に、サーバー証明書と中間証明書を一つのファイルとしてつなげることで、 中間証明書も一緒にインストールするのが一般的です。ルート証明書のように信頼ストアにインストールされていることも多いですが、そうではないこともよくあることが理由です。
そのため、上記理由でローカルの信頼ストアはあまり使われず、サーバーから送信される証明書チェーンが基本的に使われます。
キーペアの中身
RSAの場合におけるキーペアの確認を確認します。
公開鍵の場合は以下のような内容になります。
$ openssl rsa -in public.pem -text -noout -pubin
Public-Key: (2048 bit)
Modulus:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
Exponent: 65537 (0x10001)
公開鍵の場合は以下のような内容になります。
$ openssl rsa -in private.pem -text -noout
Private-Key: (2048 bit)
modulus:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
publicExponent: 65537 (0x10001)
privateExponent:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
prime1:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
prime2:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
exponent1:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
exponent2:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
coefficient:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
ルート認証局と中間認証局が分かれている理由
信頼されたルート証明書は一度その秘密鍵が漏れてしまうと世界中のクライアントに影響が出てしまいます。その場合は速やかにそのルート証明書を失効し、新たな証明書を生成し、クライアントに配布する必要があります。
2階層だった場合、証明書を発行した上位認証局の証明書はルート証明書であるため、こちらを無効化することになりますが、それを実行した場合、発行した全ての証明書が無効になります。これでは影響範囲が大きいため、間に中間認証局を挟み、3階層にします。
ルート認証局はオフラインで構築しておき、別途構築した複数の中間認証局へ、それぞれ中間証明書を発行します。
自己証明書
ルート認証局が証明した証明書がある一方で、自己証明証明書とは所有者自身で署名した証明書になります。
前者がパブリック向けの使用に適しているのに対して、後者はクローズドな環境のみの利用に適しています。 前者であれば、信頼ストアにルート証明書を持っている、もしくはOSの信頼ストアを利用しているブラウザで基本的に信頼されていますが、後者では公開鍵を手動でインポートするまで信頼されません。 これに伴い、ルート認証局が署名した証明書では証明書の更新や修正はブラウザ側の変更は必要ありませんが、自己署名証明では更新や修正があるごとに新しい証明書をインポートし直す必要があります。
自己署名証明書は以下のように作成できます。
$ openssl genrsa 2048 > private.pem
$ openssl req -new -x509 -key private.pem -sha512 -days 1 -out cert.pem
公開鍵を作成する場合は以下
$ openssl rsa -pubout < private.pem > public.pem
ACMにインポートする場合は、以下の手順で実行します。
$ aws acm import-certificate --certificate file://cert.pem --private-key file://private.pem
$ aws acm describe-certificate --certificate-arn arn:aws:acm:ap-northeast-1:...
- Reference
クロス証明書
ルート証明書から発行されたサーバ証明書を別のルート証明書が設定されているクライアントでも利用できるようにする仕組みです。
サーバー証明書と合わせて複数の中間証明書(証明書チェーン)が送信される場合もあります。これにより、TLS通信を行うクライアントでは証明書の検証にあたって複数の信頼パスを利用できます。このとき、検証でどの信頼パスもしくはルート証明書を選択するかは、Webブラウザーなどのクライアントに依存します。必要なルート証明書がインストールされていない場合や、不要な証明書チェーンが含まれている場合、提供されている証明書パスを利用するように証明書チェーンを再構築していない場合などに、意図しないルート証明書を選択することもあります。
例えば、新しい認証局を立ち上げる場合やルート証明書の移行、古くからあるルート証明書しか使えないクライアントに対して証明書を利用できるようにするといった場合に使用します。
ある証明書に対して、検証先の上位の証明書が分岐している場合、その証明書のIssuerと一致するSubjectおよびAKIと一致するSKIを持つ証明書が複数あります。すなわち、それらの証明書のSubjectやSKI(もしくは公開鍵)は同じ値を持ちます。Issuerは異なります。
Topics
トラブルシューティング
以上を踏まえて、TLSハンドシェイクに失敗する理由としては、例えば以下のようなものが挙げられます。TLS接続関連の問題のトラブルシューティングの際には参考になるかもしれません。
- ネゴシエーションエラー
- サーバー側の暗号スイートがクライアント側になく一致しない
- サーバー側の暗号スイートのリストが新しく、クライアント側が保持しているリストが古い場合
- プロトコルミスマッチ
- サーバー側の暗号スイートがクライアント側になく一致しない
- 証明書の問題(サーバー証明書、クライアント証明書)
- CN、ドメインの不一致
- 親ドメインのワイルドカード指定は、親ドメインとは一致しない
- 失効している
- 有効でない
- 自己証明証明書
- CRL
- OCSP
- 信頼パス
- ルート証明書がインストールされていない
- 中間証明書が正しくない場合
- 間違った証明書(そもそもアップロードができないこともある)
- 秘密鍵
- 暗号化(パスワードやパスフレーズで保護)された秘密鍵
- フォーマットがおかしい
- 公開鍵
- 無効なフォーマット
- X.509。PEMフォーマットでない
- 証明書チェーンが無効
- チェーンにユーザーの公開鍵が含まれてはいけない
- 順序が間違っている
- 無効なフォーマット
- 証明書、秘密鍵、証明書チェーンがPEMエンコードされていない
- 証明書チェーンにサーバー証明書自体が含まれている
- チェーン内の中間証明書が正しい順序
- チェーンの最初の証明書はサーバー証明書を発行したCAの証明書でないといけない
- 秘密鍵
- CN、ドメインの不一致
- SNI対応
- クライアントがSNI未対応(ALBの場合デフォルト証明書が選ばれる)
openssl s_client
の-servername
オプションの未指定
- 相互認証
- NLB/ALB/CLBでは未サポート
- SMTPやPostgresなどのプロトコル
- クライアントのClientHelloの前にいくつかのプロトコル変換が行われる
- ELBはこれに対応していない
- TCPリスナーを使用し、バックエンドインスタンス側で対応する必要がある
- 環境問題
- クライアントなどのネットワークの環境が貧弱
TLS通信の解読
TLS通信解読の方法は状況に応じていくつか方法があります。いずれの場合も第三者から通信を容易に読み取られるといった類のものではなく、デバッグなどの用途に使用するものです。
SSLKKEYLOGFILE変数を用いた方法
この方法はクライアント側で準備をしておくことにより、自身が行ったTLS通信の中身を確認するものです。このとき、SSL証明書の秘密鍵等は事前に準備する必要はありません。
以下のようにSSLKEYLOGFILE
環境変数でログの出力先を指定したあとに、実際に解読対象の通信を行う。すると、変数に指定したログにデータが書き込まれる。
$ export SSLKEYLOGFILE=/home/ubuntu/sslkeylog.log
# ここでたとえば下記のように対象の通信を行う。
# $ curl https://hayashier.com
$ cat sslkeylog.log
CLIENT_RANDOM xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Wiresharkで、Preferences... > Protocols > TLS の画面を開き、(Pre)-Master-Secret log filename
で上記ファイルを指定。
TLS debug file
はデバッグログ出力するログのパス。うまくキャプチャできない場合に活用できる。
すると、TLSの通信も以下のように中身が見られるようになります。
1 2021-10-15 16:47:23.601334 172.31.5.148 44.237.150.182 TCP 74 35686 → 443 [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=3293266384 TSecr=0 WS=128
2 2021-10-15 16:47:23.601709 44.237.150.182 172.31.5.148 TCP 74 443 → 35686 [SYN, ACK] Seq=0 Ack=1 Win=26847 Len=0 MSS=1460 SACK_PERM=1 TSval=2439383746 TSecr=3293266384 WS=256
3 2021-10-15 16:47:23.601722 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=3293266384 TSecr=2439383746
4 2021-10-15 16:47:23.608216 172.31.5.148 44.237.150.182 TLSv1.2 583 Client Hello
5 2021-10-15 16:47:23.608509 44.237.150.182 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=1 Ack=518 Win=28160 Len=0 TSval=2439383753 TSecr=3293266391
6 2021-10-15 16:47:23.613762 44.237.150.182 172.31.5.148 TLSv1.2 2406 Server Hello, Certificate, Server Key Exchange, Server Hello Done
7 2021-10-15 16:47:23.613777 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=518 Ack=2341 Win=60544 Len=0 TSval=3293266397 TSecr=2439383758
8 2021-10-15 16:47:23.614293 172.31.5.148 44.237.150.182 TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Finished
9 2021-10-15 16:47:23.615913 44.237.150.182 172.31.5.148 TLSv1.2 117 Change Cipher Spec, Finished
10 2021-10-15 16:47:23.615921 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=644 Ack=2392 Win=60544 Len=0 TSval=3293266399 TSecr=2439383760
11 2021-10-15 16:47:23.615974 44.237.150.182 172.31.5.148 HTTP2 135 SETTINGS[0], WINDOW_UPDATE[0]
12 2021-10-15 16:47:23.615976 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=644 Ack=2461 Win=60544 Len=0 TSval=3293266399 TSecr=2439383760
13 2021-10-15 16:47:23.616043 172.31.5.148 44.237.150.182 HTTP2 119 Magic
14 2021-10-15 16:47:23.616049 172.31.5.148 44.237.150.182 HTTP2 122 SETTINGS[0]
15 2021-10-15 16:47:23.616063 172.31.5.148 44.237.150.182 HTTP2 108 WINDOW_UPDATE[0]
16 2021-10-15 16:47:23.616091 172.31.5.148 44.237.150.182 HTTP2 140 HEADERS[1]: GET /
17 2021-10-15 16:47:23.616111 172.31.5.148 44.237.150.182 HTTP2 104 SETTINGS[0]
18 2021-10-15 16:47:23.616529 44.237.150.182 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=2461 Ack=907 Win=28160 Len=0 TSval=2439383761 TSecr=3293266399
19 2021-10-15 16:47:23.616696 44.237.150.182 172.31.5.148 HTTP2 104 SETTINGS[0]
20 2021-10-15 16:47:23.616698 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=2499 Win=60544 Len=0 TSval=3293266399 TSecr=2439383761
21 2021-10-15 16:47:23.649782 44.237.150.182 172.31.5.148 HTTP2 808 HEADERS[1]: 200 OK, DATA[1]
22 2021-10-15 16:47:23.649783 44.237.150.182 172.31.5.148 HTTP2 104 DATA[1] (text/html)
23 2021-10-15 16:47:23.649811 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=3241 Win=59904 Len=0 TSval=3293266433 TSecr=2439383793
24 2021-10-15 16:47:23.649816 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=3279 Win=59904 Len=0 TSval=3293266433 TSecr=2439383793
25 2021-10-15 16:47:23.650796 172.31.5.148 44.237.150.182 TLSv1.2 97 Alert (Level: Warning, Description: Close Notify)
26 2021-10-15 16:47:23.651117 44.237.150.182 172.31.5.148 TCP 66 443 → 35686 [FIN, ACK] Seq=3279 Ack=938 Win=28160 Len=0 TSval=2439383795 TSecr=3293266434
27 2021-10-15 16:47:23.651408 172.31.5.148 44.237.150.182 TCP 66 35686 → 443 [FIN, ACK] Seq=938 Ack=3280 Win=59904 Len=0 TSval=3293266434 TSecr=2439383795
28 2021-10-15 16:47:23.651658 44.237.150.182 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=3280 Ack=939 Win=28160 Len=0 TSval=2439383796 TSecr=3293266434
次にtsharkにおける実行方法にも触れます。
tsharkをインストールするため、Macの場合は以下のようにWireshark付属の形でインストールします。
$ brew install --cask wireshark
tsharkの場合は以下のように実行します。GUIで既に解読している場合は設定を解除しておいてください。GUIの方で設定していると特にキーログファイルを指定しなくても解読されます。
$ tshark \
-r ./ssldecrypt.pcap \
-o "tls.keylog_file:./sslkeylog.log" \
-o "tls.debug_file:./tlsdebug.log"
すると、以下のように通信が見られるようになります。
1 0.000000 172.31.5.148 → 44.237.150.182 TCP 74 35686 → 443 [SYN] Seq=0 Win=62727 Len=0 MSS=8961 SACK_PERM=1 TSval=3293266384 TSecr=0 WS=128
2 0.000375 44.237.150.182 → 172.31.5.148 TCP 74 443 → 35686 [SYN, ACK] Seq=0 Ack=1 Win=26847 Len=0 MSS=1460 SACK_PERM=1 TSval=2439383746 TSecr=3293266384 WS=256
3 0.000388 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=1 Ack=1 Win=62848 Len=0 TSval=3293266384 TSecr=2439383746
4 0.006882 172.31.5.148 → 44.237.150.182 TLSv1 583 Client Hello
5 0.007175 44.237.150.182 → 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=1 Ack=518 Win=28160 Len=0 TSval=2439383753 TSecr=3293266391
6 0.012428 44.237.150.182 → 172.31.5.148 TLSv1.2 2406 Server Hello, Certificate, Server Key Exchange, Server Hello Done
7 0.012443 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=518 Ack=2341 Win=60544 Len=0 TSval=3293266397 TSecr=2439383758
8 0.012959 172.31.5.148 → 44.237.150.182 TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Finished
9 0.014579 44.237.150.182 → 172.31.5.148 TLSv1.2 117 Change Cipher Spec, Finished
10 0.014587 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=644 Ack=2392 Win=60544 Len=0 TSval=3293266399 TSecr=2439383760
11 0.014640 44.237.150.182 → 172.31.5.148 HTTP2 135 SETTINGS[0], WINDOW_UPDATE[0]
12 0.014642 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=644 Ack=2461 Win=60544 Len=0 TSval=3293266399 TSecr=2439383760
13 0.014709 172.31.5.148 → 44.237.150.182 HTTP2 119 Magic
14 0.014715 172.31.5.148 → 44.237.150.182 HTTP2 122 SETTINGS[0]
15 0.014729 172.31.5.148 → 44.237.150.182 HTTP2 108 WINDOW_UPDATE[0]
16 0.014757 172.31.5.148 → 44.237.150.182 HTTP2 140 HEADERS[1]: GET /
17 0.014777 172.31.5.148 → 44.237.150.182 HTTP2 104 SETTINGS[0]
18 0.015195 44.237.150.182 → 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=2461 Ack=907 Win=28160 Len=0 TSval=2439383761 TSecr=3293266399
19 0.015362 44.237.150.182 → 172.31.5.148 HTTP2 104 SETTINGS[0]
20 0.015364 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=2499 Win=60544 Len=0 TSval=3293266399 TSecr=2439383761
21 0.048448 44.237.150.182 → 172.31.5.148 HTTP2 808 HEADERS[1]: 200 OK, DATA[1]
22 0.048449 44.237.150.182 → 172.31.5.148 HTTP2 104 DATA[1] (text/html)
23 0.048477 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=3241 Win=59904 Len=0 TSval=3293266433 TSecr=2439383793
24 0.048482 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [ACK] Seq=907 Ack=3279 Win=59904 Len=0 TSval=3293266433 TSecr=2439383793
25 0.049462 172.31.5.148 → 44.237.150.182 TLSv1.2 97 Alert (Level: Warning, Description: Close Notify)
26 0.049783 44.237.150.182 → 172.31.5.148 TCP 66 443 → 35686 [FIN, ACK] Seq=3279 Ack=938 Win=28160 Len=0 TSval=2439383795 TSecr=3293266434
27 0.050074 172.31.5.148 → 44.237.150.182 TCP 66 35686 → 443 [FIN, ACK] Seq=938 Ack=3280 Win=59904 Len=0 TSval=3293266434 TSecr=2439383795
28 0.050324 44.237.150.182 → 172.31.5.148 TCP 66 443 → 35686 [ACK] Seq=3280 Ack=939 Win=28160 Len=0 TSval=2439383796 TSecr=3293266434
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つの方法のうち、最後の方法を利用した解説をしています。