TLS

Similar documents
HTTP/2, QUICからTLS1.3へ

2.SSL/TLS と暗号プロトコルの安全性 恒久的に噴出する脆弱性との戦い クライアント ClientKeyExchange Verify ServerKeyExchange Request Done Request サーバ X Master Secret CCS MAC 図 -1 図

調査結果詳細 本書は SSL/TLS アプライアンス製品の暗号設定方法等の調査報告書 の 1 部分を取り出したもの である 調査の背景 調査方法等は報告書を参考にされたい 1.x.1 章記載の表 1.x.1-1 暗号設定内容 ( デフォルト ) の見方を以下に示す CipherSuite 選択優先権

IPsec徹底入門

MPX8005c SSL/TLS アプライアンス製品の暗号設定方法等の調査報告書

C02.pdf

SSL 安 全 性 調 査 報 告 書 改 訂 第 2 版 2004 年 2 月 6 日 ( 株 )KDDI 研 究 所 1

IPCOM EX (IPCOM EX IN ソフトウェア V01) SSL/TLS アプライアンス製品の暗号設定方法等の調査報告書

TLS/SSLの暗号利用に関する現状と課題

Microsoft PowerPoint - IPsec徹底入門.ppt

ATS の概要とCloudFrontの対応状況CloudFrontのSSL機能

TFTP serverの実装

ローカル ポリシーでの FIPS の有効化

楕円曲線暗号の整備動向 +楕円暗号の実装状況

ビットコイン (ブロックチェーン)

山添.pptx

TLS _final

通信プロトコルの認証技術

SSL/TLS暗号設定ガイドライン

全てのパートナー様に該当する可能性のある 重要なお知らせです 2015 年 8 月 28 日 パートナー各位 合同会社シマンテック ウェブサイトセキュリティ SSL サーバ証明書における階層構造オプションの追加 および DNS Certification Authority Authorizatio

橡sirahasi.PDF

AirStationPro初期設定

証明書(Certificates)

IPSEC(Si-RG)

DNSSECの基礎概要

スライド 1

PowerPoint プレゼンテーション

シナリオ:サイトツーサイト VPN の設定

VPN 接続の設定

Juniper Networks Corporate PowerPoint Template

Microsoft PowerPoint - 2k_SSL Value for Customers.pptx

PKI(Public Key Infrastructure: 公開鍵暗号基盤 ) の活用 1 認証局ソフトウェアで証明書を発行する認証局ソフトウェア (Easy Cert) で認証局を構築する手順を示す この Easy Cert は名古屋工業大学電気情報工学科の岩田研究室で開発された暗号ライブラリを

