【証明書入門 第7回】TLSの仕組み ― TLS 1.3のハンドシェイク・暗号スイート・SNI/ECH・mTLS・PQC

証明書・PKI
スポンサーリンク
スポンサーリンク

「nginxでssl_ciphersを絞ったのに、TLS 1.3の暗号スイートが変わらないんです」
「新しいブラウザーにしたら、古いプロキシーの先のサイトにつながらなくなりました」

TLSは、ここ数年で大きく変わりました。TLS 1.3の登場、古い方式の禁止、SNIの暗号化(ECH)、そして耐量子計算機暗号(PQC)の導入。仕組みが変わったことを知らないと、こうした「設定したのに変わらない」「急につながらない」の原因にたどり着けません。

第6回までで、証明書の中身と発行の流れを見てきました。第7回では、その証明書が実際の通信でどう使われるか、TLSの仕組みを見ていきます。


SSLからTLS 1.3まで

バージョン公開仕様現在の扱い
SSL 2.01995年Netscape の仕様使用禁止(RFC 6176、2011年)
SSL 3.01996年RFC 6101(歴史的記録)使用禁止(RFC 7568、2015年)。POODLE
TLS 1.01999年RFC 2246使用禁止(RFC 8996、2021年)
TLS 1.12006年RFC 4346使用禁止(RFC 8996、2021年)
TLS 1.22008年RFC 5246使用可。ECDHE と AEAD に限る
TLS 1.32018年RFC 8446 で標準化、2026年7月に RFC 9846 へ改訂推奨。新しいプロトコルは TLS 1.3 必須(RFC 9852)

RFC 8996は「MUST NOT(使ってはならない)」で、「非推奨」ではありません。RFC 9846はTLS 1.2の仕様(RFC 5246)なども廃止扱いにし、TLS 1.2の実装への要件を引き継ぎました。TLS 1.2の使用が禁止されたわけではありません。この記事ではTLS 1.3をRFC 9846として扱います。


古い方式が使えなくなった理由

SSL・TLSの歴史は、見つかった弱点を塞いできた歴史です。

1995年のSSL 2.0から2018年のTLS 1.3までのバージョンの登場と、BEAST・POODLE攻撃、SSL 3.0・RC4・TLS 1.0/1.1の禁止、2026年のTLS 1.2のRSA鍵交換・DHEの禁止までの年表
  • SSL 3.0:パディングの検査の甘さを突いて平文を割り出すPOODLE攻撃(2014年)で致命傷を負った
  • TLS 1.0:CBCモードの弱点を突くBEAST攻撃(2011年)があった
  • TLS 1.0と1.1:認証付き暗号(AEAD)を使えず、SHA-1にも頼っていたため、2021年のRFC 8996で使用禁止に。暗号ではRC4も2015年に禁止された
  • 2026年7月のRFC 10015:TLS 1.2でも、RSA鍵交換と有限体のDH(DHE)鍵交換が使用禁止になった。RSA鍵交換には前方秘匿性(第2回)がなく、サーバーの秘密鍵が後で漏れると、記録されていた過去の通信がすべて解読されるから

結果として、TLS 1.2で使ってよいのはECDHEとAEADの組み合わせにほぼ限られ、TLS 1.3と同じ考え方になりました。今使うのは、TLS 1.3と、TLS 1.2(ECDHE+AEAD)です。


TLS 1.3のハンドシェイク

TLS 1.3では、ハンドシェイクが1往復(1-RTT)で終わります。

クライアントがkey_share(X25519MLKEM768)・SNI・ALPNを含むClientHelloを送り、サーバーがServerHello(key_share)を返した時点から暗号化が始まり、EncryptedExtensions・Certificate・CertificateVerify・Finishedを暗号化して送り、クライアントのFinishedの後にアプリケーションデータを送る1往復のハンドシェイクを示す図
  1. クライアントはClientHelloで、対応する暗号スイートや署名方式、接続先の名前(SNI)に加え、鍵交換の材料(key_share)を最初から送る。選ばれそうな方式を予想して入れておく
  2. サーバーはServerHelloで方式を選び、自分のkey_shareを返す。この時点で両者は同じ秘密を計算でき、以降は暗号化される
  3. 続けて証明書(Certificate)、秘密鍵による署名(CertificateVerify)、Finishedなどを暗号化して送る
  4. クライアントは証明書を検証し(第5回)、Finishedを返してデータを送り始める