2. 機能 ( 標準サポートプロトコル ) SECURITY for Biz 対応スマートフォンでは標準で対応している VPN プロトコルがあります 本章では NTT ドコモで動作確認を実施している PPTP L2TP/IPSec IPSec Xauth について記載します PPTP(Point-t

インターネットVPN_IPoE_IPv6_fqdn

技術情報:Si-R/Si-R brinシリーズ設定例 「Oracle Cloud Infrastructure Classic」との接続

Microsoft PowerPoint SCOPE-presen

SFTPサーバー作成ガイド

RADIUS 無効な認証者およびメッセージ認証者のトラブルシューティング ガイド

Clearswift PPT Template

SmartGS-ReleaseNote-V132

UID S307-NDEF

PowerPoint Presentation

HULFT の通信をよりセキュアに HULFT と SSH Tectia を組み合わせたセキュアで強力なファイル転送 Compatibility Note 2008 年 9 月 株式会社セゾン情報システムズの企業内 企業間通信ミドルウェアである HULFT は ファイル転送のアプリケーションとして

cpvp_PKM_ProVerif

SSL/TLSサーバ構築ガイドライン

1 暗号化通信におけるリスク ~ SSH に潜む落とし穴 ~ 暗号化すれば安全ですか? 目次 1. はじめに SSH とは SSH に潜む落とし穴 SSH での効果的な対策 最後に... 13

Windows PowerShell 用スクリプト形式編 改版履歴 版数 日付 内容 担当 V /4/1 初版 NII V /2/26 動作環境の変更に伴う修正 NII V /8/21 タイムスタンプ利用手順の追加 NII 目次 1. コード署名用証明

2. 機能 ( 標準サポートプロトコル ) NTT ドコモの Android スマートフォン / タブレットでは標準で対応している VPN プロトコルがあります 本章では 動作確認を実施している PPTP L2TP/IPSec IPSec Xauth について記載します PPTP(Point-to-

無線 LAN セキュリティの基礎 2015 年 4 月 19 日セクタンラボ Copyright (C) 2015 SecTan Lab. All Rights Reserved.

自己紹介 名前 : 一ノ瀬太樹 所属 : HASH コンサルティング株式会社 OWASP Japan プロモーションチーム OWASP ZAP ユーザーグループ脆弱性診断研究会 ( 管理者その 3) Perl 入学式 ( サポーター ) HASH Consult

[ 証明書の申請から取得まで ] で受領したサーバ証明書を server.cer という名前で任意の場所に保存してください ( 本マニュアルではローカルディスクの work ディレクトリ [C:\work] に保存しています ) 中間 CA 証明書を準備します 次の URL にアク

DNSSEC の仕組みと現状 平成 22 年 11 月 DNSSEC ジャパン

他の章は下記をクリックして PDF 一覧からお入り下さい IT ライブラリー (pdf 100 冊 ) 目次番号 270 番 Windows Server Enterprise 2008 R2 完全解説 ( 再入門 )

はじめに はじめに 本書について本書はオールインワン認証アプライアンス NetAttest EPS と ELECOM 社製無線アクセスポイント WAB-M2133 の IEEE802.1X EAP-TLS/EAP-PEAP(MS-CHAP V2) 環境での接続について 設定例を示したものです 設定例

製品ラインアップ ハードウェア < 部品としてのご提供 > ーお客様でソフトエアの開発が必要ですー弊社で受託開発も可能です チャレンジ & レスポンス Web 構築に最適ドライバレスタイプ : epass1000nd チャレンジ & レスポンス方式 電子証明書の格納に両方対応可能汎用型タイプ : e

ASF-01

SOC Report

目次 1. はじめに SSL 通信を使用する上での課題 SSL アクセラレーターによる解決 SSL アクセラレーターの導入例 SSL アクセラレーターの効果... 6 富士通の SSL アクセラレーター装置のラインナップ... 8

目次 1 概要 モジュール概要 暗号モジュールの仕様 暗号境界 物理的暗号境界 論理的暗号境界 動作モードとアルゴリズム ポートとインタフェース 暗号モジュール

■POP3の廃止について

大阪大学キャンパスメールサービスの利用開始方法

脆弱性 (CTX230612) の対応方法 対応方法設定手順 GUI での設定方法 realserver に対するクライアント証明書の認証解除 CipherSuite の DHE を無効化 CLI での設定方法 realserver に対するクライアント証明書の認証解除 CipherSuite の

実務に役立つサーバー運用管理の基礎 CompTIA Server+ テキスト SK0-004 対応

パスワード暗号化の設定

DNSOPS.JP BoF nginxを利 した DNS over TLS 対応フルリゾルバの作り ( 株 ) ハートビーツ滝澤隆史

IPSEC(Si-RGX)

(Microsoft PowerPoint CRYPTREC\203V\203\223\203|\203W\203E\203\200.v4.handsout)

Transcription:

SSL/TLS の基礎と最新動向 セキュリティキャンプ 2015 2015 年 8 月 12 日 IIJ 大津繁樹 更新版資料の置場 http://goo.gl/cx1m17 Github Repo: https://goo.gl/vrlzrj

自己紹介 大津繁樹 株式会社インターネットイニシアティブ プロダクト本部アプリケーション開発部サービス開発 2 課 NodeJS Technical Committee メンバー ( 主に TLS/CRYPTO/OpenSSL バインディングを担当 ) IETF httpbis WG で HTTP/2 相互接続試験等仕様策定に参画 ブログ : http://d.hatena.ne.jp/jovi0608/

はじめに TLS(Transport Layer Security) の仕組みについて学んでいただきます 後述するよう TLS は 様々なセキュリティの要素技術から成り立っており その一つ一つが難解で深い技術要素です 残念ながら 4 時間もの時間があってもその全てを完全に理解することは容易ではありません

本講義の目的 TLS の本質は 要素技術をどう組み合わせてどういう手順でセキュアな通信を確立するかというところにあります そのため 本講義の目的は TLS 技術の基礎 TLS ハンドシェイクの仕組み を理解していただくことです 聞いているだけの理解より 実際に手を動かしての体験する方を重視して進めます 課題内容は空白にしています 講義当日にお知らせします

本講義の内容 TLS の概要 TLS を理解する準備 TLS の話 まずは TLS_RSA_WITH_AES_128_GCM_SHA256 の時から Perfect Forward Secrecy TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 を使う 最新情報 TLS1.3 とはどういうものか? 概要説明

まずやってみる モジュールのインストール $npm install seccamp2015-data-reader seccamp2015-tls Simple TLS Client (simple_tls_client.js) の取得 $git clone https://github.com/shigeki/seccamp2015-tls $cd SecCamp2015-TLS $node simple_tls_client.js キーボードを打ってみよう ( 注 : エラー処理やサニタイジングが十分でないのであくまでテスト用で利用すること )

TLS の概要

インターネットの脅威 盗聴 パスワードやクレジットカード番号を盗み見

インターネットの脅威 改ざん 通信途中でデータを書き換え

インターネットの脅威 なりすまし ユーザになりすまして通信を行う

インターネットの脅威 否認 そんな通信してませんと否認する

インターネットの脅威から守るセキュリティ対策 盗聴 暗号化 改ざん 成りすまし 完全性チェック 認証 否認 署名

各レイヤーにおけるセキュリティ通信 S/MIME, PGP データ TLS,DTLS,SSH TCP, UDP IPsec IP WPA 無線 LAN

TLS の目的 RFC5246: The Transport Layer Security (TLS) Protocol Version 1.2 1. Introduction The primary goal of the TLS protocol is to provide privacy and data integrity between two communicating applications. TLS プロトコルの最重要なゴールは 通信する 2 つのアプリケーションの間でプライバシーとデータの完全性を提供することです プライバシー アプリ アプリ 完全性

TLS の簡単な歴史 現在の利用推奨 SSL 1.0 未発表 1994 年 SSL 2.0 1995 年 SSL 3.0 1996 年 IETF TLS WG スタート 1999 年 TLS 1.0 2006 年 TLS 1.1 2008 年 TLS 1.2 SSL は 旧ネットスケープ社の私的プロトコル SSL3.0 と基本設計は大きく変えず 内部バージョンは TLS1.0 =SSL 3.1 2013 年 TLS 1.3 検討スタート TLS と名前を変えて標準化 様々な拡張仕様の追加

TLS を理解する準備

TLS の要素技術 PKI X509 証明書 乱数生成 対称暗号 デジタル署名 鍵交換 公開鍵暗号 TLS メッセージ認証 暗号モード 一方向ハッシュ TLS プロトコルは これらの要素技術を組み合わせてアプリ間のセキュア通信を確立する手順を決める

TLS 要素技術の依存性 PKI 暗号モード X509 証明書 対称暗号 デジタル署名 メッセージ認証 鍵交換 公開鍵暗号 一方向ハッシュ 乱数生成 本来はこの一つ一つをきちんと理解してもらうのが必要

TLS 要素技術の依存性 PKI 暗号モード GCM X509 証明書 対称暗号 AES デジタル署名 メッセージ認証 HMAC ECDHE 鍵交換 RSA 公開鍵暗号 一方向ハッシュ SHA256 乱数生成 本日の講義で扱う技術 説明は概要だけですが 演習で実際の動作を手を動かして体験してもらいます

要素技術と TLS CipherSuites デジタ対称暗号 TLS _ 鍵交換 _ ル署名 _WITH_ 暗号 _ 鍵長 _ モード _ メッセージ認証 ( ハッシュ ) TLS_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9C} 鍵交換 デジタル署名に RSA 対称暗号に 128bit 鍵長の AES 暗号モードに GCM ハッシュに SHA256 番号として 0x00,0x9C を割り当て TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256= {0xC0,0x2F}; 鍵交換に ECDHE デジタル署名に RSA 対称暗号に 128bit 鍵長の AES 暗号モードに GCM ハッシュに SHA256 番号として 0xC0,0x2F を割り当て

乱数生成 利用用途 : 暗号鍵 ( 対称暗号 : 秘密鍵 公開鍵暗号 : 鍵ペア ) の生成 暗号モードの初期ベクトルや Nonce(*) の生成 MAC( メッセージ認証 ) 用鍵 求められる機能無作為性 : 偏りがなく等しい数である 予測不可能性 : 次の乱数が予想できない 制限負可能性 : 同じ乱数列を再現できない (* Nonce(number used once) 一度だけ使い捨て用に使われる数字

乱数生成 実際の利用は 疑似乱数生成 seed が必要 OpenSSL では seed は Linux の /dev/urandom を利用 Windows では OS の API の CryptGenRandom だけでなく画面スクリーンのビットマップハッシュも利用 脆弱性 : CVE-2008-0166: Debian や Ubuntu の OpenSSL に予測可能な乱数を生成してしまう脆弱性 SSH 公開鍵にブルートフォース攻撃

対称暗号 暗号化 復号化 平文 暗号文 平文 共通鍵 共通鍵 ストリーム暗号 : データを逐次暗号化 (RC4, Chacha20) ブロック暗号 : データをブロック毎に暗号化 (DES, AES) 幾つかの暗号では既に危殆化 : DES: 2005 年 NIST FPS46-3 規格の廃止 (2030 年までは許容 ) RC4: RFC7455: Prohibiting RC4 Cipher Suites

対称暗号 AES 1997 年よりプロジェクト開始 2000 年選定 2001 年仕様発行 ブロックサイズ 128bit 鍵長 : 128bits, 192bits, 256bits の3 種類 Intel/AMDのCPUでハードウェア処理のサポート AES-NI

暗号モード ブロック暗号は同じデータを同じ鍵で暗号化すると毎回同一の暗号文になる ブロック長より長いデータを暗号化する場合に暗号モードを利用して繰り返しを避ける CBC: ( 平文 XOR ベクトル ) を暗号化 を続ける CTR: カウンターを暗号化 XOR 平文 を続ける これまでの主流 これからの主流に (GCM 後述 ) 実際に TLS で利用するには改ざん検知のための MAC( メッセージ認証 ) との組み合わせる (AEAD)

AEAD( 認証付き暗号 ) 暗号化しないけど改ざん防止が必要なデータ ( ヘッダ等 ) 暗号化する平文 初期ベクトル AEAD 暗号化 共通鍵 暗号文 認証タグ

AEAD( 認証付き暗号 ) 暗号化しないけど改ざん防止が必要なデータ ( ヘッダ等 ) 暗号文 認証タグ 初期ベクトル AEAD 復号化改ざんチェック 共通鍵 平文

GCM GCM (Galois Counter Mode: ガロアカウンターモード ) CTRとGHASHを組み合わせたAEAD ハードウェア処理で高速化が可能 AESと組み合わせて AES-GCMとして利用

一方向ハッシュ データ 一方向ハッシュ関数 ハッシュ値 ハッシュ値を比較することでデータの改ざんをチェックすることができる

一方向ハッシュ md5 既に現実的な攻撃手法が存在 (*1) SHA-1 SHA-2(SHA-256 など 6 種 ) 2018 年ぐらいには現実的なコストで衝突データを探せる見込み (*2) SHA-3(SHA3-256 など 6 種 ) 8/5 に NIST より正式公開 (*1) how to Break MD5 and Other Hash Functions http://merlot.usc.edu/csac-f06/papers/wang05a.pdf (*2) Cryptanalysis of SHA-1 https://www.schneier.com/blog/archives/2005/02/cryptanalysis_o.html

メッセージ認証 (HMAC) 共通鍵 データ 一方向ハッシュ関数 ハッシュ値 事前に共通鍵を共有 共通鍵とデータを組み合わせたハッシュ値を作成 データの完全性とハッシュ作成者を認証する

公開鍵暗号 公開鍵 秘密鍵 暗号化 復号化 解を求めるのが困難な数学的問題を利用して暗号を生成 公開鍵と秘密鍵のペアを生成 公開鍵はさらして大丈夫 公開鍵で暗号化し秘密鍵で復号化 RSA ECC( 楕円曲線暗号 ) 512bit RSA の危険性 FREAK https://freakattack.com/

鍵交換 2 者間で安全に鍵を共有する仕組み 互いに公開鍵を交換しあい 共有鍵を生成する 通信経路上で共有鍵のやり取りがない DH (Diffie-Hellman) ECDH( 楕円曲線 DH) 512bit DH Logjam https://weakdh.org/

デジタル署名 秘密鍵 データ + デジタル署名 公開鍵 データの完全性のチェックが可能となる データの送信元の認証が可能となる 公開鍵の信頼性の範囲で否認防止が可能となる RSA DSA,ECDSA データハッシュ値を暗号化しデジタル署名を生成 デジタル署名を復号化 データハッシュ値と比較し検証する

X509 証明書 (Certificate) 公開鍵と所有者 発行者やその他属性情報をデジタル署名したデータ 元々は電子ディレクトリサービス仕様 (X500) の一部 認証局 (CA) が所有者の実体を確認して証明書を発行する (PKI)

X509 証明書 (Certificate)

演習 : sudo npm install -g seccamp2015-crypto-workshopper 乱数生成 AES-GCM 公開鍵暗号 一方向ハッシュ 鍵交換 メッセージ認証 デジタル署名 X509 証明書 ( 時間がなさそうなので取りやめました )

TLS の話 まずは TLS_RSA_WITH_AES_128_GCM_SHA256 の時から 注 : 複雑さを避けるためクライアント認証機能は説明しません

TLS データ表現の仕方 ( 構造体, メンバー ) 構造体と同じ struct { uint8 major; uint8 minor; } ProtocolVersion; 構造体名 8bit 符号なし整数 (2 バイト ) 0 1 majaor minor ProtocolVersion version = { 3, 3 }; /* TLS v1.2*/ 0 1 0x03 0x03

TLS データ表現の仕方 ( 配列 エンディアン ) struct { uint32 gmt_unix_time; opaque random_bytes[28]; } Random; 32bit 符号なし整数 (4 バイト ) 1970/1/1 0:00(UTC) からの経過秒数 28 バイト長の任意のバイト列 [] の中はバイト数を表す データを書き込むときは 最上位のバイトデータをインデックスの小さい方から大きい方への順番で書き込む (big-endian/network byte order) 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 gmt_unix_time random_bytes Mon Jul 20 2015 01:55:29 GMT+0900 (JST) = 1437324929 sec = 0x55abd681 0 1 2 3 55 ab d6 81

TLS データ表現の仕方 ( 可変ベクター ) 0 0x00 opaque SessionID<0..32>; SessionID のサイズが 0 の場合 <> は可変ベクター型を表す 中の数字は < 最少サイズ.. 最大サイズ > 先頭にサイズを必ず入れ その後にデータが続く 先頭のサイズの領域は最大サイズが格納できる量 左の場合は最大 32 バイトだから 1 バイト (255 まで表現可能 ) 分のサイズ領域があればよい 0 1 0x01 SessionID(1 バイト ) SessionID のサイズが 1 の場合 SessionID のサイズが 32 の場合 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 0x20 SessionID(32 バイト )

TLS データ表現の仕方 (enum) uint8 CipherSuite[2]; 8bit 符号なし整数が 2 バイト CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = { 0x00,0x40 }; 0 1 0x00 0x40 enum { null(0), (255) } CompressionMethod; CompressionMethod の値は最大 255 まで (1 バイト分 ) NULL は 0 に割り当てられています

TLS データ表現の仕方 ( 条件式 ) struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-2>; CompressionMethod compression_methods<1..2^8-1>; select (extensions_present) { 条件式 case false: extensionが存在しなければ 空 struct {}; してれば 0~2^16-1までの可変ベクターのデータが入る case true: Extension extensions<0..2^16-1>; }; } ClientHello;

TLS データ表現の仕方 ( 読んでみよう ) struct { ExtensionType extension_type; opaque extension_data<0..2^16-1>; } Extension; enum { signature_algorithms(13), (65535) } ExtensionType;

TLS データ表現の仕方 ( 読んでみよう ) enum { none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), sha512(6), (255) } HashAlgorithm; enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } SignatureAlgorithm; struct { HashAlgorithm hash; SignatureAlgorithm signature; } SignatureAndHashAlgorithm; SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>;

TLS データ表現の仕方 ( 読んでみよう ) struct { uint8 major; uint8 minor; } ProtocolVersion; enum { change_cipher_spec(20), alert(21), handshake(22), application_data(23), (255) } ContentType; struct { ContentType type; ProtocolVersion version; uint16 length; opaque fragment[tlsplaintext.length]; } TLSPlaintext;

TLS1.2 の構造 ChangeCipherSpec ( タイプ :0x14) タイプ I P ヘッダ T C P ヘッダ タイプ (4 種類 ) (1byte) TLS Record Layer (5 バイト ) バージョン (2byte) 長さ (2byte) Alert ( タイプ :0x15) レベル msg タイプ (10 種類 ) 理由 Handshake ( タイプ :0x16) 長さ (3 バイト長 ) ハンドシェイクデータ TLS Record Layer データに続いて 次の 4 種類の TLS データのいずれかが続く Application Data ( タイプ :0x17) 暗号化されたデータ msgタイプ 0x00 0x01 ハンドシェイクデータの種類 HelloRequest ClientHello 0x02 ServerHello TLS Handshake は この 10 種類に分かれる 0x0b 0x0c 0x0d Certificate ServerKeyExchange CertificateRequest 0x0e ServerHelloDone 0x0f CertificateVerify 0x10 ClientKeyExchange 0x14 Finished