証明書も暗号化されて届くため、途中の機器からは中身が見えません。予想が外れると、サーバーがHelloRetryRequestで方式を指定し、1往復増えます。最初の1通に鍵の材料を入れるから、2通目から暗号化できるわけです。

メッセージの役割

メッセージ向き暗号化役割
ClientHelloC→Sなし対応するバージョン・暗号スイート・グループ・署名方式、key_share、SNI、ALPN
ServerHelloS→Cなし選んだ暗号スイートとグループ、サーバーの key_share
EncryptedExtensionsS→CありALPN の結果など、暗号化してよい拡張
CertificateRequestS→Cありクライアント証明書を求める(mTLS のときだけ)
CertificateS→Cありサーバー証明書と中間証明書
CertificateVerifyS→Cありここまでのやり取りへの署名。証明書の秘密鍵を持つことの証明
Finished双方向ありやり取り全体の MAC。途中で改ざんされていないことの確認
NewSessionTicketS→Cあり次回の再開用のチケット

TLS 1.3では、証明書の秘密鍵は鍵交換に使われず、CertificateVerifyで「この証明書の持ち主が、今このやり取りをしている」ことを示す署名にだけ使われます。鍵交換は毎回使い捨てのECDHEで行うため、証明書の秘密鍵が後で漏れても過去の通信は解読されません(前方秘匿性)。


TLS 1.2(ECDHE)との違い

TLS 1.2(ECDHE)はClientHelloからFinishedまで2往復で暗号化が始まり証明書が平文で流れるのに対し、TLS 1.3は1往復で、ServerHelloの後から証明書も暗号化されることを並べて比べた図

TLS 1.2のECDHEによるハンドシェイクは2往復です。TLS 1.3との違いは3つあります。

  1. 鍵交換の材料を2往復目に送るため、遅い
  2. 証明書が平文で流れる。同じ証明書でも、1.2では途中の機器から中身が見える
  3. 古い方式を選べてしまう

よく見かける「プリマスターシークレットをサーバーの公開鍵で暗号化して送る」という図は、RSA鍵交換の図です。前方秘匿性がないためTLS 1.3で廃止され、TLS 1.2でもRFC 10015で禁止されました。TLS 1.2を残すなら、ECDHEとAEADの暗号スイートだけを許可します。


暗号スイートの読み方(1.2と1.3)

項目TLS 1.2TLS 1.3
例(IANA の名前)TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256TLS_AES_128_GCM_SHA256
例(OpenSSL の名前)ECDHE-RSA-AES128-GCM-SHA256TLS_AES_128_GCM_SHA256(同じ)
名前が表すもの鍵交換(ECDHE)・認証(RSA)・暗号(AES-128-GCM)・ハッシュ暗号(AEAD)とハッシュだけ
鍵交換の決め方暗号スイートで決まるsupported_groups・key_share 拡張(X25519MLKEM768 等)
署名の決め方暗号スイート+signature_algorithmssignature_algorithms 拡張
種類数百(古いものを含む)5つ(主に使うのは3つ)
OpenSSL・nginx での設定-cipher、ssl_ciphers-ciphersuites、ssl_conf_command Ciphersuites

TLS 1.3で主に使うのは、AES-128-GCM・AES-256-GCM・ChaCha20-Poly1305の3つです。

冒頭の「ssl_ciphersを絞ったのに変わらない」の答えがここにあります。nginxのssl_ciphersはTLS 1.2以前の設定で、TLS 1.3の暗号スイートは変わりません。TLS 1.3はssl_conf_command Ciphersuitesで設定します。WindowsではGet-TlsCipherSuiteで、有効な暗号スイートと順序を確認できます。