TLS ハンドシェイクデータの構造 struct { HandshakeType msg_type; uint24 length; select (HandshakeType) { case hello_request: case client_hello: case server_hello: case certificate: HelloRequest; ClientHello; ServerHello; Certificate; case server_key_exchange: ServerKeyExchange; case certificate_request: CertificateRequest; case server_hello_done: ServerHelloDone; case certificate_verify: CertificateVerify; case client_key_exchange: ClientKeyExchange; case finished: } body; } Handshake; Finished; msg タイプ (10 種類 ) Handshake ( タイプ :0x16) 長さ (3 バイト長 ) ハンドシェイクデータ enum { hello_request(0), client_hello(1), server_hello(2), certificate(11), server_key_exchange (12), certificate_request(13), server_hello_done(14), certificate_verify(15), client_key_exchange(16), finished(20) (255) } HandshakeType; msg タイプの種類でそれぞれの構造を参照する

TLS ハンドシェイク まずは TLS_RSA_WITH_AES_128_GCM_SHA256 の時から

TLS ハンドシェイク (full handshake) ClientHello ServerHello Certificate ServerHelloDone ClientHello と ServerHello のやり取りで双方が利用する TLS バージョンや暗号化方式などを合意する ClientKeyExchange ChangeCipherSpec Finished ChangeCipherSpec Finished Application Data Application Data ( 赤文字はハンドシェイク )

TLS ハンドシェイク (resumption) ClientHello ServerHello ChangeCipherSpec Finished SessionID による TLS セッションの再開 鍵交換や証明書送付をスキップ ChangeCipherSpec Finished Application Data Application Data ( 赤文字はハンドシェイク ) 今回は演習の対象外です

TLS ハンドシェイクの意味 ClientHello/ServerHello/ServerHelloDone TLS のための情報交換バージョン 乱数 暗号方式 拡張情報 Certificate 公開鍵情報の送付エンドポイントの認証 ClientKeyExchange/ServerKeyExchange 共有鍵交換 ChangeCipherSpec 暗号開始の合図 Finished ハンドシェイクデータの改ざんチェック

ClientHello struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-2>; CompressionMethod compression_methods<1..2^8-1>; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ClientHello;

ClientHello 項目要素サイズ先頭の長さ情報 client_version uint8 major, uint8 minor 2 N/A random uint32 gmt_unix_time, opaque random_bytes[28] 4 + 28 N/A session_id opaque SessionID <0..32> 1 バイト分 cipher_suites uint8 CipherSuite[2] <2..2^16-2> 2 バイト分 compression_met hods null(0) <1..2^8-1> 1 バイト分 extensions extension_type(65535), extension_data<0..2^16-1> <0..2^16-1> 2 バイト分 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 type データ長 Extensions データ例 データ type データ 長 データ type データ 長 データ Extension 長

ClientHello クライアントが利用できる最高の TLS バージョンを指定 サーバがどのバージョンを使うか選択する Record Layer Handshake (ClientHello) type protocol version length (2byte) msg type length (3byte) client version random session id cipher suite compr ession Extensi on major minor major minor 0x16 0x03 0x01???? 0x01?????? 0x03 0x03 32 byte 可変可変可変可変 Version 0x03,0x00 = SSLv3 0x03,0x01= TLSv1.0 0x03,0x02=TLSv1.1 0x03,0x03=TLSv1.2

最小の ClientHello Record Layer Handshake (ClientHello) type protocol version length (2byte) msg type length (3byte) client version random session id cipher suite compression major minor major minor 0x16 0x03 0x01 0x00 0x2D 0x01 0x00 0x00 0x29 0x03 0x03 32 byte All 0x00 0x00 0x00,0x02 0x00,0x9c 0x01 0x00 45 byte 長 41 byte 長 CipherSuite 指定 (1 種 ) TLS1.2 用 TLS_RSA_WITH_AES_128_GCM_SHA256:0x00,0x9c '160301002D' + '0100290303' + + crypto.randombytes(32).tostring('hex') '000002009C0100' 本当はちゃんとした乱数を入れる

演習 : 最少 ClientHello を作って送る https://gist.github.com/shigeki/d880ae0b4eef3cfd1acc var net = require('net'); var crypto = require('crypto'); var recordheader = '160301002D'; var random = crypto.randombytes(32).tostring('hex'); var handshake = '010000290303' + random + '000002009C0100'; var clienthello = new Buffer(recordheader + handshake, 'hex'); var client = net.connect({host: 'tls.koulayer.com', port: 443}, function() { client.write(clienthello); }); client.on('data', function(c) { // Receive ServerHello console.log(c); });

ServerHello struct { ProtocolVersion server_version; Random random; SessionID session_id; 複数ではない CipherSuite cipher_suite; CompressionMethod compression_method; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ServerHello; 複数ではない

ServerHello 項目要素サイズ先頭の長さ情報 server_version uint8 major, uint8 minor 2 N/A random uint32 gmt_unix_time, opaque random_bytes[28] 4 + 28 N/A session_id opaque SessionID <0..32> 1 cipher_suite uint8 CipherSuite[2] 2 N/A compression_met hod null(0) 1 N/A extensions extension_type, extension_data<0..2^16-1> <0..2^16-1> 2 バイト分 Record Layer(5bytes) Handshake (ServerHello) type protocol version length (2bytes) msg type length (3byte) server version major minor major minor random 32bytes session id cipher suite 2bytes compression 0x16 0x03 0x03? + 4 0x01? 0x03 0x03? 長さ 1byte 0x00,0x9c 長さ 2bytes

DataReader を使う https://github.com/shigeki/seccamp2015-data-reader データを読み込む Helper オブジェクト var DataReader = require('seccamp2015-data-reader').datareader; var reader = new DataReader(buffer); API reader.readbytes(n): 前回読み込んだ位置から n バイト分のデータをバッファで返す reader. readvector(floor, ceiling): 可変ベクターのデータを読み込み バッファで返す (floor: 最小値 ceiling: 最大値 ) reader. peekbytes(from, n): from 個目から to 個目までのバッファをコピーして返す reader. bytesremaining(): 残っているバイトサイズを返す

演習 : Record Header を見る function parserecordheader(reader) { var type = reader.readbytes(1).readuint8(0); var version = reader.readbytes(2); var length = reader.readbytes(2).readuintbe(0, 2); return {type: type, version: version, length: length}; } Record Layer type (1byte) protocol version length (2bytes) major (1byte) minor (1byte)

演習 ServerHello を見る https://gist.github.com/shigeki/67c35e12b0834fca3821 function parseserverhello(reader) { var record_header = parserecordheader(reader); var type = reader.readbytes(1).readuint8(0); var length = reader.readbytes(3).readuintbe(0, 3); var version = reader.readbytes(2); var random = reader.readbytes(32); var session_id = reader.readvector(0, 32); var cipher = reader.readbytes(2); var compression = reader.readbytes(1); return { record_header: record_header, type: type, length: length, version: version, random: random, session_id: session_id, cipher: cipher, compression: compression }; } Handshake (ServerHello) msg type length (3byte) major server version minor random 32bytes session id cipher suite 2bytes compression

Certificate 最大値のみ 3 バイト分 opaque ASN.1Cert<2^24-1>; struct { 3 バイト分 ASN.1Cert certificate_list<0..2^24-1>; } Certificate; 複数の証明書データを送付 項目要素サイズ certificate_list ASN.1Cert<2^24-1> <0..2^24-1> 全証明書長証明書 #1 長証明書データ #1 証明書 #2 長証明書データ #2 最初は必ずサーバ証明書 2 つ目以降は中間証明書など

ここから先の演習は状態管理が必要 はじめに使った simple_tls_client.js を使います モジュールのインストール $npm install seccamp2015-data-reader seccamp2015-tls Simple TLS Client (simple_tls_client.js) の取得 $git clone https://github.com/shigeki/seccamp2015-tls $cd SecCamp2015-TLS $node simple_tls_client.js キーボードを打ってみよう ( 注 : エラー処理やサニタイジングが十分でないのであくまでテスト用で利用すること )

演習 Certificate を見る https://github.com/shigeki/seccamp2015-tls/blob/master/index.js function parsecertificate(reader, state) { if (!checkrecordheader(reader)) return null; var record_header = parserecordheader(reader); storehandshakedata(reader, record_header.length, state); var type = reader.readbytes(1).readuint8(0); var length = reader.readbytes(3).readuintbe(0, 3); var cert_reader = new DataReader(reader.readBytes(length)); var certlist = []; while(cert_reader.bytesremaining() > 0) { var cert = cert_reader.readvector(0, 1 << 24-1); certlist.push(cert); 3バイト分 } 証明書はリストに格納 return { record_header: record_header, type: type, length: length, certlist: certlist }; }

ServerKeyExchange RSA 鍵交換では不要 今の時点じゃスキップします ECDHE のところで再度説明します

ServerHelloDone struct { } ServerHelloDone; ServerHello の終了の合図ハンドシェイクヘッダのみ handshake type handshake 長 0x0e 0x00 0x00 0x00

ClientKeyExchange struct { select (KeyExchangeAlgorithm) { case rsa: EncryptedPreMasterSecret; case dhe_dss: case dhe_rsa: case dh_dss: case dh_rsa: case dh_anon: ClientDiffieHellmanPublic; } exchange_keys; } ClientKeyExchange; 鍵交換のアルゴリズムによって異なる RSA による鍵交換では暗号化された PreMasterSecret を送る DH/DHE による鍵交換ではクライアントの公開鍵を送る

ClientKeyExchange (RSA 鍵交換の場合 ) struct { ProtocolVersion client_version; opaque random[46]; } PreMasterSecret; struct { public-key-encrypted PreMasterSecret pre_master_secret; } EncryptedPreMasterSecret; エラー処理が脆弱性がなる場合もある 通常は証明書に記載されている RSA 公開鍵で pre_master_secret を暗号化 ClientHello で送付したバージョン <0..2^16-1> の可変ベクター

ClientKeyExchange (RSA 鍵交換の場合 ) PreMasterSecret client version random 46bytes major 0x03 minor 0x01 Record Layer(5bytes) Handshake(ClientKeyExchange) type protocol version length (2bytes) msg type length (3byte) Encrypted PreMasterSecret major minor 0x16 0x03 0x03? + 4 0x10? 長さ 2 バイト?

TLS の鍵生成の流れ pre master secret ( 任意のバイト数 : 鍵交換による ) サーバ クライアント間の鍵交換方式で生成し 秘密的に共有する master secret (48 bytes) PRF(pre_master_secret, "master secret", client_random+server_random) keyblock ( 任意のバイト数 : 利用暗号方式による ) PRF(master_secret, "key expansion", server_random+client_random) client_write_mac server_write_mac client_write_key server_write_key client_write_iv server_write_iv

PreMasterSecret/MasterSecret TLS で利用する IV( 初期ベクトル ) 共有鍵 MAC 鍵のデータ元 MasterSecret は 48 バイト長 PreMasterSecret の長さは鍵交換方式に依存する MasterSecret は PreMasterSecret ClientRandom ServerRandom 固定ラベルから生成する Clinet/ServerRandom は全て丸見え PreMasterSecret は 必ず死守して守らないといけない これが漏えいすると TLS の安全性は全ておじゃん

演習 :PreMasterSecret の計算 TLS1.2 の RSA 鍵交換時 function createpremastersecretrsakeyexchange(state) { var pre_master_secret = ( ここを作る ) } return pre_master_secret;

演習答え :PreMasterSecret の計算 TLS1.2 の RSA 鍵交換時 (48 バイト ) function createpremastersecretrsakeyexchange(state) { var version = new Buffer('0303', 'hex'); } var pre_master_secret = Buffer.concat([version, crypto.randombytes(46)]); return pre_master_secret; ClientHello で送った Version 2 バイト分 残り 46 バイトは乱数で発生させる

演習 : ClientKeyExchange を作る var clientkeyexchange_json = { }; pre_master_secret: pre_master_secret, pubkey: require('fs').readfilesync( dirname + '/pubkey.pem') var clientkeyexchange = createclientkeyexchange(clientkeyexchange_json, state); 公開鍵情報は 本当は Certificate データから抽出する パーサーが必要なので別ファイルから読み込む function createclientkeyexchange(json, state) { state.handshake.clientkeyexchange_json = json; var public_key = json.pubkey; var pre_master_secret = json.pre_master_secret; var encrypted = crypto.publicencrypt({ key: public_key, 公開鍵で pre_master_secret を暗号化 padding: require('constants').rsa_pkcs1_padding }, pre_master_secret); var encrypted_pre_master_secret = writevector(encrypted, 0, 1 << 16-1); var handshake = createhandshake(handshake_type.clientkeyexchange, encrypted_pre_master_secret); return createrecord(type.handshake, handshake); };

MasterSecret の計算その 1: P_hash PreMasterSecret のサイズは 鍵交換方式で異なる MasterSecret は 48 バイト必要 P_hash: データ拡張関数 ある secret を必要なサイズまで伸長させる P_hash(secret, seed) = HMAC_hash(secret, A(1)+seed) + HMAC_hash(secret, A(2)+seed) +. ( 必要なサイズまで伸長 ) A(0) = seed; A(i) = HMAC_hash(secret, A(i-1)) + はデータの結合を表す HMAC_hash のアルゴリズムは TLS1.2 では SHA256 を使う ( それ以前は MD5/SHA-1 の組み合わせ )

演習 : TLS1.2 の P_hash を作る var crypto = require('crypto'); var P_hash = require('seccamp2015-tls').p_hash; var algo = 'sha256'; var secret = 'mysecret'; var seed = (new Buffer(32)).fill(0); var size = 48; function MyP_hash(algo, secret, seed, size) { var ret = new Buffer(size); ( ここを作る ) return ret; } var answer = P_hash(algo, secret, seed, size); var my_answer = MyP_hash(algo, secret, seed, size); console.log(answer); console.log(my_answer); console.log(answer.equals(my_answer));

演習 : 答え HMAC_hash(secret, A(i)+seed) サイズ分まで結合する次のA(i) を計算 function MyP_hash(algo, secret, seed, size) { var ret = new Buffer(size); var hmac = crypto.createhmac(algo, secret); hmac.update(seed); A(0) はseed var a = hmac.digest(); // A(1) var end = 0; A(1) を計算 while(size > end) { hmac = crypto.createhmac(algo, secret); hmac.update(buffer.concat([a, seed])); var b = hmac.digest(); var len = (size - end >= b.length)? b.length: size - end; b.copy(ret, end, 0, len); end += len; hmac = crypto.createhmac(algo, secret); hmac.update(a); a = hmac.digest(); // A(i+1) } return ret; }

MasterSecret の計算その 2 PRF(PseudoRandom Function) PRF(secret, label, seed) = P_hash(secret, label + seed) master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) [0..47]; 48 バイトまで計算 固定ラベル = P_hash(pre_master_secret, "master secret" + ClientHello.random +ServerHello.random)[0..47] 重要 :PRFはTLSで他にも様々な要素の計算に用いられます

演習 : TLS1.2 master_secret を計算する var crypto = require('crypto'); var PRF12 = require('seccamp2015-tls').prf12; var pre_master_secret = crypto.randombytes(48); var client_random = crypto.randombytes(32); var server_random = crypto.randombytes(32); label と seed を結合して新しい seed を生成 function MyPRF12(secret, label, seed, size) { return MyP_hash('sha256', secret, Buffer.concat([label, seed]), size); } ラベルは master secret master_secret は 48 バイト var label = new Buffer("master secret"); var master_secret = PRF12(pre_master_secret, label, Buffer.concat([client_random, server_random]), 48); var Mymaster_secret = MyPRF12(pre_master_secret, label, Buffer.concat([client_random, server_random]), 48); console.log(master_secret); console.log(mymaster_secret); console.log(master_secret.equals(mymaster_secret));

KeyExpansion TLS で必要な鍵は MAC 用 共有鍵用 初期ベクトル (IV) 用の 3 種類 Client/Server それぞれが必要なので 6 つ必要 それぞれで必要なサイズは暗号方式で異なる TLS で必要な鍵は 48 バイトの MasterSecret では サイズが足りない MasterSecret から PRF で必要なサイズの key_block に伸長させる master_secret(48 バイト ) 注意!:master_secret の計算時と順番が逆 key_block = PRF(master_secret, "key expansion", server_random + client_random); client_write_mac server_write_mac client_write_key server_write_key client_write_iv server_write_iv

KeyExpansion(AES-128-GCM) client_write_mac, server_write_mac: 0バイトx2 (AEADはMAC 不要 ) client_write_key, server_write_key: 16バイトx2 (128bits 鍵長 ) client_write_iv, server_write_iv: 4バイトx2 (12バイト中の頭 後述) 合計 : 40バイト key_block = PRF12(algo, master_secret, "key expansion", ServerHello.random+ClientHello.random, 40); 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 client_write_key(16bytes) server_write_key(16bytes) client_write _IV(4bytes) server_write _IV(4bytes)

演習 :KeyBlock の計算 function KDF(pre_master_secret, client_random, server_random) { var master_secret = PRF12(pre_master_secret, "master secret", Buffer.concat([client_random, server_random]), 48); // 40 bytes key_block for AES-128-GCM var key_block_reader = new DataReader( ラベルは key expansion PRF12(master_secret, "key expansion", Buffer.concat([server_random, client_random]), 40)); AES-128-GCM は 40 バイト分必要 return { } }; master_secret: master_secret, client_write_mac_key: null, server_write_mac_key: null, client_write_key: key_block_reader.readbytes(16), server_write_key: key_block_reader.readbytes(16), client_write_iv: key_block_reader.readbytes(4), server_write_iv: key_block_reader.readbytes(4) GCM は MAC はいらない 結合の順番が反対 AES-128 の秘密鍵は 16 バイト 初期ベクトルの最初の 4 バイト分は両者で秘密共有 残り 8 バイトはフレームに付加して送る

ChangeCipherSpec struct { enum { change_cipher_spec(1), (255) } type; } ChangeCipherSpec; 送信元が暗号開始を宣言 これを送信した後は暗号通信を行う Record Layer ChangeCipherSpec ContentType Version length major minor (2byte) 0x14 0x03 0x03 0x00 0x01 0x01

Finished struct { opaque verify_data[verify_data_length]; } Finished; 12 バイト固定 これまでのハンドシェイクデータ ( ただし自分は除く ) のハッシュを計算 TLS1.2 では SHA256 を使う verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))[0..11]; finished_label: クライアントは "client finished" サーバは "server finished" Finished を受信すると これまで送受信したハンドシェイクデータから計算した値と比較 ハンドシェイクデータが改ざんされてないことを確認する