SNI・ALPN・ECH

  • SNI(Server Name Indication):ClientHelloで接続したい名前を伝える拡張。複数のサイトを動かすサーバーは、SNIを見て返す証明書を選ぶ
  • ALPN:HTTP/2(h2)とHTTP/1.1のどちらを使うかを決める拡張
ECHなしではClientHelloのSNI(shop.example.jp)が平文で途中の機器に見えて振り分けや記録に使われるが、ECHありではDNSのHTTPSレコードから得た公開鍵で本当のClientHelloを暗号化し、外側には共通の名前public.example.netだけを見せることを示す図

ただしSNIは平文なので、途中の機器から接続先が見えます。これを隠すのがECH(Encrypted Client Hello、RFC 9849、2026年3月)です。

  • クライアントは、DNSのHTTPSレコード(連載「DNS入門」第6回)からECHの公開鍵を得て、本当のClientHelloを暗号化し、外側には共通の名前だけを見せる
  • Chromeは117、Firefoxは119から既定で有効

注意したいのは、SNIで振り分けや監視をする社内のプロキシーやファイアウォールは、ECHの通信を見分けられなくなることです。


セッション再開と0-RTT

フルのハンドシェイクは時間がかかるため、一度接続した相手とは、前回の結果を使って短い手順で再接続します。

初回はフルハンドシェイクでNewSessionTicketを受け取り、再開時はチケット(PSK)で証明書なしに短縮し、0-RTTでは最初の1通で早期データも送るが、攻撃者が記録して送り直すリプレイで同じ注文が2回処理されうることを示す図
  • TLS 1.2ではセッションIDやセッションチケット、TLS 1.3ではNewSessionTicketで渡されるチケット(PSK、事前共有鍵)を使う。TLS 1.3ではPSKと新しいECDHEを組み合わせて、前方秘匿性も保てる
  • 注意点は、チケットを暗号化するサーバー側の鍵(チケットキー)。長く変えずにいて漏れると多くの通信が解読されるため、定期的に入れ替える

さらにTLS 1.3には、再開時にClientHelloと一緒に最初のデータを送る0-RTT(早期データ)があります。速くなる代わりに、記録した早期データを送り直すリプレイ攻撃を防げず、同じ「注文」が2回処理されるおそれがあります。0-RTTは既定で無効のサーバーが多く、使うなら副作用のない処理に限ります。迷ったら無効のままにしましょう。


クライアント証明書(mTLS)

サーバーがCertificateRequestを送り、クライアントも証明書と署名(CertificateVerify)を返して互いに認証する方式を、相互TLS(mTLS、クライアント証明書認証)と呼びます。

社内CAがクライアント証明書を発行・配布し、サーバーがCertificateRequestで証明書を求め、クライアントも証明書とCertificateVerifyを返し、サーバーが社内CAのルートで検証して鍵を持つ端末だけを通すことを示す図
  • 通常のTLSと違い、秘密鍵を持つ端末だけが接続できるため、パスワードを盗まれても使えない
  • 802.1X(EAP-TLS)、VPN、サービス間のAPI通信などで使い、証明書は社内CA(第9回)で発行するのが基本
  • 以前は公開CAの証明書にもクライアント認証の用途(EKUのclientAuth)が入っていたが、Chromeのルートプログラムの要件の変更で、Let’s Encryptは2026年2月にこれを外した。流用している構成は見直す
  • TLS 1.3はRSAのPKCS#1 v1.5署名を認めないが、古いICカードなどのため、2026年4月のRFC 9963でクライアント証明書に限り例外が設けられた

サーバー証明書と同じ確認を、逆向きにもう1回行う、と考えると分かりやすいでしょう。


PQCハイブリッド鍵交換(X25519MLKEM768)

冒頭の2つ目、「新しいブラウザーで古いプロキシーの先につながらない」の原因になりうるのが、これです。

従来のX25519とFIPS 203のML-KEM-768の2つの秘密を混ぜてセッション鍵を作り片方が破られても安全であることと、ClientHelloのkey_shareがX25519の32バイトからX25519MLKEM768の約1,216バイトに増えて1パケットに収まらず古い機器で失敗することがあることを示す図