Finished を作る var clientfinished = { master_secret: state.keyblock.master_secret, handshake_message_list: state.handshake_message_list }; var clientfinished = createclientfinished(clientfinished, state); これまで交換したハンドシェイクデータのリスト function createclientfinished(json, state) { state.handshake.clientfinished = json; これまで交換したハンドシェイクデータの // create session hash ハッシュ値を求める var shasum = crypto.createhash('sha256'); shasum.update(buffer.concat(json.handshake_message_list)); var message_hash = shasum.digest(); var r = PRF12(json.master_secret, "client finished", message_hash, 12); var handshake = createhandshake(handshake_type.finished, r); return createrecord(type.handshake, handshake); フレーム作 } 成後暗号化 PRF で 12 バイト分に切り詰める 受信した Finished 中の値と比較して改ざんチェック

データの暗号化 struct { ContentType type; ProtocolVersion version; uint16 length; select (SecurityParameters.cipher_type) { case stream: GenericStreamCipher; case block: GenericBlockCipher; case aead: GenericAEADCipher; } fragment; } TLSCiphertext; Record Layer レコードフィールド 暗号化した後の長さ ContentType Version length major minor (2byte) ストリーム暗号 ブロック暗号 AEAD で構造が変わる 暗号化されたデータ 0x03 0x03..

データの暗号化 (AEAD) struct { opaque nonce_explicit[record_iv_length]; aead-ciphered struct { }; opaque content[tlscompressed.length]; } GenericAEADCipher; key block から生成した 4bytes struct { opaque salt[4]; opaque nonce_explicit[8]; } GCMNonce; 毎回生成する乱数 (8bytes 丸見え ) 認証データ TLS レコード層の情報 additional_data = seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length; uint16 0 から始まる 暗号化する前の長さ AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext, additional_data)

AEAD(AES-128-GCM) で暗号化されたデータ Cont entty pe Record Header major Version minor length (2byte) explicit nonce (8 byte) 暗号化されたデータ tag (16 bytes) 0x03 0x03 explicit nonce 暗号データ tag を合わせた長さに再計算 AAD writeseq + Record Header 暗号化する平文 初期ベクトル writeiv(4bytes) + explicit nonce(8bytes) AES-128-GCM write_key 暗号化されたデータ tag