量子コンピューターが実用化されるとECDHEやRSAは解かれるおそれがあり、今の通信を記録して将来解読する「Harvest Now, Decrypt Later」攻撃に備えて、鍵交換から移行が進んでいます(第2回)。

  • 使われるのは、従来のX25519と、FIPS 203のML-KEM-768を組み合わせるX25519MLKEM768(RFC 10024、2026年8月)。両方を混ぜて鍵を作るため、片方が破られても安全
  • Chrome 131、Firefox 132、iOS・macOS 26、OpenSSL 3.5が既定で提示する。WindowsのSchannelも2026年に対応したが既定では無効
  • 注意点は、key_shareが約1.2KB増えて、ClientHelloが1パケットに収まらなくなること。これを扱えない古い機器やミドルボックスでは、接続に失敗する

変わったのは鍵交換だけで、証明書の署名は今もECDSAやRSAです。


推奨設定(RFC 9325とMozillaの設定例)

項目ModernIntermediate(一般的な推奨)
TLS バージョン1.3 のみ1.2、1.3
TLS 1.3 の暗号スイートAES-128-GCM、AES-256-GCM、ChaCha20-Poly1305同左
TLS 1.2 の暗号スイート—ECDHE+AES-GCM/ChaCha20-Poly1305 の6つだけ
鍵交換のグループX25519MLKEM768、X25519、P-256、P-384同左
証明書ECDSA(P-256・P-384)ECDSA、または RSA 2048ビット以上
HSTSmax-age=63072000(2年)同左
想定する最も古いクライアントChrome 70、Firefox 63、Android 10、Safari 12.1IE 11(Windows 10)、Android 4.4.2、Java 8u161

Mozilla SSL Configuration Generator(ssl-config.mozilla.org、ガイドライン 6.0)は、nginx・Apache等の設定例をサーバーのバージョンに合わせて出してくれます。迷ったらIntermediateを選びます。RFC 9325(2022年)はTLS 1.2以上を必須・TLS 1.3を推奨とし、RFC 9852(2026年)は新しいプロトコルにTLS 1.3を必須としました。


接続を調べる:openssl s_client

$ openssl s_client -connect www.example.jp:443 -servername www.example.jp </dev/null
(抜粋)
Certificate chain
 0 s:CN=www.example.jp
   i:C=JP, O=Example Trust, CN=Example Issuing CA
   a:PKEY: EC, (prime256v1); sigalg: ecdsa-with-SHA256
   v:NotBefore: Jul 29 22:10:08 2026 GMT; NotAfter: Oct 27 22:17:21 2026 GMT
 1 s:C=JP, O=Example Trust, CN=Example Issuing CA
   i:C=JP, O=Example Trust, CN=Example Root CA
Negotiated TLS1.3 group: X25519MLKEM768
Verification: OK
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
    Verify return code: 0 (ok)
  • -servernameを必ず付ける(SNI)。付けないと既定の証明書が返り、名前の不一致と誤解する
  • Certificate chain:0がサーバー証明書、1以降が中間証明書。各行のi:(発行者)が次の番号のs:(主体)とつながっているかを見る(第4回)。v:で有効期間も分かる
  • Verification: OKは、手元の信頼ストアでチェーンの検証に成功したという意味。名前の一致は既定では確かめないので、-verify_hostname www.example.jpを付ける。失敗すると10 (certificate has expired)のように番号と理由が出る(第10回)

s_clientの主なオプション

やりたいことオプション・コマンド見るところ
名前の一致も検証する-verify_hostname www.example.jpVerified peername:、不一致は 62 (hostname mismatch)
バージョンを指定して試す-tls1_2/-tls1_3接続できるか、Protocol:
鍵交換のグループを指定する-groups X25519MLKEM768Negotiated TLS1.3 group:
ALPN を送る-alpn h2,http/1.1ALPN protocol: h2
送られたチェーンを PEM で全部見る-showcerts中間証明書が送られているか
要約だけ見る-briefProtocol version:、Ciphersuite:
メールの STARTTLS-starttls smtp(imap・pop3 等)メールサーバーの証明書
期限と SAN だけ見るs_client の出力をパイプで openssl x509 -noout -dates -ext subjectAltName に渡すnotAfter と SAN

-tls1_2で接続すると、ECDHEの鍵交換はPeer Temp Key: X25519, 253 bitsのように表示されます。OpenSSL 3は既定のセキュリティレベルでTLS 1.0/1.1を送らないため、-tls1_1は手元で「no protocols available」になり、サーバーの設定は分かりません。サーバーが受け付ける版の一覧は、次のnmapなどで調べます。


curlとWindows(PowerShell)で調べる

$ curl -v -o /dev/null https://www.example.jp/        # (抜粋)
* ALPN: curl offers h2,http/1.1
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
*   subject: CN=www.example.jp
*   expire date: Oct 27 22:17:21 2026 GMT
*   subjectAltName: "www.example.jp" matches cert's "www.example.jp"
* SSL certificate verified via OpenSSL.
PS> $tcp = [System.Net.Sockets.TcpClient]::new('www.example.jp', 443)
PS> $ssl = [System.Net.Security.SslStream]::new($tcp.GetStream())
PS> $ssl.AuthenticateAsClient('www.example.jp')     # 検証(名前を含む)に失敗すると例外
PS> $ssl.SslProtocol                                # Tls13
PS> $ssl.NegotiatedCipherSuite                      # TLS_AES_256_GCM_SHA384(PowerShell 7)
PS> ([System.Security.Cryptography.X509Certificates.X509Certificate2]$ssl.RemoteCertificate).NotAfter
PS> $ssl.Dispose(); $tcp.Dispose()
  • Test-NetConnection www.example.jp -Port 443は、TCPの到達性だけを見る。TLSと証明書は上のSslStreamで確かめる
  • PowerShell 7ならInvoke-WebRequest https://www.example.jp -SslProtocol Tls12で、指定した版で接続できるかを試せる
  • サーバーが受け付ける版と暗号スイートの一覧はnmap --script ssl-enum-ciphers -p 443 www.example.jpで取れる(許可を得た対象にだけ使う)

考えてみよう

  1. 自分の担当サーバーは、TLS 1.0/1.1やRSA鍵交換(TLS_RSA_WITH_…)の暗号スイートをまだ受け付けていませんか。どうやって確かめますか。
  2. 社内のプロキシーやファイアウォールは、SNIを見て通信を制御していますか。ECHや大きなClientHello(PQC)が広がると、何が起きそうですか。
  3. クライアント証明書(mTLS)を使っている仕組みはありますか。その証明書はどのCAが発行し、失効はどう確かめていますか。

ヒント:この記事の「古い方式が使えなくなった理由」「SNI・ALPN・ECH」「mTLS」「PQCハイブリッド鍵交換」と、確認コマンドが手がかりです。


まとめ

  • 今使うのはTLS 1.3とTLS 1.2(ECDHE+AEAD)。RSA鍵交換は2026年に1.2でも禁止
  • TLS 1.3は1往復で暗号化が始まり、証明書も暗号化される。証明書の秘密鍵は署名にだけ使う
  • TLS 1.3の暗号スイートはAEADとハッシュだけ。nginxのssl_ciphersでは変わらない
  • SNIは平文、ECHで暗号化。SNIを見る社内の機器に影響する
  • 0-RTTはリプレイを防げない。mTLSの証明書は社内CAで発行する
  • PQCのX25519MLKEM768は既定で使われ始めた。大きなClientHelloで古い機器が失敗しうる

次回は、証明書の期限切れを防ぐための棚卸し、ACMEによる自動更新、期限の監視を扱います。


連載「証明書入門」全11回

  1. なぜ証明書が必要か
  2. 暗号の基礎
  3. openssl・PowerShellで試す
  4. X.509証明書の中身
  5. PKIと信頼の仕組み
  6. 証明書の種類と発行
  7. TLSの仕組み(この記事)
  8. ライフサイクルと自動化
  9. 社内PKIとクラウド
  10. 証明書トラブルシュート
  11. 証明書の設計演習

コメント

タイトルとURLをコピーしました