アプリケーションデータの暗号化 function EncryptAEAD(frame, state) { var key = state.keyblock.client_write_key; var iv = Buffer.concat([state.keyblock.client_write_IV.slice(0,4), state.nonce_explicit]); var record_header = frame.slice(0, 5); var aad = Buffer.concat([state.write_seq, record_header]); var ret = Encrypt(frame.slice(5), key, iv, aad); var encrypted = ret.encrypted; var tag = ret.tag; 初期ベクトルは write_iv(4) と explicit nonce を合わせたもの // re-calcuate length with adding nonce_explit and tag length var length = state.nonce_explicit.length + encrypted.length + tag.length; record_header.writeuintbe(length, 3, 2); record 長の再計算 // increment write sequence number incseq(state.write_seq); sequence no を増加 return Buffer.concat([record_header, state.nonce_explicit, encrypted, tag]); }

秘密鍵漏洩の脅威 TLS_RSA_WITH_AES_128_GCM_SHA256 は 鍵交換 署名に RSA を利用している 通信経路に pre_master_secret を暗号化して相手に送信 公開鍵 秘密鍵共に長期に固定化されている 暗号強度が低い又は秘密鍵が漏えいしてしまうとどうなるか?

演習 : TLS を破る 時間があれば行います サーバの秘密鍵をお渡しします 秘密鍵とハンドシェイクデータから暗号化されたアプリ通信を解読する

演習 : TLS を破る https://github.com/shigeki/seccamp2015-tls/tree/master/break_tls 秘密鍵のパスワードは口頭でお伝えします 戻し方 $ openssl rsa -in server_encrypted.key -out server.key Enter pass phrase for server_encrypted.key: writing RSA key 秘密鍵と handshake.json のデータから暗号化された Application Data を復号してください

演習回答 : Client/Server Random の取得 Record Layer Handshake (ClientHello) type protocol version length (2byte) msg type length (3byte) client version random session id cipher suite compr ession Extensi on major minor major minor 0x16 0x03 0x01???? 0x01?????? 0x03 0x03 32 byte 可変可変可変可変 type Record Layer(5bytes) protocol version 5+4+2=11bytes 先から 32byte 暗号化された pre master secret の取得 major minor length (2bytes) msg type length (3byte) Handshake(ClientKeyExchange) Encrypted PreMasterSecret 0x16 0x03 0x03? + 4 0x10? 長さ 2 バイト? 5+4+2=11bytes 先から最後まで 秘密鍵で復号化

演習回答 : ここを復号化して平文をゲットする Cont entty pe Record Header major Version minor length (2byte) explicit nonce (8 byte) 暗号化されたデータ tag (16 bytes) 0x03 0x03 sequence no と合わせて AAD ただし長さは再計算が必要 writeiv と合わせて IV 復号化でセットするタグ値

演習回答 :solve.js var DataReader = require('seccamp2015-data-reader').datareader; var SecCampTLS = require('seccamp2015-tls'); var fs = require('fs'), crypto = require('crypto'); var handshake = require( dirname + '/handshake.json'); var clienthello = new Buffer(handshake.ClientHello, 'hex'); var serverhello = new Buffer(handshake.ServerHello, 'hex'); var clientkeyexchange = new Buffer(handshake.ClientKeyExchange, 'hex'); var encryptedapplicationdata = new Buffer(handshake.EncryptedApplicationData, 'hex'); // obtain handshake parameters var client_random = clienthello.slice(11, 11+32); var server_random = serverhello.slice(11, 11+32); var encrypted_pre_master_secret = clientkeyexchange.slice(11); // obtain private key var private_key = fs.readfilesync( dirname + '/server.key'); JSON データからハンドシェイクデータを抽出 ハンドシェイクパラメータを抽出 秘密鍵の入手

演習回答 : // decrypt pre master secret var pre_master_secret = crypto.privatedecrypt( {key: private_key, padding: require('constants').rsa_pkcs1_padding }, encrypted_pre_master_secret); // objtain keyblock 秘密鍵を使って ClientKeyExchange で暗号化された pre master secret の復号化 pre master secret と client/server random を使って key block を生成 var keyblock = SecCampTLS.KDF(pre_master_secret, client_random, server_random); // Calculate Sequence Number var read_seq = (new Buffer(8)).fill(0); read_seq[7] = 0x01; sequence number を生成

演習回答 : var reader = new DataReader(encryptedApplicationData); // Obtain AEAD parameters var record_header = reader.readbytes(5); var length = record_header.readuintbe(3, 2); var frame = reader.readbytes(length); var nonce_explicit = frame.slice(0, 8); var encrypted = frame.slice(8, frame.length - 16); var tag = frame.slice(-16); // Re-Caluclate record header record_header.writeuintbe(encrypted.length, 3, 2); record header の長さ再計算 暗号化されたアプリケーションデータから AEAD パラメータを抽出する var iv = Buffer.concat([keyblock.client_write_IV, nonce_explicit]); var aad = Buffer.concat([read_seq, record_header]);

演習回答 : // Decrypt Application Data var decipher = crypto.createdecipheriv('aes-128-gcm', keyblock.client_write_key, iv); decipher.setauthtag(tag); decipher.setaad(aad); var clear = decipher.update(encrypted); decipher.final(); console.log(clear.tostring()); これまで得られたパラメータからデータの復号化 平文の取得

Perfect Forward Secrecy TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 を使う

Perfect Forward Secrecy(PFS) 前方秘匿性 セッション毎に一時的な鍵を使う ハンドシェイクを含む全暗号データを取得されているような状況でも 将来的な秘密鍵漏洩などのリスクに対応する TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Ephemeral: 一時的な鍵交換手法

ECDHE のハンドシェイク ClientHello 拡張を追加 Client の公開鍵を送付 ClientHello + elliptic_curves(10) + ec_point_formats(11) ClientKeyExchange ChangeCipherSpec Finished 使える楕円曲線名と ECPoint 書式を通知 ECPoint の書式を合意 Application Data ServerHello + ec_point_formats(11) Certificate ServerKeyExchange ServerHelloDone ChangeCipherSpec Finished ServerHello 拡張を追加 楕円曲線名と Server の公開鍵を署名付きで送付 ( 赤文字が追加変更されるところ )

ECDHE ClientHello 拡張 struct { NamedCurve elliptic_curve_list<1..2^16-1> } EllipticCurveList; enum { sect163k1 (1), 省略, secp256r1 (23), 省略, (0xFFFF) } NamedCurve; クライアントがサポートしている楕円曲線のリストをサーバ側に通知 サーバはリストの中から適切な楕円曲線を選び ServerKeyExchange 内で選択した楕円曲線を通知する 0 1 2 3 4 5 6 7 elliptic_curves(10) リスト長データ長 secp256r1 (23) 0x00 0x0a 0x00 0x04 0x00 0x02 0x00 0x17

ECDHE Client/Server Hello 拡張 enum { uncompressed (0), 省略, reserved (248..255) } ECPointFormat; struct { 楕円暗号の公開鍵の書式 ECPointFormat ec_point_format_list<1..2^8-1> } ECPointFormatList; 0 1 2 3 4 5 ec_point_formats(11) リスト長データ長 uncompressed(0) 0x00 0x0b 0x00 0x02 0x01 0x00

ECDHE ServerKeyExchange select (KeyExchangeAlgorithm) { case ec_diffie_hellman: ServerECDHParams params; Signature signed_params; } ServerKeyExchange; struct { ECParameters curve_params; ECPoint public; } ServerECDHParams; struct { SignatureAndHashAlgorithm algorithm; opaque signature<0..2^16-1>; } DigitallySigned; RSA 秘密鍵で ServerECDHParms と Random を署名 ServerECDHParams ECParameters ECPoint algorithm curve_type named_curve 長さ public key named_curve (3) secp256r1 (23) (Hello 拡張指定の書式 ) RSA-SHA256 (0x04,0x01) Signature signature signature = sign(algorithm, ClientHello.random + ServerHello.random + ServerECDHParams);

ECDHE ClientKeyExchange struct { select (KeyExchangeAlgorithm) { case ec_diffie_hellman: ClientECDiffieHellmanPublic; } exchange_keys; } ClientKeyExchange; ECDHEは explicit struct { select (PublicValueEncoding) { case implicit: struct { }; case explicit: ECPoint ecdh_yc; } ecdh_public; } ClientECDiffieHellmanPublic; 長さ ClientECDHParams ECPoint public key (Hello 拡張指定の書式 ) ClientKeyExchange は署名の必要はない

演習 : ECDHE 公開鍵の守られ方の違い ServerKeyExchange: 公開鍵を署名 ClientKeyExchange: やりたい放題 どうしてでしょう?

TLS 最新情報 TLS1.3(*) とはどういうものか? (* 注 : 2015-7-23 時点のものです 最終仕様で変更になる可能性があります )

TLS1.3(*) の背景 2008 年 TLS1.2 仕様化から 7 年 古い暗号やプロトコルの危殆化に伴う機能の抜本的な見直し 常時 TLS 化を目指し 将来的に安心で強固なセキュリティの必要性 モバイル環境の普及や Web アプリの高度化に伴う高パフォーマンス 低レイテンシー化要望の高まり

TLS1.3 の目的 1. ハンドシェイクデータをできるだけ暗号化して隠匿する 2. ハンドシェイクレイテンシーの削減 再接続の場合は 0-RTT フルハンドシェイクは 1-RTT 3. ハンドシェイクで交換する項目の見直し 4. レコード層暗号化の見直し (RC4 廃止 CBC の不採用 )

TLS1.3 の構造 (*) Alert ( タイプ :0x15) レベル 理由 ChangeCipherSpec を廃止 I P ヘッダ T C P ヘッダ タイプ (4 種類 ) (1byte) TLS Record Layer (5 バイト ) バージョン 0x0301 に固定 (2byte) 長さ (2byte) msg タイプ (10 種類 ) Handshake ( タイプ :0x16) 長さ Application Data ( タイプ :0x17) 暗号化されたデータ ハンドシェイクデータ msg タイプ ハンドシェイクデータの種類 0x00 reserved( 旧 HelloRequest 廃止 ) Extens ion ID 0x00d TBD TBD TBD TBD TBD Extension signature_algorithms early_data supported_groups known_configration pre_shared_key client_key_shares Early Handshake ( タイプ :0x19) msg タイプ長さハンドシェイクデータ TLS Handshake は この 12 種類に増加 後方互換のため 3 つは予約 (* 注 : 2015-7-20 時点のものです 最終仕様で変更になる可能性があります ) 0x01 0x02 0x04 0x06 0x07 0x0b ClientHello ServerHello NewSessionTicket HelloRetryRequest ServerKeyShare Certificate 0x0c reserved( 旧 ServerKeyExchange 廃止 ) 0x0d 0x0e 0x0f CertificateRequest ServerConfigration CertificateVerify 0x10 reserved( 旧 ClientKeyExchange 廃止 ) 0x14 Finished

TLS1.3 ハンドシェイク (full handshake) ClientHello + ClientKeyShare Finished Application Data Application Data ここで即暗号化 ServerHello ServerKeyShare EncryptedExtensions ServerConfigration Certificate Finished Application Data 1-RTT ( 赤文字は暗号化されているデータ )

TLS1.3 ハンドシェイク ( 鍵交換ができなかった時 ) ClientHello + ClientKeyShare ClientHello + ClientKeyShare Finished Application Data Application Data HelloRetryRequest ServerHello ServerKeyShare EncryptedExtensions ServerConfigration Certificate Finished Application Data ここで即暗号化 2-RTT ( 赤文字は暗号化されているデータ )

TLS1.3 ハンドシェイク ( 再接続 ) 以前のサーバ公開鍵と組み合わせてフライイングでアプリデータ暗号化して送る ClientHello + ClientKeyShare + KnownConfigration + EarlyDataIndication ApplicationData Finished ServerHello + KnownConfigration + EarlyDataIndication ServerKeyShare Finished Application Data Application Data 0-RTT ( 赤文字は暗号化されているデータ )

TLS1.3 0-RTT の問題点 0-RTT ApplicationData POST / HTTP/1.1 xxxx Reply 攻撃 更新 クラスタリング厳密な同期は不可能 0-RTT ApplicationData POST / HTTP/1.1 xxxx 更新 Reply 攻撃に弱いため 最初のデータは冪等性のあるリクエストのみに制限しなければならない

TLS1.3 鍵生成 (Server view) DH or ECDH 鍵交換 ClientPubKey Server SecretKey in ClientKeyShare Client PubKey in ClientKeyShare DH or ECDH 鍵交換 Server SecretKey in KnownConfigration Ephemeral Secret Static Secret 以前に送付した古いの 最初なら鍵生成したもの HKDF xes xss HKDF HKDF(label + session_hash) HKDF key HKDF seed Master Secret Handshake Traffic Keys ハンドシェイク暗号化用 Exporter Secret Resumption Secret Application Finished Traffic Keys Secret アプリデータ暗号化用 Finished 用 Early Data Traffic Keys

TSL1.3 変更点まとめ (*) Compression, Renegotiationの廃止 ChangeCipherSpec 廃止 ClientKeyExchange 廃止してClientHelloの拡張フィールドに HelloRequest/ServerHello 廃止 Record 層のバージョンを 0x03,0x03(TLS1.0) に固定 ServerConfigrationをクライアントに渡し 0-RTT 接続を実現 ServerKeyShare 後即暗号化 証明書データも隠匿 乱数から時間の gmt フィールド廃止 (* 注 : 2015-7-23 時点のものです 最終仕様で変更になる可能性があります )

TSL1.3 変更点まとめ (*) 鍵交換は名前付き DH,ECDH で ephemeral 利用のみ 鍵生成は HKDF 利用に変更 Ephemeral/Static の 2 種類の secret から session_hash を付けて各用途別に生成 暗号モードで利用できるのは AEAD のみ (GCM, CCM, Poly1305) AEAD の初期ベクタ廃止 Record 層の Length を AEAD で認証外に 他にも色々 (* 注 : 2015-7-23 時点のものです 最終仕様で変更になる可能性があります )