プライマリ・コンテンツに移動
Java Platform, Standard Editionセキュリティ開発者ガイド
リリース9
E91919-01
目次へ移動
目次

前
次
次へ

8 Java Secure Socket Extension (JSSE)リファレンス・ガイド

Java Secure Socket Extension (JSSE)により、セキュアなインターネット通信が可能になります。これは、JavaバージョンのSSL、TLSおよびDTLSプロトコルのフレームワークおよび実装を提供し、データ暗号化、サーバー認証、メッセージの整合性の他、オプションでクライアント認証の機能を含んでいます。

JSSEの概要

ネットワークを通じてやり取りされるデータには、意図された受信者以外の人も、簡単にアクセスできます。データにパスワードやクレジット・カード番号などの個人情報が含まれる場合、権限のない者がデータを理解できないよう、手段を講じる必要があります。また、意図的であるかどうかにかかわらず、通信中にデータが変更されていないことを確認することも重要です。Secure Sockets Layer (SSL)およびTransport Layer Security (TLS)は、ネットワークを通じたデータの送信時に、データの機密性および整合性を保護するために設計されたプロトコルです。

Java Secure Socket Extension (JSSE)により、セキュアなインターネット通信が可能になります。これにより、JavaバージョンのSSLおよびTLSプロトコルのフレームワークおよび実装が提供されます。また、データ暗号化、サーバー認証、メッセージの整合性の他、オプションでクライアント認証の機能が含まれます。JSSEを使用すると、開発者はHTTP、Telnet、FTPなど、TCP/IP上のアプリケーション・プロトコルを実行するクライアントとサーバーの間で、セキュアなデータのやり取りを実現できます。SSLの概要については、「Secure Sockets Layer (SSL)プロトコルの概要」を参照してください。

JSSEは、基盤となる複雑なセキュリティ・アルゴリズムやハンドシェーク・メカニズムを抽象化することにより、識別するのが難しく、しかし危険なセキュリティ上の弱点が生まれるリスクを最小限に抑えます。また、開発者がそれをアプリケーションに直接統合できる構築ブロックとして使用すると、アプリケーション開発が簡単になります。

JSSEは、アプリケーション・プログラミング・インタフェース(API)フレームワークと、そのAPIの実装を提供します。JSSE APIは、java.securityおよびjava.netパッケージによって定義されたコア・ネットワークおよび暗号化サービスを補い、拡張されたネットワーク・ソケット・クラス、トラスト・マネージャ、キー・マネージャ、SSLコンテキストおよびソケット作成動作をカプセル化するソケット・ファクトリのフレームワークを提供します。SSLSocketクラスはブロック入出力モデルに基づいているため、Java Development Kit (JDK)には、実装で独自の入出力メソッドを選択できるようにするために非ブロックSSLEngine クラスが含まれます。

JSSE APIでは、次のセキュリティ・プロトコルがサポートされています。

  • SSL: バージョン3.0

  • TLS: バージョン1.0、1.1および1.2

  • DTLS: バージョン1.0および1.2

これらのセキュリティ・プロトコルは、通常の双方向のストリーム・ソケットをカプセル化し、JSSE APIは認証、暗号化および整合性保護の透過的なサポートを追加します。JDKに付属のJSSE実装ではSSL 2.0は実装されないことに注意してください。

JSSEはJava SEプラットフォームのセキュリティ・コンポーネントであり、Java暗号化アーキテクチャ(JCA)リファレンス・ガイドのフレームワーク内の至るところで見られる同じ設計方針に基づいています。暗号化に関するセキュリティ・コンポーネントのこのフレームワークにより、実装の独立性と、可能な場合にはアルゴリズムの独立性を実現できます。JSSEはJCAフレームワークによって定義された暗号化サービス・プロバイダを使用します。

Java SEプラットフォーム内の他のセキュリティ・コンポーネントには、Java Authentication and Authorization Service (JAAS)リファレンス・ガイドおよびJavaセキュリティ・ツールがあります。JSSEはJCAと同じ概念およびアルゴリズムを多く含んでいますが、単純なストリーム・ソケットAPIの下でこれらを自動的に適用します。

JSSE APIは、その他のSSL/TLS/DTLSプロトコルと公開鍵インフラストラクチャ(PKI)実装をシームレスにプラグインできる設計になっています。開発者が、リモート・ホストの信頼性やリモート・ホストに送信する認証鍵データを決定するロジックを提供することもできます。

JSSEの特長と利点

JSSEには、次のような重要な利点と特長があります。

  • JDKの標準のコンポーネントとして含まれている
  • 拡張可能なプロバイダ・ベースのアーキテクチャ
  • 100% Pure Javaに実装される
  • SSL/TLS/DTLSのAPIサポートを提供する
  • SSL 3.0、TLS (バージョン1.0、1.1および1.2)およびDTLS (バージョン1.0および1.2)の実装を提供する
  • セキュアなチャネルを作成するためにインスタンス化可能なクラスを含む(SSLSocketSSLServerSocket、およびSSLEngine)
  • セキュアな通信を開始または検証するのに使用されるSSL/TLS/DTLSハンドシェーク機能の一部として、暗号群ネゴシエーションをサポートする
  • 通常のSSL/TLS/DTLSハンドシェーク機能の一部として、クライアントとサーバーの認証をサポートする
  • SSL/TLSプロトコルでカプセル化されたHTTPをサポートし、これにより、HTTPSを使用するWebページなどのデータにアクセスできる
  • メモリー常駐型のSSLセッションを管理するためのサーバー・セッション管理APIを提供する
  • サーバー名指定拡張機能をサポートする。これにより、仮想サーバーとのセキュアな接続が容易になります。
  • 証明書ステータス要求拡張機能(OCSPステープリング)をサポートする。これにより、クライアント証明書の検証のラウンドトリップおよびリソースが節約されます。
  • Server Name Indication (SNI)拡張機能をサポートする。これにより、ハンドシェーク時にクライアントが接続を試みているサーバーの名前を示すようSSL/TLS/DTLSプロトコルが拡張されます。
  • ハンドシェーク時のエンドポイント識別をサポートする。これにより、介入者攻撃を防ぐことができます。
  • 暗号化アルゴリズム制約をサポートする。これにより、JSSEによってネゴシエーションされたアルゴリズムを、詳細に管理できるようになります。

JSSEは、次の暗号化アルゴリズムを使用します。

表8-1 JSSEで使用される暗号化アルゴリズム

暗号化機能 暗号化アルゴリズム脚注1 鍵の長さ(ビット)脚注2
バルク暗号化 Advanced Encryption Standard(AES) 256脚注3

128

バルク暗号化 データ暗号化規格(DES) 64 (56が有効)

64 (40が有効)

バルク暗号化 Rivest Cipher 4 (RC4) 128

128 (40が有効)

バルク暗号化 トリプルDES (3DES) 192 (112が有効)
ハッシュ・アルゴリズム メッセージ・ダイジェスト・アルゴリズム(MD5) 128
ハッシュ・アルゴリズム Secure Hash Algorithm 1 (SHA1) 160
ハッシュ・アルゴリズム Secure Hash Algorithm 224 (SHA224) 224
ハッシュ・アルゴリズム Secure Hash Algorithm 256 (SHA256) 256
ハッシュ・アルゴリズム Secure Hash Algorithm 384 (SHA384) 384
ハッシュ・アルゴリズム Secure Hash Algorithm 512 (SHA512) 512
認証 デジタル署名アルゴリズム(DSA) 1024, 2048, 3072
認証 Elliptic Curve Digital Signature Algorithm 160から512
認証と鍵交換 Rivest-Shamir-Adleman (RSA) 512以上
鍵交換 Static Elliptic Curve Diffie-Hellman (ECDH) 160から512
鍵交換 Ephemeral Elliptic Curve Diffie-Hellman (ECDHE) 160から512
鍵合意 Diffie-Hellman (DH) 512, 768, 1024, 2048, 3072, 4096, 6144, 8192

脚注1 SunJSSE実装では、そのすべての暗号化アルゴリズムでJava暗号化アーキテクチャ(JCA)が使用されています。

脚注2 JSSEプロバイダでは、弱いアルゴリズムおよび弱い鍵は無効化または非アクティブ化される場合があります。

脚注3 AES_256を使用する暗号群では、Java Cryptography Extension (JCE)の無制限強度の適切な管轄ポリシー・ファイル・セットが必要となります。これは、JDKに含まれています。デフォルトでは、アクティブな暗号化ポリシーは、無制限です。暗号強度の構成を参照してください。

JSSEの標準API

JSSE標準APIは、javax.netおよびjavax.net.sslパッケージで利用でき、次を提供します。

  • クライアント側アプリケーションとサーバー側アプリケーションに合わせたセキュア・ソケット。
  • SSL/TLS/DTLSデータのストリームを生成および消費する非ブロック・エンジン(SSLEngine)。
  • ソケット、サーバー・ソケット、SSLソケット、およびSSLサーバー・ソケットを作成するファクトリ。ソケット・ファクトリを使用すると、ソケットの作成および構成動作をカプセル化できます。
  • セキュアなソケット・ファクトリとエンジンのファクトリとして動作するセキュアなソケット・コンテキストを表すクラス。
  • X.509固有のキー・マネージャやトラスト・マネージャなどの鍵およびトラスト・マネージャ・インタフェース、およびそれらのインタフェースを作成するために使用可能なファクトリ。
  • セキュアなHTTP URL接続用のクラス(HTTPS)。

SunJSSEプロバイダ

OracleのJava SEの実装には、SunJSSEという名前のJSSEプロバイダが含まれており、これはあらかじめインストールされ、JCAに登録されています。このプロバイダが提供する暗号化サービスは次のとおりです。

  • SSL 3.0、TLS (バージョン1.0、1.1および1.2)およびDTLS (バージョン1.0および1.2)セキュリティ・プロトコルの実装。
  • 最も一般的なSSL、TLSおよびDTLS暗号群の実装。この実装は、認証、鍵合意、暗号化および整合性保護の組合せを含みます。
  • 標準JCAキーストアから適切な認証鍵を選択するX.509ベースのキー・マネージャの実装。
  • 証明書チェーン・パスを検証する規則を実装する、X.509ベースのトラスト・マネージャの実装。

SunJSSEプロバイダを参照してください。

JSSE関連ドキュメント

次のリストにはオンライン・ドキュメントのリンクと、関連サブジェクトの文書名を示しています。

JSSE APIドキュメント

暗号化

  • 暗号化とセキュリティに関するページ、Ronald L. Rivest博士著(保守されなくなりました)

  • Applied Cryptography』(Bruce Schneier著)、第2版。John Wiley and Sons, Inc.、1996年

  • Cryptography Theory and Practice』(Doug Stinson著)、CRC Press, Inc.、1995年。2005年発行第3版。

  • Cryptography & Network Security: Principles & Practice』(William Stallings著)、Prentice Hall、1998年。2010年発行第5版。

Secure Sockets Layer(SSL)

用語と定義

次に、一般的に使用されている暗号化用語とその定義を示します。

認証

通信している相手側の識別情報を確認するプロセスです。

証明書

デジタル署名付きの文で、あるエンティティ(人や会社など)の識別情報および公開鍵の内容を保証します。証明書は、自己署名されるか証明書発行局(CA)(他のエンティティのために有効な証明書を発行する信頼されているエンティティ)によって発行されます。よく知られているCAには、Comodo、EntrustおよびGoDaddyなどがあります。X509は証明書の一般的な形式であり、JDKのkeytoolで管理できます。

暗号化方式群

暗号化パラメータの組合わせで、認証、鍵合意、暗号化および整合性保護に使用するセキュリティ・アルゴリズムおよび鍵のサイズを定義します。

暗号化ハッシュ関数

データの任意のブロックから比較的小さな固定サイズのビットの文字列(ハッシュと呼ばれる)を生成するために使われるアルゴリズム。暗号化ハッシュ関数はチェックサムに似ており、3つの主な特性があります。一方向の関数であるため、ハッシュからオリジナル・データを生成することはできません。オリジナル・データをわずかに変更しても、結果となるハッシュでは大きな変更になります。暗号化鍵は必要ありません。

暗号化サービス・プロバイダ(CSP)

短縮形としてプロバイダとだけ呼ばれることもあり、Java暗号化アーキテクチャ(JCA)ではそれを、特定の暗号化アルゴリズムの1つまたは複数のエンジン・クラスを実装するパッケージ(または一連のパッケージ)と定義しています。エンジン・クラスは、具体的な実装のない抽象的な方法で暗号化サービスを定義します。

Datagram Transport Layer Security (DTLS)プロトコル

クライアントとサーバーの認証、データ整合性、およびUDPなどの信頼できないトランスポート・チャネルに基づいたクライアントとサーバーとの間の暗号化通信を管理するプロトコルです。

復号化

暗号化/復号化を参照してください。

デジタル署名

デジタル署名とは、手書きの署名のデジタル版です。これは、ネットワークで伝送されるデータが、それを送信したと主張する人物からのものであり、送信中にデータが変更されていないことを保証するものです。たとえば、RSAベースのデジタル署名を計算するには、まずデータの暗号化ハッシュを計算し、次に送信者の非公開鍵でハッシュを暗号化します。

暗号化/複合化

暗号化は複雑なアルゴリズムを使用して、元のメッセージ(クリアテキスト)を、復号化しないかぎり、その内容を理解できないエンコードされたメッセージ(暗号テキスト)に変換するプロセスです。復号化とは、暗号テキストからクリアテキストを生成する逆のプロセスです。

データの暗号化および復号化に使用するアルゴリズムは一般に、秘密鍵(対称)暗号化と公開鍵(非対称)暗号化の2つのカテゴリに分けられます。

エンドポイント識別

ネットワーク上のエンドポイントを識別するために使用されるIPv4アドレスまたはIPv6アドレスです。

エンドポイント識別の手順は、SSL/TLSハンドシェーク中に処理されます。

ハンドシェーク・プロトコル

2つのソケット同士が新しいセッションや既存のセッションの使用に同意するネゴシエーションのフェーズです。ハンドシェーク・プロトコルは、レコード・プロトコルを介して交換される一連のメッセージです。ハンドシェークの終了時に、セッションの接続に固有の暗号化鍵や、整合性を保護するための鍵が、鍵合意による秘密に基づいて新たに生成されます。

java-home

このドキュメント全体でJava Development Kit (JDK)がインストールされているディレクトリを示すために使用される、可変プレースホルダです。

鍵合意

二者が協力して共通鍵を確立するための方法です。それぞれの側が一定のデータを生成して交換します。そのあと、2つのデータが組み合わされて、1つの鍵が生成されます。適正な非公開初期化データを保持しているユーザーのみが、最終的な鍵を取得できます。Diffie-Hellman (DH)は、一般的な鍵合意アルゴリズムの一例です。

鍵交換

鍵を交換する方法です。一方の側が秘密鍵を生成し、標準的にはRSAにより、ピアの公開鍵を使用して暗号化します。データがピアに送信され、ピアは対応する秘密鍵を使用して鍵を復号化します。

キー・マネージャ/トラスト・マネージャ

キー・マネージャとトラスト・マネージャは、それぞれの鍵データにキーストアを使用します。キー・マネージャはキーストアを管理し、ユーザーを他のユーザーに対して承認する場合に使用するなど必要に応じて、他のユーザーに公開鍵を提供します。トラスト・マネージャは、管理するトラストストアの情報に基づいて、トラストの対象者を決定します。

キーストア/トラストストア

キーストアは、鍵データのデータベースです。鍵データにはさまざまな用途があり、それには認証やデータ整合性も含まれます。利用できるキーストアには様々なタイプがあり、その中にはPKCS12やOracleのJKSも含まれます。

一般に、キーストア情報は、鍵エントリと信頼される証明書エントリ2つのカテゴリに分類できます。鍵エントリはエンティティの識別情報とその秘密鍵から構成されており、様々な暗号化の目的で使用できます。これとは対照的に、信頼される証明書のエントリには、公開鍵とそのエンティティの識別情報しか含まれていません。したがって、javax.net.ssl.KeyManagerの場合など、秘密鍵が必要な場合は、信頼される証明書エントリを使用することはできません。JKSのJDK実装では、キーストアに鍵のエントリと、信頼される証明書エントリの両方を含めることができます。

トラストストアとは、トラストの対象を決めるときに使用するキーストアです。すでに信頼しているエンティティからデータを受け取る場合、およびそのエンティティが発信元を名乗るエンティティであることを確認できる場合は、データは実際にそのエンティティから届いたものであると仮定できます。

ユーザーがそのエンティティを信頼する場合にのみ、エントリをトラストストアに追加する必要があります。ユーザーは、鍵のペアを生成するか、証明書をインポートすることにより、そのエントリにトラストを与えます。トラストストア内のすべてのエントリは信頼されたエントリとみなされます。

2つの異なるキーストア・ファイルを持つと便利な場合があります。1つは鍵エントリのみのファイル、もう1つはCA証明書を含む信頼された証明書エントリを含むファイルです。前者には機密性のある情報が含まれますが、後者には含まれません。単独のキーストア・ファイルではなく、2つのファイルを使用すると、独自の証明書(および対応する秘密鍵)と他の証明書を論理的に区別した明確な区分が提供されます。秘密鍵の保護を強化するには、アクセスが制限されたキーストアにそれらを保存し、必要に応じて、より公的にアクセスできるキーストアで信頼される証明書を提供することもできます。

メッセージ認証コード(MAC)

信頼できない媒体に送信または格納された情報の整合性を、秘密鍵に基づいてチェックする方法を提供します。通常、MACは秘密鍵を共有する2つの当事者間で、お互いが送信する情報を検証するために使用されます。

暗号化ハッシュ機能に基づくMACメカニズムは、HMACと呼ばれます。HMACは、共有する秘密鍵と組み合せて、Message Digest 5 (MD5)やSecure Hash Algorithm (SHA-256)などの暗号化ハッシュ関数とともに使用できます。HMACについては、RFC 2104で規定されています。

公開鍵暗号化

2つの鍵を生成する暗号化アルゴリズムを使用する鍵暗号化システムです。一方の鍵は公開されますが、他方は秘密のままです。公開鍵と非公開鍵では、逆の暗号化処理がなされ、一方の鍵で暗号化したものを他方の鍵で復号化します。公開鍵暗号化は、非対称暗号化とも呼ばれます。

レコード・プロトコル

すべてのデータ(アプリケーション・レベルであるかハンドシェーク・プロセスの一部であるかに関係なく)を独立したデータのレコードにパッケージ化するプロトコルで、TCPストリーム・ソケットがアプリケーション・バイト・ストリームをネットワーク・パケットに変換するのとよく似ています。個々のレコードは、現在の暗号化鍵と整合性保護鍵によって保護されます。

秘密鍵暗号化

データの暗号化と復号化に同じ鍵を使用する暗号化アルゴリズムを使用する暗号化システム。秘密鍵暗号化は対称暗号化とも呼ばれます。

Secure Sockets Layer (SSL)プロトコル

クライアントとサーバーの認証、データ整合性、およびクライアントとサーバーとの間の暗号化通信を管理するプロトコルです。

セッション

認証されたピア識別情報、暗号化方式群、鍵合意の秘密を含む名前付きの状態情報のコレクションで、セキュアなソケット・ハンドシェークを通じてネゴシエーションが行われ、複数のセキュアなソケット・インスタンス間で共有できます。

Transport Layer Security (TLS)プロトコル

クライアントとサーバーの認証、データ整合性、およびTCPなどの信頼できるトランスポート・チャネルに基づいたクライアントとサーバーとの間の暗号化通信を管理するプロトコルです。

TLS 1は、SSL 3.0プロトコルの後継です。

トラスト・マネージャ

キー・マネージャ/トラスト・マネージャを参照してください。

トラストストア

キーストア/トラストストアを参照してください。

Secure Sockets Layer (SSL)プロトコルの概要

Secure Sockets Layer (SSL)は、Webで暗号化を実装する場合にもっともよく使用されるプロトコルです。SSLは、ネットワークでセキュアな通信を行うために暗号化プロセスを組み合わせて使用します。このセクションでは、SSLおよびSSLが使用する暗号化プロセスについて簡単に説明します。

SSLは、インターネット通信で使用される標準的なTCP/IPソケットプロトコルをセキュアに拡張します。表8-2に示すように、Secure Sockets Layerは標準TCP/IPプロトコル・スタックのトランスポート層とアプリケーション層の間に追加されます。SSLとともにもっともよく使用されるアプリケーションは、インターネットWebページ用のプロトコルであるHypertext Transfer Protocol (HTTP)です。この他にも、Net News Transfer Protocol (NNTP)、Telnet、Lightweight Directory Access Protocol (LDAP)、Interactive Message Access Protocol (IMAP)、File Transfer Protocol (FTP)などのアプリケーションがあり、同様にSSLとともに使用します。

表8-2 SSLによるTCP/IPプロトコル・スタック

TCP/IPの層 プロトコル
アプリケーション層 HTTP、NNTP、Telnet、FTPなど
Secure Sockets Layer SSL
トランスポート層 TCP
インターネット層 IP

SSLは1994年にNetscape社によって開発され、インターネットの世界で使用されるようになると、標準的な存在になりました。現在では、国際的な標準化機構であるInternet Engineering Task Force (IETF)が管理しています。IETFはSSLの名称をTransport Layer Security (TLS)に変更し、1999年1月に最初の仕様のバージョン1.0をリリースしました。TLS 1.0は、SSLの最新バージョン3.0を少しだけ変更したものです。このアップグレードでは、前のバージョンでの不具合が修正され、既知の弱いアルゴリズムの使用が禁止されました。TLS 1.1は2006年4月にリリースされ、TLS 1.2は2008年8月にリリースされました。

SSLを使用することの利点

次の3つの理由から、機密情報をネットワークで送信する際に危険が伴う場合があります。

  • 通信相手のエンティティが、実際には必ずしも想定する相手とはかぎらない。
  • ネットワーク上のデータは傍受されることがあり、権限のない第三者(場合によっては攻撃者)にデータを読み取られてしまうことがある。
  • データを傍受する攻撃者はデータが受信者に届く前に内容を変更できる可能性があります。

SSLはこれらの各問題に対処します。最初の問題には、認証と呼ばれるプロセスで、通信の当事者双方に相手側の識別情報をオプションで確認させることで対応しています。両者が認証されると、SSLはセキュアなメッセージ伝送のために両者間の暗号化接続を提供します。両者の通信を暗号化することで機密性が保持されるため、2番目の問題に対処します。SSLで使用する暗号化アルゴリズムには、セキュアなハッシュ関数が含まれており、これはチェックサムに似ています。これにより、送信中にデータが変更されていないことが保証されます。セキュアなハッシュ関数により、3番目のデータの整合性の問題に対処します。

注意:

認証も暗号化もオプションであり、2つのエンティティ間のネゴシエーションされた暗号化方式群に依存します。

SSLを使用する場合の明確な例は電子商取引です。電子商取引では、通信するサーバーの識別情報は保証されていると考えるべきではありません。クレジット・カードの番号を入力するだけですばらしいサービスが受けられるという偽のWebサイトを作成するのは簡単なことです。SSLを使うと、クライアントがサーバーの識別情報を認証することができます。また、サーバーもクライアントの情報を認証できますが、インターネット上の取引では、この方法はあまり使われていません。

クライアントとサーバーが互いの情報を認証すると、SSLは暗号化アルゴリズムを使用して機密性とデータの整合性を提供します。これにより、クレジット・カード番号のような機密情報をインターネット上でセキュアに送信することができます。

SSLは認証、機密性およびデータの整合性を提供しますが、非拒否サービスは提供しません。非拒否性とは、メッセージを送信したエンティティは、後で送信を拒否できないということを意味します。メッセージとデジタル署名が関連付けられていると、後になって通信内容を証明することができます。SSL単独では、非拒否性を提供しません。

SSLの仕組み

SSLが有効な理由の1つに、複数の暗号化プロセスを使用していることがあります。SSLは、公開鍵暗号化で認証を行い、秘密鍵暗号化とハッシュ関数で機密性とデータ整合性を提供します。SSLについて理解する前に、暗号化の処理方法を理解しておくと役立ちます。

暗号化処理

暗号化の主な目的は、2者間の秘密の通信に権限のない第三者がアクセスしたり、その内容を理解するのを困難にすることです。暗号化のプロセスによって、データに対する権限のないすべてのアクセスを必ずしも制限できるわけではありませんが、権限のない者が秘密のデータを理解できないようにすることができます。暗号化では、複雑なアルゴリズムを使用して、元のメッセージ(クリアテキスト)をエンコードされたメッセージ(暗号テキスト)に変更します。ネットワーク上で転送されるデータの暗号化および復号化に使用するアルゴリズムは一般に、秘密鍵暗号化と公開鍵暗号化の2つのカテゴリに分けられます。

秘密鍵暗号化も公開鍵暗号化も、合意に基づく暗号鍵または暗号鍵のペアを使用します。鍵は、データの暗号化プロセスおよび復号化プロセスで暗号化アルゴリズムが使用するビット文字列です。暗号化鍵は、錠の鍵と同様、錠を開けることができるのは正しい鍵のみです。

通信の当事者が互いに鍵を安全に送信するのは、些細な問題ではありません。公開鍵証明書を使用すると、公開鍵を安全に送信し、受信者に公開鍵の信頼性を保証できます。公開鍵証明書を参照してください。

秘密鍵暗号化と公開鍵暗号化における暗号化処理の説明では、セキュリティのコミュニティで広く使用されている慣例(通信する2人の当事者はAliceとBobという名前で示される)に従います。権限のない第三者は攻撃者とも呼ばれ、Charlieと名付けられます。

秘密鍵暗号化

秘密鍵暗号化では、通信するAliceとBobはメッセージの暗号化と復号化に同じ鍵を使用します。暗号化されたデータをネットワークで送信する前に、AliceとBobは鍵を持っていることが必要で、暗号化と復号化に使用する暗号化アルゴリズムに同意している必要があります

秘密鍵暗号化で大きな問題の1つが、攻撃者にアクセスされずに一方から他方に鍵を渡す方法の問題です。AliceとBobが秘密鍵暗号化でデータを保護しても、Charlieがその鍵にアクセスできればAliceとBobの間で傍受した秘密メッセージを理解できます。CharlieはAliceとBobのメッセージを復号化できるだけではなく、Aliceになりすまして暗号化データをBobに送信することもできるのです。Bobには、メッセージがCharlieから届いたものかAliceから届いたものかはわかりません。

秘密鍵の配布の問題が解決すれば、秘密鍵暗号化はたいへん貴重なツールになります。そのアルゴリズムにより、優れたセキュリティと暗号化データが比較的迅速に提供できるからです。SSLセッションで送信される機密性の高いデータの多くは、秘密鍵暗号化で送信されます。

秘密鍵暗号化は、データの暗号化と復号化の両方に同じ鍵を使用するため、対称暗号化とも呼ばれます。よく知られている秘密鍵暗号化アルゴリズムには、Advanced Encryption Standard (AES)、Triple Data Encryption Standard (3DES)およびRivest Cipher 4 (RC4)があります。

公開鍵暗号化

公開鍵暗号化は、公開鍵と秘密鍵の両方を使用することで鍵の配布方法の問題を解決しました。公開鍵はネットワークを通じて公開し、送信できますが、非公開鍵は通信の1人の当事者にしか公開されません。公開鍵と非公開鍵は暗号化方式が逆で、一方の鍵で暗号化したものをもう一方の鍵で復号化します。

Bobが公開鍵暗号化を使用して、Aliceに秘密のメッセージを送信するとします。Aliceは公開鍵と非公開鍵をどちらも持っているので、非公開鍵は安全な場所に保管しておき、公開鍵をBobに送信します。BobはAliceの公開鍵を使ってAliceへの秘密のメッセージを暗号化します。Aliceは非公開鍵を使ってメッセージを復号化します。

Aliceが自分の秘密鍵を使用してメッセージを暗号化し、その暗号化されたメッセージをBobに送信すれば、Bobが受信するデータはAliceから届いたものだと考えることができます。BobがAliceの公開鍵でデータを復号化できれば、そのメッセージはAliceが自分の秘密鍵で暗号化したものに間違いなく、Aliceの秘密鍵を持っているのはAliceのみです。問題は、Aliceの公開鍵が公開されているために、だれもがメッセージを読めてしまうことです。このシナリオは、セキュアなデータ通信を考慮に入れていませんが、デジタル署名の基本を示しています。デジタル署名とは公開鍵証明書のコンポーネントの1つで、SSLでクライアントやサーバーを認証するために使用します。公開鍵証明書デジタル署名を参照してください。

公開鍵暗号化は、データの暗号化と復号化に別の鍵を使用するので、非対称暗号化とも呼ばれます。SSLでよく使われる、よく知られている公開鍵暗号化アルゴリズムは、Rivest Shamir Adleman (RSA)アルゴリズムです。このほかにも、秘密鍵を交換するために設計されたSSLを使う公開鍵暗号化アルゴリズムには、Diffie-Hellman (DH)があります。公開鍵暗号化には膨大な計算が必要なため、速度が大幅に遅くなります。そこで、この方式は暗号化データ通信全体に使用するよりもむしろ、秘密鍵など少量のデータを暗号化する場合にだけ使用します。

秘密鍵暗号化と公開鍵暗号化の比較

秘密鍵暗号化と公開鍵暗号化のどちらにも、長所と短所があります。秘密鍵暗号化では、データの暗号化や復号化に時間はかかりませんが、通信者同士が同じ秘密鍵情報を共有する必要があり、鍵の交換の方法が問題になります。公開鍵暗号化では、鍵を秘密にする必要がないので鍵の交換は問題になりませんが、データの暗号化と復号化に使用するアルゴリズムには膨大な計算が必要で、著しく遅くなります

公開鍵証明書

公開鍵証明書を使用すると、エンティティは非対称暗号化で使用する公開鍵を安全に配布できます。公開鍵証明書は、次の状況を回避します。Charlieが自分の公開鍵と秘密鍵を作成すれば、自分はAliceだと名乗ってBobに公開鍵を送信できます。BobはCharlieと通信できますが、データをAliceに送信していると思い込んでしまいます。

公開鍵証明書は電子的なパスポートだと考えることができます。これは、信頼できる組織によって発行され、所有者に識別情報を提供します。公開鍵証明書を発行する信頼できる組織を、証明書発行局(CA)と呼びます。CAは公証人にたとえることができます。CAから証明書を取得するには、識別情報の証拠となるものを提供する必要があります。CAは、申請者が申し立てる組織の代表であるとの確証が得られたら、証明書に含まれる情報の妥当性を証明する証明書に署名します。

公開鍵証明書には、次のようなフィールドがあります。

発行者
証明書を発行した認証局(CA)。証明書を発行したCAが信頼でき、証明書が有効であれば、証明書は信頼できます。
有効期間
証明書には有効期限があります。証明書の有効性を検証する場合は、この日付をチェックしてください。
サブジェクト
証明書が表すエンティティに関する情報が含まれます。
サブジェクトの公開鍵
証明書が提供する情報の主要な部分は、サブジェクトの公開鍵です。その他のフィールドは、この鍵の妥当性を確認するためのものです。
署名
証明書は、証明書を発行したCAによってデジタルで署名されます。署名はCAの非公開鍵を使って作成され、証明書の妥当性を保証するものです。証明書のみに署名され、SSLトランザクションで送信されるデータには署名されないので、SSLには非拒否性がありません。

AliceがBobに公開鍵証明書で自分の公開鍵を送信するとき、BobがAliceの公開鍵のみを有効として受け付ける場合、CharlieがAliceになりすましたとしても、BobがだまされてCharlieに秘密情報を送信することはありません。

複数の証明書を証明書チェーンでリンクすることもできます。証明書チェーンを使用する場合、最初の証明書は必ず送信者の証明書です。次は送信者の証明書を発行したエンティティの証明書です。チェーン内に他の証明書がある場合、それぞれ直前の証明書を発行した証明書発行局の証明書です。チェーンの最後の証明書は、ルートCAの証明書です。ルートCAは、広く信頼されている公開証明書発行局です。複数のルートCAの情報は、通常、クライアントのインターネット・ブラウザに保存されています。この情報には、CAの公開鍵が含まれています。よく知られているCAにはVeriSign、Entrust、およびGTE CyberTrustがあります。

暗号化ハッシュ関数

暗号化されたデータを送信する場合、SSLは通常、暗号化ハッシュ関数を使ってデータの整合性を保証します。ハッシュ関数を使って、AliceがBobに送ったデータをCharlieが改ざんできないようにします。

暗号化ハッシュ関数はチェックサムに似ています。主な違いは、チェックサムがデータの偶発的変化を検出するのに対し、暗号化ハッシュ関数は故意による変更を検出するように設計されています。データが暗号化ハッシュ関数で処理されると、ハッシュと呼ばれる小さなビット文字列が生成されます。メッセージがごくわずかだけ変更された場合も、結果として生成されるハッシュは大きく変更されます。暗号化ハッシュ関数には、暗号化鍵が必要ありません。SSLとともによく使用されるハッシュ関数は、Secure Hash Algorithm (SHA)です。SHAは、U.S. National Institute of Standards and Technology (NIST)によって提案されました。

メッセージ認証コード

メッセージ認証コード(MAC)は暗号化ハッシュに似ていますが、秘密鍵をベースにしている点が異なります。秘密鍵情報が暗号化ハッシュ関数で処理したデータに含まれている場合、その結果生成されるハッシュはHMACと呼ばれます。

Aliceは、BobへのメッセージをCharlieが確実に改ざんしないようにする場合、メッセージのHMACを計算して元のメッセージにHMACを追加できます。次に、Bobと共有している秘密鍵を使用してメッセージとHMACを暗号化できます。Bobは、メッセージを復号化してHMACを計算すれば、送信中にメッセージが変更されたかどうかを知ることができます。SSLでは、HMACを使ってセキュアなデータを送信します。

デジタル署名

メッセージに暗号化ハッシュが作成されると、ハッシュは送信者の非公開鍵で暗号化されます。このような暗号化ハッシュをデジタル署名と呼びます。

SSLハンドシェーク

SSLを使った通信は、クライアントとサーバー間の情報交換から始まります。この情報交換をSSLハンドシェークと呼びます。SSLハンドシェークには、次のステージがあります。

  1. 暗号化方式群のネゴシエーション

    SSLセッションは、どの暗号群を使用するかについて、クライアントとサーバーがネゴシエーションを行うことから始まります。暗号化方式群とは、コンピュータがデータを暗号化するために使用する暗号化アルゴリズムと鍵のサイズのセットです。符号化方式には、公開鍵交換アルゴリズムまたは鍵合意アルゴリズム、および暗号化ハッシュ関数に関する情報が含まれます。クライアントは利用できる暗号群をサーバーに伝え、サーバーは、どちらにも適用できる暗号群を選択します。

  2. サーバーの識別情報の認証(オプション)

    SSLの認証ステップはオプションです。しかし、Web上の電子商取引の例では、一般にクライアントがサーバーを認証します。サーバーの認証により、サーバーが表すとクライアントが信じているエンティティを、そのサーバーが実際に表していることをクライアントが確認できます。

    サーバーは、自らが表すと唱える組織に属していることを証明するため、クライアントに公開鍵証明書を提示します。この証明書が有効であれば、クライアントはサーバーの識別情報について確信できます。

    クライアントとサーバーは、同じ秘密鍵について同意できる情報を交換します。たとえば、RSAを使う場合、クライアントは公開鍵証明書で取得したサーバーの公開鍵を使用して、秘密鍵情報を暗号化します。クライアントは暗号化された秘密鍵情報をサーバーに送信します。復号化にはサーバーの非公開鍵が必要なので、サーバーでだけ、このメッセージを復号化できます。

  3. 暗号化メカニズムの合意

    クライアントとサーバーは、同じ秘密鍵にアクセスします。それぞれのメッセージでは、ハンドシェークの最初のステップで選択した暗号化ハッシュ関数と、共有された秘密情報を使用して、メッセージに添付されるHMACを計算します。次に、秘密鍵と、ハンドシェークの最初のステップでネゴシエーションされた秘密鍵アルゴリズムを使用し、セキュアなデータとHMACを暗号化します。そのあと、クライアントとサーバーは、暗号化されハッシュ化されたデータを使ってセキュアに通信することができます。

SSLプロトコル

SSLハンドシェークでは、SSLハンドシェークについて概要を説明しました。それは、暗号化されたメッセージを送信する前にクライアントとサーバーの間で行われる情報の交換です。図8-1に詳細を示します。これは、SSLハンドシェークで交換される一連のメッセージを示しています。特定の状況下でだけ送信されるメッセージには「optional」と記されています。各SSLメッセージについては、後で詳しく説明します。

図8-1 SSL/TLSハンドシェーク

図8-1の説明が続きます
「図8-1 SSL/TLSハンドシェーク」の説明

SSLメッセージは、次の順序で送信されます。

  1. Client hello: クライアントは、それがサポートする最上位バージョンのSSLと暗号化方式群のリスト(TLS 1.0はSSL 3.1と示される)を含むサーバー情報を送信します。暗号化方式群の情報には、暗号化アルゴリズムと鍵のサイズが含まれます。
  2. Server hello: サーバーは、クライアントとサーバーの両方がサポートする最上位バージョンのSSLと最適な暗号化方式群を選択し、この情報をクライアントに送信します。
  3. (オプション) Certificate: サーバーはクライアントに証明書または証明書チェーンを送信します。証明書チェーンは通常、サーバーの公開鍵証明書で始まり、認証局のルート証明書で終わります。このメッセージはオプションで、サーバー認証を求められた場合に使用します。
  4. (オプション) Certificate request: サーバーがクライアントを認証する必要がある場合、クライアントに証明書要求を送信します。インターネット・アプリケーションでは、このメッセージが使われることはほとんどありません。
  5. (オプション) Server key exchange: Certificateからの公開鍵情報が鍵交換を行うのに不十分な場合、サーバーはクライアントにサーバー鍵交換メッセージを送信します。たとえば、Diffie-Hellman (DH)に基づく暗号化方式群では、このメッセージにはサーバーのDH公開鍵が含まれています。
  6. Server hello done: サーバーは、最初のネゴシエーション・メッセージを終了したことをクライアントに伝えます。
  7. (オプション) Certificate: サーバーがクライアントに証明書を要求すると、クライアントはサーバーが前に行ったように、その証明書チェーンを送信します。

    注意:

    クライアントに証明書を要求するのは、ごく一部のインターネット・サーバー・アプリケーションのみです。
  8. Client key exchange: クライアントは、対称暗号化で使用する鍵を作成するために使用される情報を生成します。RSAでは、クライアントはサーバーの公開鍵でこの鍵情報を暗号化してサーバーに送信します。DHに基づく暗号化方式群の場合、このメッセージにはクライアントのDH公開鍵が含まれています。
  9. (オプション) Certificate verify: このメッセージは、上述のとおりクライアントが証明書を提示する場合にクライアントによって送信されます。このメッセージは、サーバーにクライアントの認証処理を完了させるためのものです。このメッセージが使用されると、クライアントは暗号化ハッシュ関数で電子的に署名した情報を送信します。サーバーがクライアントの公開鍵でこの情報を復号化すれば、サーバーはクライアントを認証できます。
  10. Change cipher spec: クライアントはメッセージを送信し、暗号化モードに変更するようサーバーに伝えます。
  11. Finished クライアントはサーバーに、セキュアなデータ通信を開始する準備ができたことを伝えます。
  12. Change cipher spec: サーバーはメッセージを送信し、暗号化モードを変更するようクライアントに伝えます。
  13. Finished: サーバーはクライアントに、セキュアなデータ通信を開始する準備ができたことを伝えます。SSLハンドシェークが終了します。
  14. Encrypted data: クライアントとサーバーは、client helloとserver hello時にネゴシエーションされた対称暗号化アルゴリズムと暗号化ハッシュ関数およびclient key exchange時にクライアントがサーバーに送信した秘密鍵を使用して通信します。このときハンドシェークの再ネゴシエーションを行うことができます。ハンドシェークの再実行(再ネゴシエーション)を参照してください。
  15. Close Messages: 接続の終わりに、それぞれの側がclose_notifyアラートを送信し、接続が終了したことをピアに伝えます。

SSLセッションで生成したパラメータを保存しておけば、将来のSSLセッションでこれらのパラメータを再利用できます。SSLセッションのパラメータを保存しておけば、暗号化通信をすばやく開始できます。

ハンドシェークの再実行(再ネゴシエーション)

初期のハンドシェークが完了してアプリケーション・データが流れているとき、いずれの側からでも新しいハンドシェークをいつでも開始できます。特に重要な操作について、アプリケーションで強力な暗号化方式群を使用したり、サーバー・アプリケーションでクライアント認証が必要になる場合もあります。

理由は何であれ、新しいハンドシェークが既存の暗号化セッションに置き換わり、新しいセッションが確立されるまで、アプリケーション・データとハンドシェーク・メッセージが交互に配置されます。

アプリケーションで次のいずれかのメソッドを使用して、新しいハンドシェークを開始できます。

  • SSLSocket.startHandshake()
  • SSLEngine.beginHandshake()

注意:

再ネゴシエーションに関するプロトコルの問題が2009年に見つかりました。プロトコルおよびJava SE実装はいずれも修正されています。Transport Layer Security (TLS)再ネゴシエーションの問題を参照してください。

符号化方式の選択とリモート・エンティティの検証

SSL/TLSプロトコルは、保護された接続を確保するための一連の特定のステップを定義します。ただし、暗号化方式群の選択が、接続で確保するセキュリティのタイプに直接影響します。たとえば、匿名暗号化方式群を選択した場合、アプリケーションにはリモート・ピアの識別情報を検証する方法がありません。暗号化しない方式群が選択された場合は、データの機密性を保護できません。またSSL/TLSプロトコルでは、受信した資格と、ピアから送信されることが予期される資格が一致するようにとは規定していません。接続がなんらかの理由で悪意のあるピアにリダイレクトされたときに、悪意のあるピアのクレデンシャルが現在のトラスト・データに基づいて受け付けられた場合、その接続は有効とみなされてしまいます。

raw SSLSocketおよびSSLEngineクラスを使用する場合は、データの送信前に必ずピアのクレデンシャルをチェックしてください。SSLSocketおよびSSLEngineクラスは、URL内のホスト名がピアのクレデンシャル内のホスト名と一致することを自動的に検証しません。ホスト名が検証されない場合、URL不正行為によってアプリケーションが悪用される可能性があります。JDK 7以降は、エンドポイント識別/検証の手順は、SSL/TLSハンドシェーク中に処理できます。SSLParameters.getEndpointIdentificationAlgorithmメソッドを参照してください。

HTTPS (HTTP Over TLS)などのプロトコルでは、ホスト名検証が必要です。JDK 7以降、HTTPSエンドポイント識別は、HttpsURLConnectionのためのハンドシェーク中にはデフォルトで強制されます。SSLParameters.getEndpointIdentificationAlgorithmメソッドを参照してください。また、アプリケーションは、HostnameVerifierインタフェースを使用してデフォルトのHTTPSホスト名規則をオーバーライドできます。HostnameVerifierインタフェースおよびHttpsURLConnectionクラスを参照してください。

クライアント主導型OCSPとOCSPステープリング

Transport Layer Security (TLS)のハンドシェーク中にX.509証明書失効ステータスを判定するには、オンライン証明書ステータス・プロトコル(OCSP)を使用します。

TLSで使用されるX.509証明書は、証明書に欠陥があるとみなす理由がある場合は、発行元の証明書発行局(CA)によって無効にされる可能性があります。次のいずれかの手法を使用することで、TLSハンドシェーク中に証明書の失効ステータスを確認できます。
  • 証明書失効リスト(CRL)の実装

    CRLは、失効した証明書を単純に示すリストです。証明書を受け取るアプリケーションは、CRLサーバーからCRLを取得し、受け取った証明書がリストにあるかどうかを確認します。CRLの使用で不便な点は2つあります。それは、証明書を失効させることができるが、その失効した証明書はCRLにリストされないということです。

    • CRLは非常に大きくなる可能性があるため、ネットワーク・トラフィックがかなり増加する可能性があります。

    • 多くのCRLは長い有効期間で作成されます。これにより、証明書がその有効期間内に失効し次のCRL更新までリストに含まれなくなる可能性が高くなります。

    Java PKIプログラマーズ・ガイド証明書/CRLストレージ・クラスのトピックを参照してください。

  • クライアント主導型OCSP

    クライアント主導型OCSPでは、クライアントはOCSPを使用してOCSPレスポンダに連絡し、証明書の失効ステータスを確認します。必要なデータの量は少なく、OCSPレスポンダは、CRLよりも最新の失効ステータスを把握している可能性があります。サーバーに接続する各クライアントは、確認する証明書ごとに1つのOCSP応答が必要となります。サーバーがよく使用されるものであり、クライアントの多くでクライアント主導型OCSPが使用されている場合、これらのOCSP要求は、OCSPレスポンダのパフォーマンスに悪影響を及ぼす可能性があります。

  • OCSPステープリング

    OCSPステープリングにより、クライアントではなくサーバーで、OCSPレスポンダへの要求を行うことができます。サーバーは、証明書へのOCSP応答をステープリングして、TLSハンドシェーク中にそれをクライアントに返します。この手法では、発行元のCAではなく、証明書の提示者が、OCSP応答の提供のリソース・コストを負担できます。また、サーバーでOCSP応答をキャッシュし、それらをすべてのクライアントに提供できるようになります。これにより、応答をキャッシュし各クライアントによってではなくサーバーによって定期的に更新できるため、OCSPレスポンダの負荷が大幅に軽減されます。

クライアント主導型OCSPと証明書失効

クライアント主導型オンライン証明書ステータス・プロトコル(OCSP)では、クライアントが、Transport Layer Security (TLS)ハンドシェーク中にOCSPレスポンダに接続することで、証明書失効ステータスを確認できます。

クライアント主導型OCSPの要求は、TLSハンドシェーク中の、クライアントがサーバーから証明書を受け取りそれを検証したすぐ後に発生します。SSLハンドシェークを参照してください。

クライアント主導型OCSPを使用するTLSハンドシェーク

クライアント主導型OCSPは、サーバーの証明書失効ステータスを確認するために、クライアントとサーバーとの間のTLSハンドシェーク中に使用されます。クライアントは証明書を受け取った後、証明書検証を実行します。検証が成功すると、クライアントは、証明書が発行者によって失効にされていないことを確認します。これは、OCSPレスポンダにOCSP要求を送信することで行われます。OCSP応答を受け取ると、クライアントは、TLSハンドシェークが完了する前にこの応答を確認します。

図8-2 クライアント主導型OCSPを使用するTLSハンドシェーク

図8-2の説明が続きます
「図8-2 クライアント主導型OCSPを使用するTLSハンドシェーク」の説明

通常、クライアントは証明書のAuthority Information Access (AIA)拡張情報を調べてOCSPレスポンダのURLを見つけますが、システム・プロパティの使用によってそれを静的URLに設定できます。

クライアント主導型OCSPを使用するためのJavaクライアントの設定

クライアント主導型OCSPは、失効チェックとOCSPを有効にすることで有効になります。

クライアント主導型OCSPを使用するようにJavaクライアントを構成するには、Javaクライアントを、TLSを使用してサーバーに接続するように設定してある必要があります。
  1. 失効チェックを有効にします。これを行うには、異なる2通りの方法があります。
    • システム・プロパティcom.sun.net.ssl.checkRevocationtrueに設定します。
    • PKIXParameterssetRevocationEnabledメソッドを使用します。PKIXParametersクラスを参照してください。
  2. クライアント主導型OCSPを有効にします。

    セキュリティ・プロパティocsp.enabletrueに設定します。

両方のステップが必要となります。失効チェックが有効になっている場合以外は、ocsp.enable設定に効果はありません。

OCSPステープリングと証明書失効

オンライン証明書ステータス・プロトコル(OCSP)ステープリングでは、発行元の証明書発行局(CA)ではなく、証明書の提示者が、証明書の失効ステータスを含むOCSP応答の提供のリソース・コストを負担できます。

OCSPステープリングを使用するTLSハンドシェーク

OCSPステープリングは、サーバーの証明書失効ステータスを確認するために、クライアントとサーバーとの間のTransport Layer Security (TLS)ハンドシェーク中に使用されます。サーバーはOCSPレスポンダへのOCSP要求を行い、クライアントに返された証明書にOCSP要求をステープリングします。サーバーにOCSPレスポンダへの要求を行わせることで、応答をキャッシュし、多数のクライアントのために複数回使用できます。

TLSハンドシェークは、TLS ClientHelloメッセージで始まります。OCSPステープリングが使用される場合、このメッセージは、サーバーがOCSP要求を実行する必要があることを示すstatus_request拡張情報とともにサーバーに送信されます。ClientHelloメッセージを処理した後、サーバーは、証明書ごとに適切なOCSPレスポンダにOCSP要求を送信します。サーバーはOCSPレスポンダからOCSP応答を受け取ると、TLSハンドシェークでOCSP応答が提供されることを示すstatus_request拡張情報とともに、ServerHelloメッセージを送信します。次に、サーバーはサーバー証明書チェーンを提示し、その後にそれらの証明書の1つ以上のOCSP応答で構成されているメッセージが続きます。ステープリングされたOCSP応答とともに証明書を受け取るクライアントは、各証明書を検証してから、ハンドシェークを続行する前にそのOCSP応答を確認します。

クライアントの視点から述べると、証明書のための、サーバーからのステープリング済OCSP応答がない場合、クライアントはクライアント主導型OCSPまたはCRLを使用して失効情報を取得しようとします。これらのどちらかが有効になっている場合、失効チェックはtrueに設定されます。

図8-3 OCSPステープリングを使用するTLSハンドシェーク

図8-3の説明が続きます
「図8-3 OCSPステープリングを使用するTLSハンドシェーク」の説明

TLSハンドシェーク・メッセージの詳細は、SSLハンドシェークを参照してください。

ステータス要求と複数ステータス要求との比較

OCSPステープリング機能は、TLS Certificate Status Request拡張機能(RFC 6066の第8項)およびMultiple Certificate Status Request拡張機能(RFC 6961)を実装します。

TLS Certificate Status Request拡張機能は、証明書チェーン内のサーバー証明書のみのために失効情報を要求しますが、Multiple Certificate Status Request拡張機能は、証明書チェーン内のすべての証明書のために失効情報を要求します。サーバー証明書の失効情報のみがクライアントに送信される場合、チェーン内の他の証明書を、証明書失効リスト(CRL)またはクライアント主導型OCSPを使用して検証できます(ただし、クライアントを、これを行うように設定する必要があります)。

TLSによって、サーバーがクライアントの証明書も要求するようにできますが、クライアントが適切なOCSPレスポンダに連絡して、サーバーに送信された証明書に応答をステープリングできるようにする、OCSPステープリングでの用意はできていません。

OCSPの要求と応答

OCSPの要求メッセージと応答メッセージは、通常は、暗号化されていないHTTPを介して送信されます。応答は、CAによって署名されます。

必要な場合は、ステープリングされた応答は、クライアント・コードで、ExtendedSSLSessionオブジェクトでgetStatusResponsesメソッドを呼び出すことで取得できます。メソッド・シグネチャは次のとおりです。

public List<byte[]> getStatusResponses();

OCSP応答は、RFC 6960内のASN.1で示されている形式でDistinguished Encoding Rules (DER)を使用してエンコードされます。

OCSPステープリングを使用するためのJavaクライアントの設定

オンライン証明書ステータス・プロトコル(OCSP)ステープリングは、クライアント側で、システム・プロパティjdk.tls.client.enableStatusRequestExtensiontrue(そのデフォルト値)に設定することで有効になります。

サーバーから返された証明書にステープリングされたOCSP応答を使用するようにJavaクライアントを構成するには、Javaクライアントを、TLSを使用してサーバーに接続するように設定してある必要があり、サーバーを、TLSハンドシェークの一環でそれが返す証明書にOCSP応答をステープリングするように設定する必要があります。
  1. クライアントでOCSPステープリングを有効にします。

    必要な場合は、システム・プロパティjdk.tls.client.enableStatusRequestExtensiontrueに設定します。

  2. 失効チェックを有効にします。これを行うには、異なる2通りの方法があります。
    • システム・プロパティcom.sun.net.ssl.checkRevocationtrueに設定します。これは、コマンド行から、またはコードで実行できます。
    • PKIXParametersクラスでsetRevocationEnabledメソッドを使用します。PKIXParametersクラスを参照してください。

    クライアントで、証明書検証にサーバーから受け取ったステープリング済応答を含める場合は、失効チェックをtrueに設定する必要があります。失効チェックがtrueに設定されていない場合、失効情報の存在またはステータスに関係なく、接続を継続できます。

OCSPステープリングを使用するためのJavaサーバーの設定

オンライン証明書ステータス・プロトコル(OCSP)ステープリングは、サーバーで、システム・プロパティjdk.tls.server.enableStatusRequestExtensiontrueに設定することで有効になります。(デフォルトでは、falseに設定されています。)

Javaサーバーを、OCSPレスポンダに接続しOCSP応答を証明書にステープリングしてクライアントに返すように構成するには、次の手順を使用します。Javaサーバーを、TLSを使用してクライアントに応答するように設定してある必要があります。
  1. サーバーでOCSPステープリングを有効にします。

    システム・プロパティjdk.tls.server.enableStatusRequestExtensiontrueに設定します。

  2. オプション: 必要に応じて他のプロパティを設定します。有効なプロパティのリストは、OCSPステープリングの構成プロパティを参照してください。

OCSPステープリングの構成プロパティ

このトピックでは、オンライン証明書ステータス・プロトコル(OCSP)使用時の各種プロパティの設定の効果をリストします。クライアント主導型OCSPとOCSPステープリングの両方で使用されるプロパティを示します。

サーバー側のプロパティ

大部分のプロパティは、SSLContextのインスタンス化時に読み取られます。これは、プロパティを設定した場合に、新しいSSLContextオブジェクトを取得して、そのSSLContextオブジェクトから取得するSSLSocketまたはSSLEngineオブジェクトがそのプロパティ設定を反映するようにする必要があることを意味します。1つの例外は、jdk.tls.stapling.responseTimeoutプロパティです。このプロパティは、ServerHandshakerオブジェクトの作成時に評価されます(基本的に、SSLSocketまたはSSLEngineオブジェクトの作成と同時)。

表8-3 サーバー側のOCSPステープリングのプロパティ

プロパティ 説明 デフォルト値
jdk.tls.server.enableStatusRequestExtension OCSPステープリングのサーバー側サポートを有効にします。 False
jdk.tls.stapling.responseTimeout

キャッシュから取得するかOCSPレスポンダに連絡することで取得するかに関係なく、サーバーでOCSP応答の取得に使用される最長時間を制御します。

受取済の応答は、該当する場合は実行中のステープリングのタイプに基づいて、CertificateStatusメッセージで送信されます。

5000 (ミリ秒単位の整数値)
jdk.tls.stapling.cacheSize

エントリ内の最大キャッシュ・サイズを制御します。

キャッシュがいっぱいで、新しい応答をキャッシュする必要がある場合は、最も長い間使用されていないキャッシュ・エントリが、新しいものに置き換えられます。このプロパティの値がゼロ以下の場合は、キャッシュに含めることができる応答の数に上限がないことを意味します。

256個のオブジェクト
jdk.tls.stapling.cacheLifetime

キャッシュされた応答の最長存続時間を制御します。

応答にキャッシュ存続時間より早く期限切れになるnextUpdateフィールドがある場合は、応答の存続時間を、このプロパティで設定されている値よりも短くできます。このプロパティの値がゼロ以下の場合は、キャッシュ存続時間が無効になります。オブジェクトにnextUpdate値がなく、キャッシュ存続時間が無効になっている場合、応答はキャッシュされません。

3600秒(1時間)
jdk.tls.stapling.responderURI

TLSのために使用される証明書にAuthority Info Access (AIA)拡張情報がない場合は、管理者がデフォルトURIを設定できるようになります。

jdk.tls.stapling.responderOverrideプロパティが設定されている場合を除き、Authority Info Access拡張情報の値はオーバーライドされません。

未設定
jdk.tls.stapling.responderOverride

jdk.tls.stapling.responderURIプロパティによって提供されるURIで、AIA拡張情報の値をオーバーライドできるようになります。

False
jdk.tls.stapling.ignoreExtensions

status_requestまたはstatus_request_v2 TLS拡張情報で指定されているOCSP拡張情報の転送を無効にします。

False

クライアント側の設定

表8-4 OCSPステープリングで使用されるクライアント側設定

PKIXBuilderParameters checkRevocationプロパティ PKIXRevocationChecker 結果
デフォルト デフォルト デフォルト 失効チェックは無効です。
デフォルト True デフォルト 失効チェックは有効です。[1]
インスタンス化済 デフォルト デフォルト 失効チェックは有効です。[1]
インスタンス化済 デフォルト インスタンス化され、PKIXBuilderParametersオブジェクトに追加されています。 失効チェックは有効であり、[1]PKIXRevocationCheckerの設定に従って動作します。

脚注1 ocsp.enableセキュリティ・プロパティがtrueに設定されている場合のみクライアント側のOCSPのフォールバックが起こるということに注意してください。

開発者は、OCSPステープリングによって提供された応答をいくらか柔軟に処理できます。OCSPステープリングによって、証明書パス・チェックおよび失効チェックに関わる現在の方法論が変更されることはありません。これは、クライアントとサーバーの両方でstatus_request拡張情報をアサートし、CertificateStatusメッセージによってOCSP応答を取得し、ユーザーが失効情報またはその不足に柔軟に対応できるようになることを意味します。

呼出し側によってPKIXBuilderParametersが提供されない場合は、失効チェックは無効になります。呼出し側がPKIXBuilderParametersオブジェクトを作成し、setRevocationEnabledメソッドを使用して失効チェックを有効にする場合は、ステープリングされたOCSP応答が評価されます。これは、com.sun.net.ssl.checkRevocationプロパティがtrueに設定されている場合にも当てはまります。

JSSEクラスとインタフェース

セキュアな通信を行うには、接続の両側がSSL対応であることが必要です。JSSE APIの接続のエンドポイント・クラスは、SSLSocketおよびSSLEngineです。図8-4では、SSLSocketSSLEngineの作成に使用される主なクラスを論理的な順序で並べています。

図8-4 SSLSocketとSSLEngineの作成に使用されるJSSEクラス

図8-4の説明が続きます
「図8-4 SSLSocketとSSLEngineの作成に使用されるJSSEクラス」の説明

SSLSocketSSLSocketFactoryまたはイン・バウンド接続を受け取るSSLServerSocketによって作成されます。SSLServerSocketSSLServerSocketFactoryで作成されます。SSLSocketFactoryおよびSSLServerSocketFactoryオブジェクトはどちらもSSLContextで作成されます。SSLEngineは、SSLContextによって直接作成され、アプリケーションに依存してすべての入出力を処理します。

注意:

raw SSLSocketクラスまたはSSLEngineクラスを使用する場合は、データの送信前に必ずピアのクレデンシャルをチェックしてください。JDK 7以降は、エンドポイント識別/検証の手順は、SSL/TLSハンドシェーク中に処理できます。メソッドSSLParameters.setEndpointIdentificationAlgorithmを参照してください。

たとえば、URL内のホスト名は、ピアのクレデンシャル内のホスト名と一致します。ホスト名が検証されない場合、URL不正行為によってアプリケーションが悪用される可能性があります。

JSSEのコア・クラスとインタフェース

コアJSSEクラスは、javax.netパッケージとjavax.net.sslパッケージに含まれています。

SocketFactoryおよびServerSocketFactoryクラス

抽象クラスjavax.net.SocketFactoryは、ソケットの作成に使われます。このクラスのサブクラスは、ソケットの特定のサブクラスを作成し、パブリック・ソケット・レベルの機能を追加するための汎用フレームワークを提供するファクトリです。たとえば、SSLSocketFactory and SSLServerSocketFactoryクラスを参照してください。

javax.net.ServerSocketFactory抽象クラスはSocketFactoryクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。

ソケット・ファクトリは、構築されるソケットに関する様々なポリシーを取得するための簡単な方法であり、ソケットを要求する特別なコード構成を必要としない方法でそれらのソケットを生成します。

  • ファクトリとソケットに多相性があるため、種類が異なるファクトリを渡すだけで、種類が異なるソケットに同じアプリケーション・コードを使用できます。
  • ソケット構築時に使用するパラメータを使って、ファクトリ自身をカスタマイズできます。たとえば、ファクトリをカスタマイズして、異なるネットワーク・タイムアウトのソケットや、構成済のセキュリティ・パラメータを返すことができます。
  • アプリケーションに返されるソケットはjava.net.Socket (またはjavax.net.ssl.SSLSocket)のサブクラスにすることができます。そうすれば、圧縮、セキュリティ、レコード宣言、統計情報収集、ファイアウォール・トンネリングなどの機能の新しいAPIを直接公開できます。

SSLSocketFactoryおよびSSLServerSocketFactoryクラス

javax.net.ssl.SSLSocketFactoryクラスは、セキュアなソケットを作成するファクトリとして動作します。このクラスは、javax.net.SocketFactoryの抽象サブクラスです。

セキュアなソケット・ファクトリは、セキュアなソケットの作成と初期設定の詳細情報をカプセル化します。これには、認証鍵、ピア証明書の検証、使用できる暗号化方式群などが含まれます。

javax.net.ssl.SSLServerSocketFactoryクラスはSSLSocketFactoryクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。

SSLSocketFactoryの取得

次の方法でSSLSocketFactoryを取得できます。

  • SSLSocketFactory.getDefault() staticメソッドを呼び出してデフォルトのファクトリを取得します。
  • APIパラメータとしてファクトリを受信する。つまり、ソケットを作成する必要があるが、そのソケットの構成方法の詳細に関与しないコードには、クライアントによって呼び出され、ソケットの作成時に使用するSSLSocketFactoryを指定できるSSLSocketFactoryパラメータを持つメソッドを含めることができます(javax.net.ssl.HttpsURLConnectionなど)。
  • 動作を指定した新規ファクトリを構築する。

通常、デフォルトのファクトリはサーバー認証だけをサポートするように構成されています。このため、デフォルトのファクトリで作成されたソケットは、一般的なTCPソケット以上にクライアントの情報を漏らすことはありません。

ソケットを作成して使用するクラスの多くは、ソケットの作成方法を詳しく知る必要はありません。パラメータとして渡されたソケット・ファクトリを介してソケットを作成するのは、ソケット構成の詳細を分離し、ソケットを作成して使用するクラスの再利用性を高めるよい方法です。

新しいソケット・ファクトリ・インスタンスを作成するには、独自のソケット・ファクトリ・サブクラスを実装するか、ソケット・ファクトリのファクトリとして動作するクラスをべつに使用します。このようなクラスの1つの例がSSLContextで、これはプロバイダ・ベースの構成クラスとしてJSSE実装に提供されます。

SSLSocketおよびSSLServerSocketクラス

javax.net.ssl.SSLSocketクラスは標準のJava java.net.Socketクラスのサブクラスです。標準的なソケット・メソッドをすべてサポートし、セキュアなソケットに固有のメソッドを追加します。標準的なソケット・メソッドをすべてサポートし、セキュアなソケットに固有のメソッドを追加します。このクラスのインスタンスは、その作成に使用されたSSLContextをカプセル化します。SSLContextクラスを参照してください。ソケット・インスタンスのセキュアなソケット・セッションの作成を管理するAPIもありますが、トラストおよび鍵管理は直接公開されません。

javax.net.ssl.SSLServerSocketクラスはSSLSocketクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。

ピアの不正行為を防止するには、常にSSLSocketに提示されるクレデンシャルを検証してください。符号化方式の選択とリモート・エンティティの検証を参照してください。

注意:

SSLプロトコルとTLSプロトコルは複雑なので、接続時の受信バイトがハンドシェークのデータとアプリケーション・データのどちらなのかを予測し、現在の接続状態にどのような影響を与えるか(処理を中断させることもある)を予測するのは困難です。Oracle JSSEの実装では、SSLSocket.getInputStream()によって取得されたオブジェクトのavailable()メソッドは、SSL接続で正常に復号化されても、アプリケーションではまだ読み込まれていないデータのバイト数を返します。

SSLSocketの取得

SSLSocketのインスタンスは、次のいずれかの方法で取得できます。

  • SSLSocketは、そのクラスの複数のcreateSocketメソッドのうちの1つを使用して、SSLSocketFactoryのインスタンスによって作成できます。
  • SSLSocketSSLServerSocketクラスのacceptメソッドを使用して作成できます。

SSLEngineクラス

SSL/TLS/DTLSが利用される機会はますます増えています。広範な計算プラットフォームやデバイスを包含するさまざまなアプリケーションで使用されています。この普及に伴い、アプリケーションのパフォーマンス、拡張性、サイズおよびその他の要件を満たすため、様々な入出力モデルやスレッド・モデルでSSL/TLS/DTLSを使用することが求められています。ブロックおよび非ブロック入出力チャネル、非同期入出力、任意の入力ストリームと出力ストリームおよびバイト・バッファでSSL/TLS/DTLSの使用が求められています。また、数千のネットワーク接続を管理することが必要な、非常に拡張性の高いパフォーマンス重視の環境で使用することも求められています。

Java SEのSSLEngineクラスを使用する入出力トランスポート・メカニズムの抽象により、トランスポートに依存せずにSSL/TLS/DTLSプロトコルをアプリケーションで使用できるようになったため、アプリケーション開発者は最もニーズを満たすトランスポート・モデルや計算モデルを自由に選択できます。この新しい抽象化により、非ブロック入出力チャネルや他の入出力モデルをアプリケーションで使用できるだけでなく、異なるスレッド・モデルにも対応できます。事実上これは、入出力とスレッドの決定がアプリケーション開発者に委ねられることになります。こうした柔軟性のため、アプリケーション開発者は、それ自体が複雑な問題でもある入出力とスレッドを管理するとともに、SSL/TLS/DTLSプロトコルをある程度理解する必要があります。このように、新しい抽象は高度なAPIなので、初心者はSSLSocketを使用してください。

Java Generic Security Services (Java GSS-API)やJava Simple Authentication Security Layer (Java SASL)などの他のJavaプログラミング言語APIのユーザーは、アプリケーションがデータをトランスポートする役割を担うことの類似点に気付くでしょう。

コア・クラスは、javax.net.ssl.SSLEngineです。これは、SSL/TLS/DTLS状態マシンをカプセル化し、SSLEngineクラスのユーザーによって供給されるインバウンドとアウトバウンドのバイト・バッファ上で動作します。図8-5は、アプリケーションから、SSLEngineを経由して、トランスポート・メカニズムまで進み、戻ってくるデータのフローを示しています。

図8-5 SSLEngineを通るデータのフロー

図8-5の説明が続きます
「図8-5 SSLEngineを通るデータのフロー」の説明

左側に示されるアプリケーションは、アプリケーションのプレーンテキスト・データをアプリケーション・バッファに供給し、それをSSLEngineに渡します。SSLEngineオブジェクトは、バッファに格納されているデータ、またはハンドシェーク・データを処理してSSL/TLS/DTLSエンコード・データを生成し、アプリケーションによって提供されるネットワーク・バッファに格納します。次にアプリケーションは、右側に示されている適切なトランスポートを使用して、ネットワーク・バッファの内容をピアに送信する役割を実行します。トランスポートを介してピアからSSL/TLS/DTLSエンコード・データを受け取ると、アプリケーションはそのデータをネットワーク・バッファに格納し、SSLEngineに渡します。SSLEngineオブジェクトは、ネットワーク・バッファの内容を処理し、ハンドシェーク・データまたはアプリケーション・データを生成します。

SSLEngineクラスのインスタンスは次のいずれかの状態になります。

作成
SSLEngineの作成と初期化は完了しましたが、まだ使用されてはいません。この段階では、アプリケーションにより、SSLEngine固有のあらゆる設定(暗号化方式群の有効化、SSLEngineがクライアント・モードとサーバー・モードのどちらでハンドシェークを行うかなど)を行うことができます。ハンドシェークが始まると、次のハンドシェークから新しい設定(クライアント/サーバー・モードの設定を除く)が使用されます。
初期ハンドシェーク
初期ハンドシェークとは、SSLSessionが確立されるまでの間、2つのピアが通信パラメータを交換する手続きです。この段階では、アプリケーション・データは送信できません。
アプリケーション・データ
通信パラメータが確立され、ハンドシェークが完了すると、SSLEngineからアプリケーション・データが送信されます。アウトバウンド・アプリケーション・メッセージは暗号化され、データの整合性が確保されます。インバウンド・メッセージでは、この逆の手続きが行われます。
再ハンドシェーク
アプリケーション・データ段階の間はいつでも、どちら側のピアからでも、必要に応じてセッションの再ネゴシエーションを要求できます。アプリケーション・データに新しいハンドシェーク・データを混合できます。再ハンドシェークの段階を開始する前に、アプリケーションは、SSL/TLS/DTLS通信パラメータ(例: 有効な暗号化方式群のリスト)や、クライアント認証を使用するかどうかの設定をリセットできます。しかし、クライアント・モードとサーバー・モードを切り替えることはできません。前回と同様に、ハンドシェークが始まってから次のハンドシェークまで、新しいSSLEngine構成設定は使用されません。
修了
接続が不要になったとき、アプリケーションは、SSLEngineを終了し、ピアと送受信するメッセージが残っている場合は送受信を完了してから、配下の転送メカニズムを終了する必要があります。いったん閉じられたエンジンを再利用することはできません。新しいSSLEngineを作成する必要があります。

SSLEngineオブジェクトの作成

SSLContext.createSSLEngine()メソッドを使用してSSLEngineオブジェクトを作成します。

SSLEngineオブジェクトを作成する前に、クライアントまたはサーバーとして動作するようにエンジンを構成し、使用する暗号化方式群やクライアント認証が必要かどうかなどの他の構成パラメータも設定します。SSLContext.createSSLEngineメソッドはjavax.net.ssl.SSLEngineオブジェクトを作成します。

注意:

サーバー名とポート番号は、サーバーとの通信には使用されません(すべてのトランスポートはアプリケーションが担当します)。それらは、SSLセッションキャッシングおよび取得すべきサーバー・クレデンシャルを決定するために、Kerberosベースの暗号化方式群の実装に使用するJSSEプロバイダへのヒントです。

例8-1 キーストアとしてJKSを使用してTLSのためのSSLEngineクライアントを作成するサンプル・コード

次のサンプル・コードでは、キーストアとしてJKSを使用するTLSのためのSSLEngineクライアントを作成します。

    import javax.net.ssl.*;
    import java.security.*;

    // Create and initialize the SSLContext with key material
    char[] passphrase = "passphrase".toCharArray();

    // First initialize the key and trust material
    KeyStore ksKeys = KeyStore.getInstance("JKS");
    ksKeys.load(new FileInputStream("testKeys"), passphrase);
    KeyStore ksTrust = KeyStore.getInstance("JKS");
    ksTrust.load(new FileInputStream("testTrust"), passphrase);

    // KeyManagers decide which key material to use
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
    kmf.init(ksKeys, passphrase);

    // TrustManagers decide whether to allow connections
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ksTrust);

    // Get an instance of SSLContext for SSL/TLS protocols
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    // Create the engine
    SSLEngine engine = sslContext.createSSLengine(hostname, port);

    // Use as client
    engine.setUseClientMode(true);

SSL/TLSデータの生成と処理

2つの主要なSSLEngineメソッドはwrap()unwrap()です。それらは、それぞれネットワーク・データの生成と消費を担当します。SSLEngineオブジェクトの状態に応じて、このデータはハンドシェーク・データかアプリケーション・データになります。

それぞれのSSLEngineオブジェクトには、存続期間中に数種類の段階があります。アプリケーション・データを送信または受信できるようにするには、SSL/TLSプロトコルで、暗号化パラメータを確立するためのハンドシェークが必要です。このハンドシェークでは、SSLEngineオブジェクトによる一連のやり取りのステップが必要です。ハンドシェーク自体の詳細は、SSLハンドシェークを参照してください。

初期ハンドシェーク時に、wrap()およびunwrap()メソッドはハンドシェーク・データを生成および消費し、アプリケーションはデータのトランスポートを担当します。wrap()およびunwrap()メソッド・シーケンスは、ハンドシェークが終了するまで繰り返されます。それぞれのSSLEngine操作によりSSLEngineResultクラスのインスタンスが生成され、その中のSSLEngineResult.HandshakeStatusフィールドは、ハンドシェークを進めるために実行する必要のある次の動作を決定するために使用されます。

表8-5に、一般的なハンドシェーク時に呼び出されるメソッドのシーケンスと、対応するメッセージおよびステータスを示します。

表8-5 一般的なハンドシェーク

クライアント SSL/TLSメッセージ HandshakeStatus
wrap() ClientHello NEED_UNWRAP
unwrap() ServerHello/Cert/ServerHelloDone NEED_WRAP
wrap() ClientKeyExchange NEED_WRAP
wrap() ChangeCipherSpec NEED_WRAP
wrap() Finished NEED_UNWRAP
unwrap() ChangeCipherSpec NEED_UNWRAP
unwrap() Finished FINISHED

表8-6に、一般的なSSL/TLSハンドシェーク時の状態マシンと、対応するメッセージおよびステータスを示します。

図8-6 SSL/TLSハンドシェーク中の状態マシン

図8-6の説明が続きます
「図8-6 SSL/TLSハンドシェーク中の状態マシン」の説明

ハンドシェークの完了時に、wrap()をさらに呼び出すと、アプリケーション・データおよびパッケージを消費してトランスポートしようとします。unwrap()メソッドはその逆を試みます。

ピアにデータを送信するには、まずアプリケーションがSSLEngine.wrap()を介して送信するデータを提供し、対応するSSL/TLSエンコード・データを取得します。次にアプリケーションは、選択したトランスポート・メカニズムを使用してエンコード・データをピアに送信します。アプリケーションは、トランスポート・メカニズムを介してピアからSSL/TLSエンコード・データを受け取ると、SSLEngine.unwrap()を介してそのデータをSSLEngineに送り、ピアによって送信されたプレーン・テキスト・データを取得します。

例8-2 非ブロックSocketChannelの作成のサンプル・コード

次の例では、非ブロックSocketChannelを使用してピアと通信するSSLアプリケーションを示します。これは、例8-1で作成したSSLEngineを使用してエンコードすることにより、ピアに文字列helloを送信します。バイト・バッファの大きさを決定するために、SSLSessionからの情報を使用しています。

注意:

この例は、非ブロックSocketChannelを組み込んだSelectorを使用することにより、堅牢性と拡張性を高めることができます。
    // Create a nonblocking socket channel
    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.configureBlocking(false);
    socketChannel.connect(new InetSocketAddress(hostname, port));

    // Complete connection
    while (!socketChannel.finishedConnect()) {
    // do something until connect completed
    }

    //Create byte buffers for holding application and encoded data

    SSLSession session = engine.getSession();
    ByteBuffer myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
    ByteBuffer myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
    ByteBuffer peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
    ByteBuffer peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());

    // Do initial handshake
    doHandshake(socketChannel, engine, myNetData, peerNetData);

    myAppData.put("hello".getBytes());
    myAppData.flip();

    while (myAppData.hasRemaining()) {
    // Generate SSL/TLS/DTLS encoded data (handshake or application data)
    SSLEngineResult res = engine.wrap(myAppData, myNetData);

    // Process status of call
    if (res.getStatus() == SSLEngineResult.Status.OK) {
        myAppData.compact();

        // Send SSL/TLS/DTLS encoded data to peer
        while(myNetData.hasRemaining()) {
            int num = socketChannel.write(myNetData);
            if (num == 0) {
                // no bytes written; try again later
            }
        }
    }

    // Handle other status:  BUFFER_OVERFLOW, CLOSED
    ...
    }

例8-3 非ブロックSocketChannelからのデータの読取りのサンプル・コード

次のサンプル・コードでは、同じ非ブロックSocketChannelからデータを読み取り、例8-1で作成したSSLEngineを使用して、そのデータからプレーン・テキストを抽出する方法を示しています。このコードが反復されるごとに、ハンドシェーク処理が進行しているかどうかに応じて、プレーン・テキストが生成されたり、生成されなかったりします。
    // Read SSL/TLS/DTLS encoded data from peer
    int num = socketChannel.read(peerNetData);
    if (num == -1) {
        // The channel has reached end-of-stream
    } else if (num == 0) {
        // No bytes read; try again ...
    } else {
        // Process incoming data
        peerNetData.flip();
        res = engine.unwrap(peerNetData, peerAppData);

        if (res.getStatus() == SSLEngineResult.Status.OK) {
            peerNetData.compact();

        if (peerAppData.hasRemaining()) {
            // Use peerAppData
        }
    }
    // Handle other status:  BUFFER_OVERFLOW, BUFFER_UNDERFLOW, CLOSED
    ...
    }

Datagram Transport Layer Security (DTLS)プロトコル

Datagram Transport Layer Security (DTLS)プロトコルは、信頼できる順次のデータ配信を必要とせず提供しない、データグラムでのTLSのトラフィックを構築するように設計されています。Java Secure Socket Extension (JSSE) APIおよびSunJSSEセキュリティ・プロバイダでは、DTLSプロトコルがサポートされています。

TLSはTCPなどの透過的な信頼できるトランスポート・チャネルを必要とするため、信頼できないデータグラム・トラフィックの保護には使用できないためです。DTLSは、TLSのデータグラム互換型です。

JSSE APIでは、Secure Socket Layer (SSL)プロトコルとTransport Layer Security (TLS)プロトコルとともにDTLSバージョン1.0DTLSバージョン1.2がサポートされるようになりました。

javax.net.ssl.SSLEngineプログラミング・モデルは、DTLS用JSSE APIで使用されます。

DTLSハンドシェーク

アプリケーション・データを送信または受信できるようにするには、DTLSプロトコルで、暗号化パラメータを確立するためのハンドシェークが必要です。このハンドシェークでは、SSLEngineオブジェクトによる、クライアントとサーバーとの間の一連のメッセージのやり取りが必要です。

DTLSハンドシェークでは、すべてのメッセージが正しく受け取られる必要があります。したがって、信頼できないデータグラム・トラフィックでは、不足または遅延しているパケットを再送信する必要があります。javax.net.ssl.SSLEngineは入出力操作を担当しないため、アプリケーションが、タイマーを提供し、再送信が必要なときにSSLEngineに知らせる役目を担います。アプリケーションのためにタイマーおよび再送信の戦略を実装することが重要です。DTLS接続での再送信の処理を参照してください。

DTLSハンドシェークには、次のステージがあります。

  1. 暗号化方式群のネゴシエーション

    DTLSセッションは、どの暗号群を使用するかについて、クライアントとサーバーがネゴシエーションを行うことから始まります。暗号化方式群とは、コンピュータがデータを暗号化するために使用する暗号化アルゴリズムと鍵のサイズのセットです。符号化方式には、公開鍵交換アルゴリズムまたは鍵合意アルゴリズム、および暗号化ハッシュ関数に関する情報が含まれます。クライアントは利用できる暗号群をサーバーに伝え、サーバーは、どちらにも適用できる暗号群を選択します。

    Cookieは、サービス妨害攻撃(DoS)を防ぐために、暗号群とともに、クライアントとサーバーとの間ので交換されます。

  2. (オプション)サーバーの識別情報の認証(オプション)

    認証ステップはオプションです。しかし、Web上の電子商取引の例では、クライアントがサーバーを認証します。サーバーの認証により、サーバーが表すとクライアントが信じているエンティティを、そのサーバーが実際に表していることをクライアントが確認できます。

    サーバーは、自らが表すと唱える組織に属していることを証明するため、クライアントに公開鍵証明書を提示します。この証明書が有効であれば、クライアントはサーバーの識別情報について確信できます。

    クライアントとサーバーは、同じ秘密鍵について同意できる情報を交換します。たとえば、RSAを使う場合、クライアントは公開鍵証明書で取得したサーバーの公開鍵を使用して、秘密鍵情報を暗号化します。クライアントは暗号化された秘密鍵情報をサーバーに送信します。復号化にはサーバーの非公開鍵が必要なので、サーバーでだけ、このメッセージを復号化できます。

  3. 暗号化メカニズムの合意

    クライアントとサーバーは、同じ秘密鍵にアクセスします。それぞれのメッセージでは、ハンドシェークの最初のステップで選択した暗号化ハッシュ関数と、共有された秘密情報を使用して、メッセージに添付されるHMACを計算します。次に、秘密鍵と、ハンドシェークの最初のステップでネゴシエーションされた秘密鍵アルゴリズムを使用し、セキュアなデータとHMACを暗号化します。そのあと、クライアントとサーバーは、暗号化されハッシュ化されたデータを使ってセキュアに通信することができます。

DTLSハンドシェークのメッセージの交換

DTLSハンドシェークでは、SSLEngineオブジェクトによって、クライアントとサーバーとの間で一連の送受信メッセージが交換されます。

図8-7に、DTLSハンドシェークで交換される一連のメッセージを示します。特定の状況下でだけ送信されるメッセージには「optional」と記されています。各メッセージをこの図の後に説明します。

DTLSハンドシェーク・メッセージの詳細は、DTLSバージョン1.0およびDTLSバージョン1.2を参照してください。

図8-7 DTLSハンドシェーク

図8-7の説明が続きます
「図8-7 DTLSハンドシェーク」の説明

次のハンドシェーク・メッセージは、DTLSハンドシェーク中にクライアントとサーバーとの間で交換されます。

  1. ClientHello:

    クライアントは、それがサポートする最上位バージョンのDTLSおよび暗号化方式群のリストを含むサーバー情報を送信します。暗号化方式群の情報には、暗号化アルゴリズムと鍵のサイズが含まれます。

  2. HelloVerifyRequest:

    サーバーは、CookieとともにクライアントからのClientHelloメッセージに応答します。

  3. ClientHello:

    クライアントは、それがサポートする最上位バージョンのDTLSおよび暗号化方式群のリストとともに、2つ目のClientHelloメッセージをサーバーに送信します。HelloVerifyRequestで受け取ったCookieは、サーバーに送り返されます。

  4. ServerHello:

    サーバーは、クライアントとサーバーの両方がサポートする最上位バージョンのDTLSと最適な暗号化方式群を選択し、この情報をクライアントに送信します。

  5. (オプション) Certificate:

    サーバーはクライアントに証明書または証明書チェーンを送信します。証明書チェーンは通常、サーバーの公開鍵証明書で始まり、認証局のルート証明書で終わります。このメッセージはオプションで、サーバー認証を求められた場合に使用します

  6. (オプション) CertificateRequest:

    サーバーは、クライアントを認証する必要がある場合、クライアントに証明書要求を送信します。インターネット・アプリケーションでは、このメッセージが使われることはほとんどありません。

  7. (オプション) ServerKeyExchange:

    Certificateからの公開鍵情報が鍵交換を行うのに不十分な場合、サーバーはクライアントにサーバー鍵交換メッセージを送信します。たとえば、Diffie-Hellman (DH)に基づく暗号化方式群では、このメッセージにはサーバーのDH公開鍵が含まれています。

  8. ServerHelloDone:

    サーバーは、最初のネゴシエーション・メッセージを終了したことをクライアントに伝えます。

  9. (オプション) Certificate:

    サーバーがクライアントに証明書を要求すると、クライアントはサーバーが前に行ったように、その証明書チェーンを送信します。

    注意:

    クライアントに証明書を要求するのは、ごく一部のインターネット・サーバー・アプリケーションのみです。
  10. ClientKeyExchange:

    クライアントは、対称暗号化で使用する鍵を作成するために使用される情報を生成します。RSAでは、クライアントはサーバーの公開鍵でこの鍵情報を暗号化してサーバーに送信します。DHに基づく暗号化方式群の場合、このメッセージにはクライアントのDH公開鍵が含まれています。

  11. (オプション) CertificateVerify:

    このメッセージは、上述のとおりクライアントが証明書を提示する場合にクライアントによって送信されます。このメッセージは、サーバーにクライアントの認証処理を完了させるためのものです。このメッセージが使用されると、クライアントは暗号化ハッシュ関数で電子的に署名した情報を送信します。サーバーがクライアントの公開鍵でこの情報を復号化すれば、サーバーはクライアントを認証できます。

  12. ChangeCipherSpec:

    クライアントは、新しくネゴシエーションされたCipherSpecおよび鍵によって後続のデータが保護されることと、そのデータが暗号化されることをサーバーに伝えるメッセージを送信します。

  13. Finished:

    クライアントはサーバーに、セキュアなデータ通信を開始する準備ができたことを伝えます。

  14. ChangeCipherSpec:

    サーバーは、新しくネゴシエーションされたCipherSpecおよび鍵によって後続のデータが保護されることと、そのデータが暗号化されることをクライアントに伝えるメッセージを送信します。

  15. Finished:

    サーバーはクライアントに、セキュアなデータ通信を開始する準備ができたことを伝えます。これでDTLSハンドシェークが終了します。

ハンドシェークの再実行(再ネゴシエーション)

初期のハンドシェークが完了してアプリケーション・データが流れているとき、いずれの側からでも新しいハンドシェークをいつでも開始できます。特に重要な操作について、アプリケーションで強力な暗号化方式群を使用したり、サーバー・アプリケーションでクライアント認証が必要になる場合もあります。

理由は何であれ、新しいハンドシェークが既存の暗号化セッションに置き換わり、新しいセッションが確立されるまで、アプリケーション・データとハンドシェーク・メッセージが交互に配置されます。

アプリケーションでSSLEngine.beginHandshake()メソッドを使用して、新しいハンドシェークを開始できます。

注意:

再ネゴシエーションに関するプロトコルの問題が2009年に見つかりました。プロトコルおよびJava SE実装はいずれも修正されています。Transport Layer Security (TLS)再ネゴシエーションの問題を参照してください。

例8-4 DTLSハンドシェーク・ステータスおよび全体的ステータスの処理のサンプル・コード

void handshake(SSLEngine engine, DatagramSocket socket, SocketAddress peerAddr) throws Exception {
    boolean endLoops = false;
    // private static int MAX_HANDSHAKE_LOOPS = 60;
    int loops = MAX_HANDSHAKE_LOOPS;
    engine.beginHandshake();
    while (!endLoops && (serverException == null) && (clientException == null)) {
        if (--loops < 0) {
            throw new RuntimeException("Too many loops to produce handshake packets");
        }
        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
        if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
                hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
            ByteBuffer iNet;
            ByteBuffer iApp;
            if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                // Receive ClientHello request and other SSL/TLS/DTLS records
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                try {
                    socket.receive(packet);
                } catch (SocketTimeoutException ste) {
                    // Retransmit the packet if timeout
                    List <Datagrampacket> packets = onReceiveTimeout(engine, peerAddr);
                    for (DatagramPacket p : packets) {
                        socket.send(p);
                    }
                    continue;
                }
                iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
                iApp = ByteBuffer.allocate(1024);
            } else {
                iNet = ByteBuffer.allocate(0);
                iApp = ByteBuffer.allocate(1024);
            }
            SSLEngineResult r = engine.unwrap(iNet, iApp);
            SSLEngineResult.Status rs = r.getStatus();
            hs = r.getHandshakeStatus();
            if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                // The client maximum fragment size config does not work?
                throw new Exception("Buffer overflow: " +
                                    "incorrect client maximum fragment size");
            } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                // Bad packet, or the client maximum fragment size
                // config does not work?
                if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                    throw new Exception("Buffer underflow: " +
                                        "incorrect client maximum fragment size");
                } // Otherwise, ignore this packet
            } else if (rs == SSLEngineResult.Status.CLOSED) {
                endLoops = true;
            } // Otherwise, SSLEngineResult.Status.OK
            if (rs != SSLEngineResult.Status.OK) {
                continue;
            }
        } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
            // Call a function to produce handshake packets
            List <DatagramPacket> packets = produceHandshakePackets(engine, peerAddr);
            for (DatagramPacket p : packets) {
                socket.send(p);
            }
        } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
            runDelegatedTasks(engine);
        } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
            // OK, time to do application data exchange
            endLoops = true;
        } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
            endLoops = true;
        }
    }
    SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
    if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
        throw new Exception("Not ready for application data yet");
    }
}
DTLS接続での再送信の処理

信頼できる接続でのSSL/TLSでは、データは正しい順序で到着することが保証されており、再送信は不要です。ただし、DTLSの場合は、信頼できないメディアで機能することが多く、不足または遅延しているハンドシェーク・メッセージを再送信する必要があります。

SSLEngineクラスはトランスポートにまったく依存しない方法で動作し、アプリケーション層がすべての入出力を実行します。SSLEngineクラスは入出力を担当しないため、かわりにアプリケーションが、タイマーの提供、および再送信が必要なときのSSLEngineへの通知を担当します。アプリケーション層は、正しいタイムアウト値、およびタイムアウト・イベントをトリガーする時期を決定する必要があります。ハンドシェーク中にSSLEngineオブジェクトがHandshakeStatus.NEED_UNWRAP状態の場合、SSLEngine.wrap()の呼出しは、前のパケットが失われ、再送信する必要があることを意味します。そのような場合、SSLEngineクラスのDTLS実装は、必要に応じて前の必要なハンドシェーク・メッセージをラップしなおす役割を担います。

注意:

DTLSエンジンでは、ハンドシェーク・メッセージのみを正しく交換する必要があります。アプリケーション・データは、タイマーを必要とせずにパケット損失に対応できます。
アプリケーションでの再送信の処理

SSLEngine.unwrap()およびSSLEngine.wrap()は、アプリケーションで再送信を処理するために一緒に使用できます。

図8-8では、DTLSハンドシェークの再送信を処理する一般的なシナリオを示します。

図8-8 DTLSハンドシェークの再送信の状態のフロー

図8-8の説明が続きます
「図8-8 DTLSハンドシェークの再送信の状態のフロー」の説明
  1. DTLS SSLEngineのインスタンスを作成し初期化します。
    SSLEngineオブジェクトの作成を参照してください。DTLSハンドシェークの処理が開始します。DTLSハンドシェークを参照してください。
  2. ハンドシェークのステータスがHandshakeStatus.NEED_UNWRAPである場合は、ネットワークからのデータを待機します。
  3. タイマーがタイムアウトした場合、これは、前に配信されたハンドシェーク・メッセージが失われた可能性があることを示します。

    注意:

    DTLSハンドシェークの再送信では、SSLEngine.wrap()の呼出しに関する判定されるハンドシェーク・ステータスは、必ずしもHandshakeStatus.NEED_WRAPではありません。
  4. SSLEngine.wrap()を呼び出します。
  5. ラップされたパケットが配信されます。
アプリケーションでのバッファ済ハンドシェーク・メッセージの処理

データグラム・トランスポートでは、信頼できる順次のデータ配信は必要なく、提供されません。ハンドシェーク・メッセージは、失われることや、並替えが必要なことがあります。DTLS実装では、前のすべてのメッセージを受け取る前に、今後の処理のためにハンドシェーク・メッセージをバッファする必要があることがあります。

SSLEngineのDTLS実装は、ハンドシェーク・メッセージを並べ替える役割を担います。ハンドシェーク・メッセージのバッファリングと並替えは、アプリケーションに対して透過的です。

ただし、アプリケーションは、HandshakeStatus.NEED_UNWRAP_AGAINステータスを管理する必要があります。このステータスは、次のSSLEngine.unwrap()操作にはリモート側からのその他のデータが必要ないことを示します。

図8-9では、HandshakeStatus.NEED_UNWRAP_AGAINの使用の一般的なシナリオを示します。

図8-9 NEED_UNWRAP_AGAINでのDTLSバッファ済ハンドシェークの状態マシン

図8-9の説明が続きます
「図8-9 NEED_UNWRAP_AGAINでのDTLSバッファ済ハンドシェークの状態マシン」の説明
  1. DTLS SSLEngineのインスタンスを作成し初期化します。
    SSLEngineオブジェクトの作成を参照してください。DTLSハンドシェークの処理が開始します。DTLSハンドシェークを参照してください。
  2. オプション: ハンドシェークのステータスがHandshakeStatus.NEED_UNWRAPである場合は、ネットワークからのデータを待機します。
  3. オプション: ネットワーク・データを受け取った場合は、SSLEngine.unwrap()を呼び出します。
  4. 次の処理のハンドシェーク・ステータスを判定します。ハンドシェーク・ステータスは、HandshakeStatus.NEED_UNWRAP_AGAINHandshakeStatus.NEED_UNWRAPまたはHandshakeStatus.NEED_WRAPである可能性があります。
    • ハンドシェーク・ステータスがHandshakeStatus.NEED_UNWRAP_AGAINである場合は、SSLEngine.unwrap()を呼び出します。

    注意:

    HandshakeStatus.NEED_UNWRAP_AGAINステータスの場合、SSLEngine.unwrap()操作のためにネットワークからのその他のデータは必要ありません。
  5. さらに次の処理のハンドシェーク・ステータスを判定します。ハンドシェーク・ステータスは、HandshakeStatus.NEED_UNWRAP_AGAINHandshakeStatus.NEED_UNWRAPまたはHandshakeStatus.NEED_WRAPである可能性があります。

DTLSのためのSSLEngineオブジェクトの作成

次の例では、DTLSのためのSSLEngineオブジェクトの作成方法を示します。

注意:

サーバー名とポート番号は、サーバーとの通信には使用されません(すべてのトランスポートはアプリケーションが担当します)。それらは、DTLSセッション・キャッシングのためや、取得する必要があるサーバー・クレデンシャルを決定するためのKerberosベースの暗号化方式群の実装のために使用するJSSEプロバイダの手掛かりとなります。

例8-5 キーストアとしてPKCS12を使用してDTLSのためのSSLEngineクライアントを作成するサンプル・コード

次のサンプル・コードでは、キーストアとしてPKCS12を使用するDTLSのためのSSLEngineクライアントを作成します。

    import javax.net.ssl.*;
    import java.security.*;

    // Create and initialize the SSLContext with key material
    char[] passphrase = "passphrase".toCharArray();

    // First initialize the key and trust material
    KeyStore ksKeys = KeyStore.getInstance("PKCS12");
    ksKeys.load(new FileInputStream("testKeys"), passphrase);
    KeyStore ksTrust = KeyStore.getInstance("PKCS12");
    ksTrust.load(new FileInputStream("testTrust"), passphrase);

    // KeyManagers decide which key material to use
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
    kmf.init(ksKeys, passphrase);

    // TrustManagers decide whether to allow connections
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ksTrust);

    // Get an instance of SSLContext for DTLS protocols
    sslContext = SSLContext.getInstance("DTLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    // Create the engine
    SSLEngine engine = sslContext.createSSLengine(hostname, port);

    // Use engine as client
    engine.setUseClientMode(true);

例8-6 キーストアとしてPKCS12を使用してDTLSのためのSSLEngineサーバーを作成するサンプル・コード

次のサンプル・コードでは、キーストアとしてPKCS12を使用するDTLSのためのSSLEngineサーバーを作成します。
    import javax.net.ssl.*;
    import java.security.*;

    // Create and initialize the SSLContext with key material
    char[] passphrase = "passphrase".toCharArray();

    // First initialize the key and trust material
    KeyStore ksKeys = KeyStore.getInstance("PKCS12");
    ksKeys.load(new FileInputStream("testKeys"), passphrase);
    KeyStore ksTrust = KeyStore.getInstance("PKCS12");
    ksTrust.load(new FileInputStream("testTrust"), passphrase);

    // KeyManagers decide which key material to use
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
    kmf.init(ksKeys, passphrase);

    // TrustManagers decide whether to allow connections
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ksTrust);

    // Get an SSLContext for DTLS Protocol without authentication
    sslContext = SSLContext.getInstance("DTLS");
    sslContext.init(null, null, null);

    // Create the engine
    SSLEngine engine = sslContext.createSSLeEngine(hostname, port);

    // Use the engine as server
    engine.setUseClientMode(false);

    // Require client authentication
    engine.setNeedClientAuth(true);

DTLSデータの生成と処理

DTLSハンドシェークとSSL/TLSハンドシェークでは、データの生成と処理が同様に行われます。(SSL/TLSデータの生成と処理を参照。)それらは両方とも、それぞれSSLEngine.wrap()メソッドとSSLEngine.wrap()メソッドを使用してネットワーク・データを生成および使用します。

次の図では、一般的なDTLSハンドシェーク時の状態マシンと、対応するメッセージおよびステータスを示します。

図8-10 DTLSハンドシェーク中の状態マシン

図8-10の説明が続きます。
「図8-10 DTLSハンドシェーク中の状態マシン」の説明

SSL/TLSとDTLSのSSLEngine.wrap()メソッドの違い

DTLS用のSSLEngine.wrap()メソッドは、SSL/TLSとは次のように異なります。
  • SSLEngineのSSL/TLS実装では、SSLEngine.wrap()の出力バッファに、1つ以上のTLSレコードが含まれます(TLSv1 BEAST暗号ブロック連鎖の脆弱性が原因)。

  • SSLEngineのDTLS実装では、すべてのDTLSレコードをマーシャリングしデータグラム層に個別に配信できるようにSSLEngine.wrap()の出力バッファに最大で1つのレコードが含まれます。

注意:

SSLEngine.wrap()によって生成された各レコードは、SSLParameters.getMaximumPacketSize()で指定された最大パケット・サイズ制限に従っている必要があります。
 

SSLEngineの操作のステータスについて

SSLEngineのステータスは、SSLEngineResult.Statusによって表されます。

エンジンのステータスとアプリケーションの取る必要があるアクションを示すため、SSLEngine.wrap()メソッドとSSLEngine.unwrap()メソッドは、例8-2で示すようなSSLEngineResultインスタンスを返します。このSSLEngineResultオブジェクトには、エンジンの全体的なステータスとハンドシェークのステータスの2つのステータス情報が格納されます。

全体的なステータスは、SSLEngineResult.Status enumによって表されます。次のステータスがあります。

OK
エラーはありませんでした。
CLOSED
操作によってSSLEngineが閉じられたか、操作はすでに閉じられていたために完了できませんでした。
BUFFER_UNDERFLOW
入力バッファのデータが不十分で、アプリケーションがピアから追加のデータを取得する(ネットワークから追加のデータを読み取ることによってなど)必要があることを示しています。
BUFFER_OVERFLOW
出力バッファに結果を保持するためのスペースが不足しており、アプリケーションは目的のバッファをクリアするか大きくする必要があることを示しています。

例8-7は、SSLEngine.unwrap()メソッドのBUFFER_UNDERFLOWおよびBUFFER_OVERFLOWステータスの処理方法を示しています。SSLSession.getApplicationBufferSize()およびSSLSession.getPacketBufferSize()を使用して、バイト・バッファのサイズを決定します。

ハンドシェークのステータスは、SSLEngineResult.HandshakeStatus enumによって表されます。それらは、ハンドシェークが完了しているかどうか、発信側はピアから追加のハンドシェーク・データを取得する必要があるかどうか、またピアに追加のハンドシェーク・データを送信する必要があるかどうかなどを表します。使用可能なステータスは次のとおりです。

FINISHED
SSLEngineがハンドシェークを完了したところです。
NEED_TASK
SSLEngineがハンドシェークを続行するには、事前に1つ(または複数の)委譲されたタスクの結果が必要です。
NEED_UNWRAP
SSLEngineがハンドシェークを続行するには、事前にリモート側からデータを受信する必要があります。
NEED_UNWRAP_AGAIN
SSLEngineは、ハンドシェークを続行するにはアンラップする必要があります。この値は、まだ解釈されていないデータをリモート側から以前に受け取っており再度受け取る必要がないことを示しています。このデータはJSSEフレームワークに受信されていますが、まだ処理されていません。
NEED_WRAP
SSLEngineがハンドシェークを続行するには、事前にリモート側にデータを送信する必要があるため、SSLEngine.wrap()を呼び出すようにしてください。
NOT_HANDSHAKING
SSLEngineは現在ハンドシェークしていません。

結果ごとに2つのステータスがあることにより、SSLEngineは、アプリケーションがハンドシェークへの応答におけるアクションとwrap()およびunwrap()メソッドの全体のステータスを表すアクションという2つのアクションを取る必要があることを示すことができます。たとえばエンジンは、1回のSSLEngine.unwrap()呼出しの結果として、SSLEngineResult.Status.OKを返すことで、入力データが正常に処理されたことを示し、SSLEngineResult.HandshakeStatus.NEED_UNWRAPを返すことで、ハンドシェークを継続するためにアプリケーションがピアからさらにSSL/TLS/DTLSエンコード・データを取得し、もう一度SSLEngine.unwrap()に供給する必要があることを示します。お気付きのとおり、先の例はかなり単純化されていますが、これらすべてのステータスを適正に処理するにはコードをかなり拡張する必要があります。

例8-9例8-8に、wrap()メソッドおよびunwrap()メソッドのハンドシェーク・ステータスと全体のステータスをチェックすることによってハンドシェーク・データを処理する方法を示します。

例8-7 BUFFER_UNDERFLOWおよびBUFFER_OVERFLOWの処理のサンプル・コード

次のコード例では、BUFFER_UNDERFLOWステータスとBUFFER_OVERFLOWステータスを処理する方法を示します。

    SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
    switch (res.getStatus()) {

    case BUFFER_OVERFLOW:
            // Maybe need to enlarge the peer application data buffer.
        if (engine.getSession().getApplicationBufferSize() > peerAppData.capacity()) {
            // enlarge the peer application data buffer
        } else {
            // compact or clear the buffer
        }
        // retry the operation
    break;

    case BUFFER_UNDERFLOW:
        // Maybe need to enlarge the peer network packet buffer
        if (engine.getSession().getPacketBufferSize() > peerNetData.capacity()) {
        // enlarge the peer network packet buffer
        } else {
        // compact or clear the buffer
        }
        // obtain more inbound network data and then retry the operation
       break;

       // Handle other status: CLOSED, OK
       // ...
    }

例8-8 ハンドシェーク・ステータスと全体のステータスの確認と処理のサンプル・コード

次のコード例では、wrap()メソッドとunwrap()メソッドのハンドシェーク・ステータスと全体のステータスをチェックすることによって、ハンドシェーク・データを処理する方法を示します。

void doHandshake(SocketChannel socketChannel, SSLEngine engine,
    ByteBuffer myNetData, ByteBuffer peerNetData) throws Exception {

    // Create byte buffers to use for holding application data
    int appBufferSize = engine.getSession().getApplicationBufferSize();
    ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
    ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);

    // Begin handshake
    engine.beginHandshake();
    SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();

    // Process handshaking message
    while (hs != SSLEngineResult.HandshakeStatus.FINISHED &&
        hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {

        switch (hs) {

        case NEED_UNWRAP:
            // Receive handshaking data from peer
            if (socketChannel.read(peerNetData) < 0) {
                // The channel has reached end-of-stream
            }

            // Process incoming handshaking data
            peerNetData.flip();
            SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
            peerNetData.compact();
            hs = res.getHandshakeStatus();

            // Check status
            switch (res.getStatus()) {
            case OK :
                // Handle OK status
                break;

            // Handle other status: BUFFER_UNDERFLOW, BUFFER_OVERFLOW, CLOSED
            // ...
            }
            break;

        case NEED_WRAP :
            // Empty the local network packet buffer.
            myNetData.clear();

            // Generate handshaking data
            res = engine.wrap(myAppData, myNetData);
            hs = res.getHandshakeStatus();

            // Check status
            switch (res.getStatus()) {
            case OK :
                myNetData.flip();

                // Send the handshaking data to peer
                while (myNetData.hasRemaining()) {
                    socketChannel.write(myNetData);
                }
                break;

            // Handle other status:  BUFFER_OVERFLOW, BUFFER_UNDERFLOW, CLOSED
            // ...
            }
            break;

        case NEED_TASK :
            // Handle blocking tasks
            break;

            // Handle other status:  // FINISHED or NOT_HANDSHAKING
            // ...
        }
    }

    // Processes after handshaking
    // ...
}

例8-9 DTLSハンドシェーク・ステータスおよび全体的ステータスの処理のサンプル・コード

次のコード例では、DTLSハンドシェーク・ステータスを処理する方法を示します。

void handshake(SSLEngine engine, DatagramSocket socket,
               SocketAddress peerAddr) throws Exception {
    boolean endLoops = false;
    // private static int MAX_HANDSHAKE_LOOPS = 60;
    int loops = MAX_HANDSHAKE_LOOPS;
    engine.beginHandshake();
    while (!endLoops && (serverException == null) && (clientException == null)) {
        if (--loops < 0) {
            throw new RuntimeException("Too many loops to produce handshake packets");
        }
        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
        if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
                hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
            ByteBuffer iNet;
            ByteBuffer iApp;
            if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                // receive ClientHello request and other SSL/TLS/DTLS records
                byte[] buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                try {
                    socket.receive(packet);
                } catch (SocketTimeoutException ste) {
                    // retransmit the packet if timeout
                    List <Datagrampacket> packets =
                        onReceiveTimeout(engine, peerAddr);
                    for (DatagramPacket p : packets) {
                        socket.send(p);
                    }
                    continue;
                }
                iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
                iApp = ByteBuffer.allocate(1024);
            } else {
                iNet = ByteBuffer.allocate(0);
                iApp = ByteBuffer.allocate(1024);
            }
            SSLEngineResult r = engine.unwrap(iNet, iApp);
            SSLEngineResult.Status rs = r.getStatus();
            hs = r.getHandshakeStatus();
            if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                // the client maximum fragment size config does not work?
                throw new Exception("Buffer overflow: " +
                                    "incorrect client maximum fragment size");
            } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                // bad packet, or the client maximum fragment size
                // config does not work?
                if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                    throw new Exception("Buffer underflow: " +
                                        "incorrect client maximum fragment size");
                } // otherwise, ignore this packet
            } else if (rs == SSLEngineResult.Status.CLOSED) {
                endLoops = true;
            }   // otherwise, SSLEngineResult.Status.OK:
            if (rs != SSLEngineResult.Status.OK) {
                continue;
            }
        } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
            List <DatagramPacket> packets =
                // Call a function to produce handshake packets
                produceHandshakePackets(engine, peerAddr);
            for (DatagramPacket p : packets) {
                socket.send(p);
            }
        } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
            runDelegatedTasks(engine);
        } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
            // OK, time to do application data exchange.
            endLoops = true;
        } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
            endLoops = true;
        }
    }
    SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
    if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
        throw new Exception("Not ready for application data yet");
    }
}

ブロック・タスクの処理

ハンドシェーク時に、SSLEngineはブロックしたり処理に長い時間がかかったりするタスクに直面することがあります。たとえば、TrustManagerは、リモート証明書検証サービスに接続する必要があることがあります。またはKeyManagerは、クライアント認証の一環として使用する証明書を決定するようにユーザーに求める必要があることがあります。SSLEngineの非ブロック性を保持するため、エンジンはそれらのタスクに直面した場合にSSLEngineResult.HandshakeStatus.NEED_TASKを返します。このステータスを受け取ると、アプリケーションはSSLEngine.getDelegatedTask()を呼び出してタスクを取得し、その要件に適したスレッド・モデルを使用してタスクを処理すべきです。アプリケーションは、たとえばスレッド・プールからスレッドを入手してタスクを処理し、メイン・スレッドは他の入出力を処理できます。

次のコードは、新しく作成されたスレッドで各タスクを実行します。

if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
    Runnable task;
    while ((task = engine.getDelegatedTask()) != null) {
        new Thread(task).start();
    }
}

SSLEngineは、未処理のタスクすべてが完了するまで、将来のwrap()およびunwrap()呼出しをブロックします。

SSL/TLS/DTLS接続の停止

SSL/TLS/DTLS接続を正しい順序で停止するため、SSL/TLS/DTLSプロトコルではクローズ・メッセージを送信する必要があります。したがって、アプリケーションがSSL/TLS/DTLS接続を終了するときは、最初にSSLEngineからクローズ・メッセージを取得し、そのトランスポート・メカニズムを使用してピアに送信して、最後にトランスポート・メカニズムを停止する必要があります。例8-10に、これを示します。

SSLEngineを明示的に閉じるアプリケーションの他に、SSLEngineは、ピアによって(ハンドシェーク・データを処理している間のクローズ・メッセージの受取りによる)、またはアプリケーション・データやハンドシェーク・データを処理している間に、SSLExceptionをスローすることによって示される、エラーが発生しているSSLEngineによって閉じられることがあります。そのような場合、アプリケーションはSSLEngine.wrap()を呼び出してクローズメッセージを取得し、SSLEngine.isOutboundDone()trueを返すまで(例8-10に示すように)、またはSSLEngineResult.getStatus()CLOSEDを返すまで、それをピアに送信する必要があります。

正常なシャットダウンに加え、クローズメッセージが交換される前にトランスポート・リンクを切断する非常シャットダウンもあります。前の例では、アプリケーションは非ブロックSocketChannelからの読取りを実行しようとすると-1またはIOExceptionを受け取り、非ブロックSocketChannelへの書込みを実行しようとするとIOExceptionを受け取ります。入力データの最後に達したら、engine.closeInbound()を呼び出して、SSLEngineによって、リモートのピアがSSL/TLS/DTLSの観点から正常に閉じたことを検証する必要があります。次に、アプリケーションが例8-10の手順を使用して正常な停止を試みる必要があります。SSLSocketと異なり、SSLEngineを使用するアプリケーションは、多くの状態移行、ステータスおよびプログラミングを処理する必要があります。SSLEngineの使用を表すサンプル・コードを参照してください。

例8-10 SSL/TLS/DTLS接続の停止のサンプル・コード

次のコード例では、SSL/TLS/DTLS接続の停止方法を示します。

// Indicate that application is done with engine
engine.closeOutbound();

while (!engine.isOutboundDone()) {
    // Get close message
    SSLEngineResult res = engine.wrap(empty, myNetData);

    // Check res statuses

    // Send close message to peer
    while(myNetData.hasRemaining()) {
        int num = socketChannel.write(myNetData);
        if (num == 0) {
            // no bytes written; try again later
        }
        myNetData().compact();
    }
}

// Close transport
socketChannel.close();

SSLSessionとExtendedSSLSession

javax.net.ssl.SSLSessionインタフェースは、SSLSocketまたはSSLEngine接続の2つのピアの間でネゴシエーションされたセキュリティ・コンテキストを表します。一度確立されたセッションは、同じ2つのピアの間で接続されるそのあとのSSLSocketまたはSSLEngineオブジェクトによっても共有できます。

場合によっては、ハンドシェーク中に取り決めたパラメータが、後のハンドシェークでトラストについて判断を下す際に必要になることもあります。たとえば、有効な署名アルゴリズムのリストによって、認証に使用できる証明書タイプが制限されることがあります。SSLSessionはハンドシェークに、SSLSocketまたはSSLEnginegetHandshakeSession()を呼び出すことによって取得できます。TrustManagerまたはKeyManagerの実装により、getHandshakeSession()メソッドを使用して、それらが判断を下す際に役立つセッション・パラメータに関する情報を取得できます。

完全に初期化されたSSLSessionには暗号化方式群が含まれ、これは、リモート・ピアのネットワーク・アドレスに関する権限のないヒントと同様、セキュアなソケットの通信でも使用され、作成や最後の使用の時点などで、管理情報としても使用されます。セッションには、SSLSocketまたはSSLEngine接続による通信を暗号化して整合性を保証する暗号鍵を作成するために使用される、ピア間でネゴシエーションされた共用マスターとなる秘密も含まれます。このマスターとなる秘密の値は、基盤となるセキュアなソケット実装のみに伝えられ、SSLSession APIによって公開されません。

ExtendedSSLSessionは、追加のセッション属性をサポートするようにSSLSessionインタフェースを拡張します。ExtendedSSLSessionクラスは、ローカル実装およびピアによってサポートされる署名アルゴリズムを記述するメソッドを追加します。ExtendedSSLSessionインスタンスで呼び出されるgetRequestedServerNames()メソッドは、要求されたServer Name Indication (SNI)拡張でSNIServerNameオブジェクトのリストを取得するために使用されます。サーバーは、要求されたサーバー名を使用して、適切な認証証明書の選択やセキュリティ・ポリシーのその他の側面をガイドする必要があります。クライアントは、要求されたサーバー名を使用して、ピアの識別情報のエンドポイントの識別やセキュリティ・ポリシーのその他の側面をガイドする必要があります。

SSLSessionでのgetPacketBufferSize()およびgetApplicationBufferSize()メソッドの呼出しは、SSLEngineによって使用される適切なバッファ・サイズを決定するために使用します。

注意:

SSL/TLSプロトコルは、実装が最大16Kバイト(KB)のプレーン・テキストを含むパケットを生成することを指定します。ただし、一部の実装はこの指定に違反し、32Kバイトまでの大きいレコードを生成します。SSLEngine.unwrap()コードが大きいインバウンド・パケットを検出した場合、SSLSessionから返されるバッファ・サイズは動的に更新されます。アプリケーションは常に、必要に応じてBUFFER_OVERFLOWおよびBUFFER_UNDERFLOWのステータスをチェックして、対応するバッファを拡大するべきです。SSLEngineの操作のステータスについてを参照してください。SunJSSE初値に標準に準拠した16Kバイトのレコードを送信し、32Kバイトの着信レコードを許可します。回避策については、「JSSEのカスタマイズ」のシステム・プロパティjsse.SSLEngine.acceptLargeFragmentsを参照してください。

HttpsURLConnectionクラス

javax.net.ssl.HttpsURLConnectionjava.net.HttpURLConnectionクラスを拡張し、HTTPS固有の機能のサポートを追加します。

HTTPSプロトコルはHTTPプロトコルに似ていますが、データを要求または受信する前に、まずSSL/TLSソケットを利用してセキュアなチャネルを確立してピアの識別情報を検証します(符号化方式の選択とリモート・エンティティの検証を参照)。javax.net.ssl.HttpsURLConnectionjava.net.HttpURLConnectionクラスを拡張し、HTTPS固有の機能のサポートを追加します。HTTPS URLの構築方法と使用方法の詳細は、java.net.URLjava.net.URLConnectionjava.net.HttpURLConnectionおよびjavax.net.ssl.HttpsURLConnectionクラスを参照してください。

HttpsURLConnectionインスタンスを取得する際、URLConnection.connect()メソッドを使用して実際にネットワーク接続を開始する前に、複数のHTTPおよびHTTPSパラメータを構成できます。これらについては、次を参照してください。

割当て済のSSLSocketFactoryの設定

状況によっては、HttpsURLConnectionのインスタンスによって使用されるSSLSocketFactoryを指定した方がよい場合があります。たとえば、デフォルト実装ではサポートされないプロキシ・タイプを使用してトンネリングを行いたいと考える場合があります。新しいSSLSocketFactoryは、すでに必要なトンネリングの完了したソケットを返すことができます。このため、HttpsURLConnectionは追加のプロキシを使用できます。

HttpsURLConnectionクラスには、ロード時に割り当てられたデフォルトのSSLSocketFactoryがあります(これはSSLSocketFactory.getDefault()メソッドによって返されるファクトリです)。以降、HttpsURLConnectionのインスタンスは、staticメソッドHttpsURLConnection.setDefaultSSLSocketFactoryによってクラスに新しいデフォルトのSSLSocketFactoryが割り当てられるまで、現在のデフォルトのSSLSocketFactoryを継承します。HttpsURLConnectionのインスタンスが作成された後、setSSLSocketFactory()メソッドへの呼出しにより、このインスタンス上の継承されたSSLSocketFactoryをオーバーライドできます。

注意:

デフォルトのstatic SSLSocketFactoryの変更はHttpsURLConnectionの既存のインスタンスに影響しません。既存のインスタンスを変更するには、setSSLSocketFactory()メソッドの呼出しが必要です。

getSSLSocketFactory()メソッドまたはgetDefaultSSLSocketFactory()メソッドを呼び出すことにより、インスタンスごと、またはクラスごとにSSLSocketFactoryを取得できます。

割当て済のHostnameVerifierの設定

URLのホスト名がSSL/TLSハンドシェークの一部として受け取ったクレデンシャル内のホスト名と一致しない場合、URL不正行為が発生した可能性があります。実装で、十分な確信を持ってホスト名の一致を判断できない場合、SSL実装で、インスタンスの割当て済HostnameVerifierのコールバックを実行して、より詳しいチェックを行います。ホスト名ベリファイアは、ホスト名パターン・マッチングを実行したり、対話型のダイアログ・ボックスを表示したりなど、判定を下すために必要なあらゆるステップを取ることができます。ホスト名ベリファイアによる検証に失敗した場合は、接続が切断されます。ホスト名の検証に関する詳細については、RFC 2818を参照してください。

setHostnameVerifier()メソッドおよびsetDefaultHostnameVerifier()メソッドの動作は、インスタンスごと、またはクラスごとにHostnameVerifierオブジェクトが割り当てられ、現在の値がgetHostnameVerifier()メソッドまたはgetDefaultHostnameVerifier()メソッドの呼出しによって取得できる点で、setSSLSocketFactory()メソッドおよびsetDefaultSSLSocketFactory()メソッドと似ています。

サポート・クラスとインタフェース

このセクションのクラスとインタフェースは、SSLSocketFactorySSLServerSocketFactoryおよびSSLEngineオブジェクトを作成するために使用されるSSLContextオブジェクトの作成と初期化をサポートするために提供されます。サポート・クラスとインタフェースはjavax.net.sslパッケージに含まれています。

この項で説明する3つのクラス(SSLContextクラスKeyManagerFactoryクラスおよびTrustManagerFactoryクラス)はエンジン・クラスです。エンジン・クラスとは、特定のアルゴリズムのAPIクラス(SSLContextの場合はプロトコル)です。その実装では1つまたは複数の暗号化サービス・プロバイダ(プロバイダ)パッケージで提供されることがあります。JCAの設計の原則およびエンジン・クラスとアルゴリズムを参照してください。

JSSEに標準で付属するSunJSSEプロバイダは、SSLContextKeyManagerFactoryおよびTrustManagerFactory実装を提供し、標準のjava.security APIではエンジン・クラスの実装も提供します。表8-6では、SunJSSEによって提供される実装をリストします。

表8-6 SunJSSEによって提供される実装

実装されるエンジン・クラス アルゴリズムまたはプロトコル
KeyStore PKCS12
KeyManagerFactory PKIX、SunX509
TrustManagerFactory PKIX (X509またはSunPKIX)、SunX509

SSLContext
SSLv3[1]、TLSv1、TLSv1.1、TLSv1.2、DTLSv1.0、DTLSv1.2

脚注1: JDK 8u31リリース以降、SSLv3プロトコル(Secure Socket Layer)は無効になっており、デフォルトでは使用できません。<java_home>/conf/security/java.securityファイルのjava.security.Securityプロパティjdk.tls.disabledAlgorithmsを参照してください。SSLv3が絶対に必要な場合は、java.securityファイルのjdk.tls.disabledAlgorithmsプロパティからSSLv3を削除するか、JSSEが初期化される前にこのセキュリティ・プロパティを動的に設定すれば、プロトコルを再度アクティブにできます。デプロイ・レベルでSSLv3プロトコルを有効にするには、前の手順に従った後、deployment.security.SSLv3=trueという行をdeployment.propertiesファイルに追加します。

SSLContextクラス

javax.net.ssl.SSLContextクラスは、セキュアなソケット・プロトコルの実装のエンジン・クラスです。このクラスのインスタンスは、SSLSocketSSLServerSocketおよびSSLEngineのファクトリの役目を果たします。SSLContextオブジェクトは、そのコンテキストの下で作成されたすべてのオブジェクトで共有される状態情報をすべて保持します。たとえば、セッションの状態は、ソケット・ファクトリにより作成され、コンテキストにより提供されたソケットによってハンドシェーク・プロトコルが取り決められると、SSLContextと関連付けられます。キャッシュに書き込まれたこれらのセッションは、同じコンテキストで作成された別のソケットで再利用したり共有することができます。

各インスタンスは、認証の実行に必要な鍵、証明書チェーン、および信頼されたルートCA証明書を使ってinitメソッドで構成されます。この構成は、鍵とトラスト・マネージャの形で提供されます。これらのマネージャは認証をサポートし、コンテキストによってサポートされる暗号群の鍵合意を提供します。

現在は、X.509ベースのマネージャだけがサポートされています。

SSLContextクラスの取得と初期化

SSLContextクラスは、SSLSocketFactoryクラスまたはSSLServerSocketFactoryクラスを作成するために使用されます。

SSLContextを取得して初期化するには、次の2つの方法があります。

  • 最も簡単な方法は、SSLSocketFactoryまたはSSLServerSocketFactoryクラスでSSLContext.getDefault staticメソッドを呼び出すことです。このメソッドは、デフォルトのKeyManagerTrustManagerおよびSecureRandom (セキュアな乱数ジェネレータ)を使用してデフォルトのSSLContextを作成します。デフォルトのKeyManagerFactoryおよびTrustManagerFactoryを使用すると、KeyManagerおよびTrustManagerがそれぞれ作成されます。使用する鍵データは、「デフォルトのキーストアとトラストストア、ストア・タイプ、およびストア・パスワードのカスタマイズ」で説明するシステム・プロパティで指定されるデフォルトのキーストアおよびトラストストアにあります。
  • 作成したコンテキストの動作を呼出し側で最も厳密に制御できるようにする方法は、SSLContextクラスでstaticメソッドSSLContext.getDefaultを呼び出してから、そのインスタンスの適切なinit()メソッドを呼び出してコンテキストを初期化することです。init()メソッドの1つのバリアントは、KeyManagerオブジェクトの配列、TrustManagerオブジェクトの配列、およびSecureRandomオブジェクトの3つの引数を取ります。適切なインタフェースを実装するか、実装を生成するKeyManagerFactoryクラスとTrustManagerFactoryクラスを使用して、KeyManagerオブジェクトとTrustManagerオブジェクトが作成されます。その後、KeyManagerFactoryTrustManagerFactoryを、TrustManagerFactoryまたはKeyManagerFactoryクラスのinit()メソッドへの引数として渡されたKeyStoreに含まれる鍵データでそれぞれ初期化できます。最後に、TrustManagerFactorygetTrustManagers()メソッドとKeyManagerFactorygetKeyManagers()メソッドを呼び出して、トラスト・データまたは鍵データの型ごとに1つずつトラスト・マネージャまたはキー・マネージャの配列を取得できます。

SSL接続が確立されると、SSLSessionが作成され、これには設定した識別情報、使用する暗号化方式群などの様々な情報が含まれます。次にSSLSessionを使用して、2つのエンティティ間の進行中の関係と状態情報が記述されます。各SSL接続には、一度に1つのセッションが含まれますが、そのセッションがエンティティ間の接続に、同時に、または連続して何度も使用されることがあります。

SSLContextオブジェクトの作成

他のJCAプロバイダ・ベースのエンジン・クラスと同様に、SSLContextオブジェクトは、SSLContextクラスのgetInstance()ファクトリ・メソッドを使用して作成されます。このようなstaticメソッドは、最低限要求されたセキュアなソケット・プロトコルを実装するインスタンスを返します。返されるインスタンスはその他のプロトコルも実装できます。たとえば、getInstance("TLSv1")はTLSv1、TLSv1.1およびTLSv1.2を実装するインスタンスを返すことができます。getSupportedProtocols()メソッドは、このコンテキストからSSLSocketSSLServerSocketまたはSSLEngineが作成されたときに、サポート対象のプロトコルのリストを返します。実際のSSL接続でどのプロトコルを有効にするかは、setEnabledProtocols(String[] protocols)メソッドを使用して制御できます。

注意:

SSLSocketFactory.getDefault()メソッドを呼び出すと、SSLContextオブジェクトが自動的に作成され、初期化され、SSLSocketFactoryクラスに静的に割り当てられます。したがって、デフォルト動作をオーバーライドする場合を除き、SSLContextオブジェクトを直接作成したり初期化したりする必要はありません。

getInstance()ファクトリ・メソッドを呼び出してSSLContextオブジェクトを作成するには、プロトコル名を指定する必要があります。または、要求されたプロトコルの実装を提供するプロバイダを次のように指定することもできます。

  • public static SSLContext getInstance(String protocol);
  • public static SSLContext getInstance(String protocol, String provider);
  • public static SSLContext getInstance(String protocol, Provider provider);

プロトコル名のみを指定すると、システムは、要求されたプロトコルの実装がその環境で利用できるかどうかを判断します。複数の実装がある場合、より望ましいものがあるかどうかを判断します。

プロトコル名とプロバイダの両方を指定すると、システムは、要求されたプロトコルの実装が要求されたプロバイダにあるかどうかを判断します。実装がない場合は、例外がスローされます。

プロトコルは、希望するセキュアなソケット・プロトコルを記述する文字列(TLSなど)です。SSLContextオブジェクトの一般的なプロトコル名は、Javaセキュリティ標準アルゴリズム名仕様で定義されています。

SSLContextは次のように取得できます。

SSLContext sc = SSLContext.getInstance("TLS");

新しく作成されたSSLContextは、initメソッドを呼び出すことによって初期化すべきです。

public void init(KeyManager[] km, TrustManager[] tm, SecureRandom random);

KeyManager[]パラメータがnullの場合、このコンテキストには空のKeyManagerが定義されます。TrustManager[]パラメータがnullの場合、インストールされたセキュリティ・プロバイダは、TrustManagerFactoryクラスの最も優先度の高い実装で検索され(TrustManagerFactoryクラスを参照)、そこから適切なTrustManagerが取得されます。同様に、SecureRandomパラメータもNULLにできます。その場合、デフォルト実装が使用されます。

内部のデフォルト・コンテキストが使用される場合(SSLContextSSLSocketFactory.getDefault()またはSSLServerSocketFactory.getDefault()によって作成されるなど)、デフォルトのKeyManagerとTrustManagerが作成されます。また、デフォルトのSecureRandom実装も選択されます。

TrustManagerインタフェース

TrustManagerは、提示された認証クレデンシャルの信頼性を判定します。信頼できないクレデンシャルの場合、接続は切断されます。セキュアなソケット・ピアのリモート識別情報を認証するには、1つまたは複数のTrustManagerオブジェクトでSSLContextオブジェクトを初期化する必要があります。サポートされる認証メカニズムのそれぞれに対し、TrustManagerを1つずつ渡す必要があります。SSLContextの初期化にnullが渡されると、自動的にトラスト・マネージャが作成されます。通常、単一のトラスト・マネージャは、X.509公開鍵証明書(X509TrustManagerなど)に基づく認証をサポートしています。セキュアなソケット実装には、共有の秘密鍵、Kerberos、またはほかのメカニズムに基づく認証をサポートするものもあります。

TrustManagerオブジェクトはTrustManagerFactoryによって、またはインタフェースの具体的な実装を提供することによって作成されます。

TrustManagerFactoryクラス

javax.net.ssl.TrustManagerFactoryはプロバイダ・ベースのサービスのエンジン・クラスで、1つまたは複数の型のTrustManagerオブジェクトのファクトリとして動作します。これはプロバイダ・ベースなので、追加のファクトリを実装して構成し、より高度なサービスを提供したり、インストール固有の認証ポリシーを実装する追加または代替のトラスト・マネージャを提供できます。

TrustManagerFactoryの作成

このクラスのインスタンスはSSLContextと同様の方法で作成しますが、getInstanceメソッドにプロトコル名ではなくアルゴリズム名の文字列を渡す点が異なります。

TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm, String provider);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm, Provider provider);

呼出しの例を次に示します。

TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE");

前の呼出しは、SunJSSEプロバイダのPKIXトラスト・マネージャ・ファクトリのインスタンスを作成します。このファクトリを使用して、X.509 PKIXベースの証明書パス妥当性検査を実行するトラスト・マネージャを作成できます。

SSLContextを初期化する場合は、トラスト・マネージャ・ファクトリから作成したトラスト・マネージャを使用するか、CertPath APIなどを使用して独自のトラスト・マネージャを記述できます。Java PKIプログラマーズ・ガイドを参照してください。X509TrustManagerインタフェースを使用してトラスト・マネージャを実装する場合は、トラスト・マネージャ・ファクトリを使用する必要はありません。

新しく作成されたファクトリは、init()メソッドの1つを呼び出すことによって初期化してください。

public void init(KeyStore ks);
public void init(ManagerFactoryParameters spec);

使用するTrustManagerFactoryに適したinit()メソッドを呼び出します。不明な場合は、プロバイダのベンダーに問い合わせてください。

SunX509 TrustManagerFactoryなど、SunJSSEプロバイダが提供するファクトリは多数ありますが、TrustManagerFactoryを初期化するために必要な情報はKeyStoreのみであるため、最初にinitメソッドを呼び出すのが適切です。TrustManagerFactoryKeyStoreに、認証チェック中に信頼すべきリモート証明書の情報を問い合わせます。

プロバイダでは、KeyStore以外の初期化パラメータを必要とすることがあります。そのプロバイダのユーザーは、プロバイダによる定義に従って、適切なManagerFactoryParametersの実装を渡すことが期待されます。そのあと、プロバイダはManagerFactoryParameters実装の特定のメソッドを呼び出し、必要な情報を取得できます。

たとえば、TrustManagerFactoryプロバイダが、そのプロバイダを使用するアプリケーションからの初期化パラメータB、RおよびSを必要としているとします。KeyStore以外の初期化パラメータを必要とするすべてのプロバイダと同様に、プロバイダはアプリケーションがManagerFactoryParametersの特定のサブインタフェースを実装するクラスのインスタンスを提供することを必要とします。たとえば、プロバイダは呼出し側のアプリケーションがMyTrustManagerFactoryParamsのインスタンスを実装して作成し、2つ目のinit()メソッドに渡すことを必要としているとします。次の例に、MyTrustManagerFactoryParamsがどのように見えるかを示します。

public interface MyTrustManagerFactoryParams extends ManagerFactoryParameters {
  public boolean getBValue();
  public float getRValue();
  public String getSValue();
}

一部のトラスト・マネージャでは、KeyStoreオブジェクトやその他のパラメータで明示的に初期化されなくても、信頼性を判定できます。たとえば、LDAP経由でローカル・ディレクトリ・サービスのトラスト・データにアクセスしたり、オンラインの証明書ステータスチェックサーバーをリモートで使用したり、または標準のローカル位置からデフォルトのトラスト・データにアクセスすることもできます。

PKIX TrustManagerのサポート

デフォルトのトラスト・マネージャのアルゴリズムは「PKIX」です。これは、java.securityファイルのssl.TrustManagerFactory.algorithmプロパティを編集することによって変更できます。

PKIXトラスト・マネージャ・ファクトリは、インストールされたセキュリティ・プロバイダのCertPath PKIX実装(PKIプログラマーズ・ガイドの概要を参照)を使用します。トラスト・マネージャ・ファクトリを初期化するには、通常のinit(KeyStores)メソッドを使用するか、CertPathTrustManagerParametersクラスを使用して、CertPathパラメータをPKIXトラスト・マネージャに渡します。

例8-11では、トラスト・マネージャを取得して特定のLDAP証明書ストアを使用する方法と、失効チェックを有効にする方法を示します。

TrustManagerFactory.init(KeyStore)メソッドが使用される場合は、失効チェックが無効にされる点を除いて、デフォルトのPKIXパラメータが使用されます。有効にするには、com.sun.net.ssl.checkRevocationシステム・プロパティをtrueに設定します。この設定では、CertPath実装自身が失効情報を見つけられる必要があります。プロバイダのPKIX実装では多くの場合にこの動作を実行できますが、システム・プロパティcom.sun.security.enableCRLDPtrueに設定する必要があります。TrustManagerFactory.init(ManagerFactoryParameters)メソッドではデフォルトで失効チェックが有効になっているということに注意してください。

PKIXクラスおよびCertPathクラスを参照してください。

例8-11 LDAP証明書を使用して失効チェックを有効にするサンプル・コード

次の例に、トラスト・マネージャを取得して特定のLDAP証明書ストアを使用する方法と、失効チェックを有効にする方法を示します。

    import javax.net.ssl.*;
    import java.security.cert.*;
    import java.security.KeyStore;
    import java.io.FileInputStream;
    ...
    
    // Obtain Keystore password
    char[] pass = System.console().readPassword("Password: ");

    // Create PKIX parameters
    KeyStore anchors = KeyStore.getInstance("JKS");
    anchors.load(new FileInputStream(anchorsFile, pass));
    PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(anchors, new X509CertSelector());
    
    // Specify LDAP certificate store to use
    LDAPCertStoreParameters lcsp = new LDAPCertStoreParameters("ldap.imc.org", 389);
    pkixParams.addCertStore(CertStore.getInstance("LDAP", lcsp));
    
    // Specify that revocation checking is to be enabled
    pkixParams.setRevocationEnabled(true);
    
    // Wrap PKIX parameters as trust manager parameters
    ManagerFactoryParameters trustParams = new CertPathTrustManagerParameters(pkixParams);
    
    // Create TrustManagerFactory for PKIX-compliant trust managers
    TrustManagerFactory factory = TrustManagerFactory.getInstance("PKIX");
    
    // Pass parameters to factory to be passed to CertPath implementation
    factory.init(trustParams);
    
    // Use factory
    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(null, factory.getTrustManagers(), null);

X509TrustManagerインタフェース

javax.net.ssl.X509TrustManagerインタフェースは、汎用のTrustManagerインタフェースを拡張したものです。X. 509ベースの認証を使用する場合、トラスト・マネージャによって実装される必要があります。

JSSEを使用したリモート・ソケット・ピアのX.509認証をサポートするには、このインタフェースのインスタンスをSSLContextオブジェクトのinitメソッドに渡す必要があります。

X509TrustManagerの作成

このインタフェースは、ユーザーが直接実装することも、SunJSSEプロバイダによって提供されているものなど、プロバイダ・ベースのTrustManagerFactoryから取得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたトラスト・マネージャに委譲することもできます。たとえば、結果の信頼性の判定をフィルタし、グラフィカル・ユーザー・インタフェースからエンド・ユーザーに問い合わせる場合に、これを実行できます。

nullのKeyStoreパラメータがSunJSSEのPKIXまたはSunX509 TrustManagerFactoryに渡された場合、ファクトリは次のプロセスを使用してトラスト・データを検索します。

  1. javax.net.ssl.trustStoreプロパティが定義されている場合、TrustManagerFactoryは、このシステム・プロパティで指定されたファイル名を使用してファイルを検索し、KeyStoreパラメータにそのファイルを使用しようとします。javax.net.ssl.trustStorePasswordシステム・プロパティも定義されている場合は、ファイルを開く前に、その値を使用してトラストストアのデータの整合性をチェックします。

    javax.net.ssl.trustStoreプロパティが定義されているが、指定したファイルが存在しない場合、空のキーストアを使用するデフォルトのTrustManagerが作成されます。

  2. javax.net.ssl.trustStoreシステム・プロパティが指定されていない場合:
    • java-home/lib/security/jssecacertsファイルが存在すれば、そのファイルが使用されます。
    • java-home/lib/security/cacertsファイルが存在すれば、そのファイルが使用されます。
    • これらのどちらのファイルも存在しない場合、SSL暗号化方式群が匿名であり、認証を行わないので、トラストストアは必要ありません。

java-homeが何を示すかについては、用語と定義を参照してください。

ファクトリは、cacertsファイルをチェックする前に、javax.net.ssl.trustStoreセキュリティ・プロパティによって指定されたファイルまたはjssecacertsファイルを検索します。そのため、コード署名の目的で、cacerts内に存在するものとは別に、JSSE固有の一連の信頼されたルート証明書を提供できます。

独自のX509TrustManagerの作成

指定したX509TrustManagerの動作が状況に適していない場合は、独自のTrustManagerFactoryを作成して登録するか、X509TrustManagerインタフェースを直接実装して、独自のX509TrustManagerを作成できます。

例8-12では、デフォルトのX509TrustManagerが失敗した場合に代替の認証ロジックを提供することによってデフォルトのSunJSSE X509TrustManagerの動作を拡張する、MyX509TrustManagerクラスを示します。

このようなトラスト・マネージャを作成できたら、次の例のように、init()メソッドを使用して、これをSSLContextに割り当てます。以降、このSSLContextから作成されたSocketFactoriesは、ユーザー独自のTrustManagerを使用して信頼性を判定するようになります。

TrustManager[] myTMs = new TrustManager[] { new MyX509TrustManager() };
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, myTMs, null);

例8-12 X509TrustManagerの作成のサンプル・コード

次のコード例では、デフォルトのX509TrustManagerが失敗した場合に代替の認証ロジックを提供することによってデフォルトのSunJSSE X509TrustManagerの動作を拡張する、MyX509TrustManagerクラスを示します。

class MyX509TrustManager implements X509TrustManager {

     /*
      * The default PKIX X509TrustManager9.  Decisions are delegated
      * to it, and a fall back to the logic in this class is performed
      * if the default X509TrustManager does not trust it.
      */
     X509TrustManager pkixTrustManager;

     MyX509TrustManager() throws Exception {
         // create a "default" JSSE X509TrustManager.

         KeyStore ks = KeyStore.getInstance("JKS");
         ks.load(new FileInputStream("trustedCerts"), "passphrase".toCharArray());

         TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
         tmf.init(ks);

         TrustManager tms [] = tmf.getTrustManagers();

         /*
          * Iterate over the returned trust managers, looking
          * for an instance of X509TrustManager.  If found,
          * use that as the default trust manager.
          */
         for (int i = 0; i < tms.length; i++) {
             if (tms[i] instanceof X509TrustManager) {
                 pkixTrustManager = (X509TrustManager) tms[i];
                 return;
             }
         }

         /*
          * Find some other way to initialize, or else the
          * constructor fails.
          */
         throw new Exception("Couldn't initialize");
     }

     /*
      * Delegate to the default trust manager.
      */
     public void checkClientTrusted(X509Certificate[] chain, String authType)
                 throws CertificateException {
         try {
             pkixTrustManager.checkClientTrusted(chain, authType);
         } catch (CertificateException excep) {
             // do any special handling here, or rethrow exception.
         }
     }

     /*
      * Delegate to the default trust manager.
      */
     public void checkServerTrusted(X509Certificate[] chain, String authType)
                 throws CertificateException {
         try {
             pkixTrustManager.checkServerTrusted(chain, authType);
         } catch (CertificateException excep) {
             /*
              * Possibly pop up a dialog box asking whether to trust the
              * cert chain.
              */
         }
     }

     /*
      * Merely pass this through.
      */
     public X509Certificate[] getAcceptedIssuers() {
         return pkixTrustManager.getAcceptedIssuers();
     }
}
keyStoreの動的更新

MyX509TrustManagerを拡張して、キーストアの動的更新処理を行うことができます。checkClientTrustedまたはcheckServerTrustedのテストに失敗し、信頼できる証明書チェーンを確立できなかった場合、キーストアに対して、要求された信頼できる証明書を追加できます。更新されたキーストアを使用して初期化されたTrustManagerFactoryから新しいpkixTrustManagerを作成する必要があります。以前に初期化したSSLContextを使って新しい接続を確立すると、信頼性の判定を行うときに、新しく追加された証明書が使用されます。

X509ExtendedTrustManagerクラス

X509ExtendedTrustManagerクラスはX509TrustManagerインタフェースの抽象実装です。これは、接続を考慮したトラスト管理のためのメソッドを追加します。さらに、TLSレイヤーでのエンド・ポイントの検証を可能にします。

TLS 1.2以降では、クライアントとサーバーの両方が、受け入れるハッシュ・アルゴリズムと署名アルゴリズムを指定できます。リモート側を認証するには、認証の決定が、X509証明書と、ローカルで受け入れられるハッシュ・アルゴリズムおよび署名アルゴリズムの両方に基づいていることが必要です。ローカルで受け入れられるハッシュ・アルゴリズムおよび署名アルゴリズムはExtendedSSLSession.getLocalSupportedSignatureAlgorithms()メソッドを使用して取得できます。

ExtendedSSLSessionオブジェクトは、SSLSocket.getHandshakeSession()メソッドまたはSSLEngine.getHandshakeSession()メソッドを呼び出すことによって取得できます。

X509TrustManagerインタフェースは、接続を考慮しません。SSLSocketまたはSSLEngineセッション・プロパティにアクセスする方法を提供しません。

X509ExtendedTrustManagerクラスはTLS 1.2サポート以外に、アルゴリズムの制約とSSLレイヤーのホスト名の検証もサポートします。JSSEプロバイダおよびトラスト・マネージャの実装については、レガシーのX509TrustManagerインタフェースよりもX509ExtendedTrustManagerクラスの方が強く推奨されます。

X509ExtendedTrustManagerの作成

X509ExtendedTrustManagerサブクラスを自分自身で作成するか(概略は次のセクションに記載)、プロバイダ・ベースのTrustManagerFactoryから取得できます(SunJSSEプロバイダによって提供されるものなど)。Java SE 7では、PKIXまたはSunX509 TrustManagerFactoryX509ExtendedTrustManagerインスタンスを返します。

独自のX509ExtendedTrustManagerの作成

このセクションでは、X509TrustManagerについて記載されているのとほぼ同じ方法でサブクラスX509ExtendedTrustManagerを作成する方法を示します。

例8-13では、PKIX TrustManagerFactoryを使用して、信頼性についての判定を下すために使用するデフォルトのX509ExtendedTrustManagerを見つけるクラスの作成方法を示します。

例8-13 PKIX TrustManagerFactoryの作成のサンプル・コード

次のコード例では、PKIX TrustManagerFactoryを使用して、信頼性についての判定を下すために使用するデフォルトのX509ExtendedTrustManagerを見つけるクラスの作成方法を示します。なんらかの理由でデフォルトのトラスト・マネージャに障害が発生した場合、サブクラスは他の動作を追加できます。このサンプルでは、これらの場所はcatch節内のコメントによって示されています。

import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
    
public class MyX509ExtendedTrustManager extends X509ExtendedTrustManager {

  /*
   * The default PKIX X509ExtendedTrustManager.  Decisions are
   * delegated to it, and a fall back to the logic in this class is
   * performed if the default X509ExtendedTrustManager does not
   * trust it.
   */
  
  X509ExtendedTrustManager pkixTrustManager;
    
  MyX509ExtendedTrustManager() throws Exception {
    // create a "default" JSSE X509ExtendedTrustManager.
    
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(new FileInputStream("trustedCerts"), "passphrase".toCharArray());
    
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ks);
    
    TrustManager tms [] = tmf.getTrustManagers();
    
    /*
     * Iterate over the returned trust managers, looking
     * for an instance of X509ExtendedTrustManager. If found,
     * use that as the default trust manager.
     */
    for (int i = 0; i < tms.length; i++) {
      if (tms[i] instanceof X509ExtendedTrustManager) {
        pkixTrustManager = (X509ExtendedTrustManager) tms[i];
        return;
      }
    }
    
    /*
     * Find some other way to initialize, or else we have to fail the
     * constructor.
     */
    throw new Exception("Couldn't initialize");
  }
    
  /*
   * Delegate to the default trust manager.
   */
  public void checkClientTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {
    try {
      pkixTrustManager.checkClientTrusted(chain, authType);
    } catch (CertificateException excep) {
      // do any special handling here, or rethrow exception.
    }
  }
    
  /*
   * Delegate to the default trust manager.
   */
  public void checkServerTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {
    try {
      pkixTrustManager.checkServerTrusted(chain, authType);
    } catch (CertificateException excep) {
      /*
       * Possibly pop up a dialog box asking whether to trust the
       * cert chain.
       */
    }
  }
    
  /*
   * Connection-sensitive verification.
   */
  public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
    throws CertificateException {
    try {
      pkixTrustManager.checkClientTrusted(chain, authType, socket);
    } catch (CertificateException excep) {
      // do any special handling here, or rethrow exception.
    }
  }
    
  public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
    throws CertificateException {
    try {
      pkixTrustManager.checkClientTrusted(chain, authType, engine);
    } catch (CertificateException excep) {
      // do any special handling here, or rethrow exception.
    }
  }
    
  public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
    throws CertificateException {
    try {
      pkixTrustManager.checkServerTrusted(chain, authType, socket);
    } catch (CertificateException excep) {
      // do any special handling here, or rethrow exception.
    }
  }
    
  public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
    throws CertificateException {
    try {
      pkixTrustManager.checkServerTrusted(chain, authType, engine);
    } catch (CertificateException excep) {
      // do any special handling here, or rethrow exception.
    }
  }
         
  /*
   * Merely pass this through.
   */
  public X509Certificate[] getAcceptedIssuers() {
    return pkixTrustManager.getAcceptedIssuers();
  }
}

KeyManagerインタフェース

KeyManagerは、最終的にリモート・ホストに送信される認証クレデンシャルを選択します。自分自身(ローカルのセキュアなソケット・ピア)をリモート・ピアに対して認証させるには、1つまたは複数のKeyManagerオブジェクトでSSLContextオブジェクトを初期化する必要があります。サポートされる認証メカニズムごとに、KeyManagerを1つ渡す必要があります。SSLContextの初期化中にnullが渡されると、空のKeyManagerが作成されます。内部のデフォルト・コンテキストが使用される場合(SSLSocketFactory.getDefault()またはSSLServerSocketFactory.getDefault()によって作成されるSSLContextなど)は、デフォルトのKeyManagerが作成されます。デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照してください。通常、単一のキー・マネージャは、X.509公開鍵証明書に基づく認証をサポートしています。セキュアなソケット実装には、共有の秘密鍵、Kerberos、またはほかのメカニズムに基づく認証をサポートするものもあります。

KeyManagerオブジェクトはKeyManagerFactoryによって、またはインタフェースの固定実装を提供することによって作成されます。

KeyManagerFactoryクラス

javax.net.ssl.KeyManagerFactoryクラスはプロバイダ・ベースのサービスのエンジン・クラスで、1つまたは複数の型のKeyManagerオブジェクトのファクトリとして動作します。SunJSSEプロバイダは、基本となるX.509キー・マネージャを返すことができるファクトリを実装します。これはプロバイダ・ベースであるため、追加のファクトリを実装し、構成することにより、追加の、または代替のキー・マネージャを提供できます。

KeyManagerFactoryの作成

このクラスのインスタンスはSSLContextと同様の方法で作成しますが、getInstanceメソッドにプロトコル名ではなくアルゴリズム名の文字列を渡す点が異なります。

KeyManagerFactory kmf = getInstance(String algorithm);
KeyManagerFactory kmf = getInstance(String algorithm, String provider);
KeyManagerFactory kmf = getInstance(String algorithm, Provider provider);

呼出しの例を次に示します。

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");

前の呼出しでSunJSSEプロバイダのデフォルトのキー・マネージャ・ファクトリのインスタンスが作成され、これは、基本となるX.509ベースの認証鍵を提供します。

新しく作成されたファクトリは、initメソッドの1つを呼び出すことによって初期化してください。

public void init(KeyStore ks, char[] password);
public void init(ManagerFactoryParameters spec);

使用するKeyManagerFactoryに適したinitメソッドを呼び出します。不明な場合は、プロバイダのベンダーに問い合わせてください。

SunX509 KeyManagerFactoryなど、SunJSSEプロバイダが提供するファクトリは多数ありますが、KeyManagerFactoryを初期化するために必要な情報はKeyStoreのみであるため、最初にinitメソッドを呼び出すのが適切です。KeyManagerFactoryKeyStoreに、リモートのソケット・ピアを認証するために使用すべき秘密鍵、および対応する公開鍵証明書について問い合わせます。パスワード・パラメータは、KeyStoreの鍵にアクセスするメソッドで使用するパスワードを指定します。KeyStoreの鍵はすべて、同じパスワードで保護する必要があります。

プロバイダでは、KeyStoreとパスワード以外の初期化パラメータを必要とすることがあります。そのプロバイダのユーザーは、プロバイダによる定義に従って、適切なManagerFactoryParametersの実装を渡すことが期待されます。そのあと、プロバイダはManagerFactoryParameters実装の特定のメソッドを呼び出し、必要な情報を取得できます。

一部のファクトリでは、KeyStoreオブジェクトやその他のパラメータで初期化されなくても、認証データにアクセスできます。たとえば、Java認証・承認サービス(JAAS)などのログイン・メカニズムの一部として鍵データにアクセスできる場合があります。

前に述べたように、SunJSSEプロバイダは、KeyStoreパラメータで初期化されている必要があるSunX509ファクトリをサポートします。

X509KeyManagerインタフェース

javax.net.ssl.X509KeyManagerインタフェースは、汎用のKeyManagerインタフェースを拡張したものです。X.509ベースの認証を行うキー・マネージャで実装します。JSSEを使用したリモート・ソケット・ピアのX.509認証をサポートするには、このインタフェースのインスタンスをSSLContextオブジェクトのinit()メソッドに渡す必要があります。

X509KeyManagerの作成

このインタフェースは、ユーザーが直接実装することも、SunJSSEプロバイダによって提供されているものなど、プロバイダ・ベースのKeyManagerFactoryから取得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたキー・マネージャに委譲することもできます。たとえば、結果の鍵をフィルタし、グラフィカル・ユーザー・インタフェースを使用してエンド・ユーザーに問い合わせる場合に、これを実行できます。

独自のX509KeyManagerの作成

X509KeyManagerのデフォルトの動作が状況に適していない場合は、独自のX509TrustManagerの作成に示す同様の方法で独自のX509KeyManagerを作成できます。

X509ExtendedKeyManagerクラス

X509ExtendedKeyManager抽象クラスは、接続に固有の鍵の選択が可能なX509KeyManagerインタフェースの実装です。これは、鍵のタイプ、許可される発行者および現在のSSLEngineに基づいて、クライアントまたはサーバー用の鍵の別名を選択する2つのメソッドを追加します。

  • public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
  • public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)

キー・マネージャがX509ExtendedKeyManagerクラスのインスタンスでない場合、SSLEngineクラスと連携して動作しません。

JSSEプロバイダおよびトラスト・マネージャの実装については、レガシーのX509KeyManagerインタフェースよりもX509ExtendedKeyManagerクラスの方が強く推奨されます。

TLS 1.2以降では、クライアントとサーバーの両方が、受け入れるハッシュ・アルゴリズムと署名アルゴリズムを指定できます。リモート側から要求される認証に合格するには、ローカルの鍵選択の決定が、X509証明書と、リモート側で受け入れられるハッシュ・アルゴリズムおよび署名アルゴリズムの両方に基づいていることが必要です。リモート側で受け入れられるハッシュ・アルゴリズムおよび署名アルゴリズムはExtendedSSLSession.getPeerSupportedSignatureAlgorithms()メソッドを使用して取得できます。

独自のX509TrustManagerの作成に示す同様の方法で、独自のX509ExtendedKeyManagerサブクラスを作成できます。

サーバー側でのServer Name Indication (SNI)拡張のサポートにより、キー・マネージャはサーバー名をチェックし、それに従って適切な鍵を選択できます。たとえば、キーストアに証明書付きの鍵エントリが3つあるとします。

  • cn=www.example.com
  • cn=www.example.org
  • cn=www.example.net

ClientHelloメッセージで、SNI拡張のwww.example.netに接続するように要求する場合、サーバーはサブジェクトcn=www.example.netで証明書を選択できる必要があります。

TrustManagerとKeyManagerの関係

これまでは、TrustManagerKeyManagerの機能に関して混乱がありました。

TrustManagerはリモート認証クレデンシャル(すなわち接続)が信頼できるかどうかを判定します。

KeyManagerはリモート・ホストに送信される認証クレデンシャルを決定します。

二次サポート・クラスおよびインタフェース

二次サポート・クラスは、セキュアなソケットの作成、使用、および管理をサポートするJSSE APIの一部として提供されます。このクラスは、セキュアなソケット・アプリケーションでは、コア・クラスやサポート・クラスほどには使用されません。セカンダリ・サポート・クラスおよびインタフェースはjavax.net.sslおよびjavax.security.certパッケージに含まれています。

SSLParametersクラス

SSLParametersクラスは、SSL/TLS/DTLS接続に影響する次のパラメータをカプセル化します。

  • SSL/TLS/DTLSハンドシェークで受け付けられる暗号化方式群のリスト
  • 許可されるプロトコルのリスト
  • SSL/TLS/DTLSハンドシェーク中のエンドポイント識別アルゴリズム
  • サーバー名とサーバー名のマッチャ(Server Name Indication (SNI)拡張を参照)
  • SSL/TLS/DTLSハンドシェークで使用される暗号化方式群の優先順位
  • SSL/TLS/DTLSハンドシェーク中のアルゴリズム
  • Server Name Indication (SNI)
  • 最大ネットワーク・パケット・サイズ
  • アルゴリズム制約、およびSSL/TLS/DTLSサーバーがクライアント認証を要求する必要があるか必要とするかどうか

次のメソッドを使用して、SSLSocketまたはSSLEngineの現在のSSLParametersを取得できます。

  • SSLSocketSSLServerSocketおよびSSLEngine内のgetSSLParameters()
  • SSLContext内のgetDefaultSSLParameters()およびgetSupportedSSLParamters()

SSLSocketSSLServerSocketおよびSSLEnginesetSSLParameters()メソッドで、SSLParametersを割り当てることができます。

SSLParameters.setServerNames()メソッドによって、サーバー名の表示を明示的に設定できます。クライアント・モードでのサーバー名の表示はエンドポイントの識別にも影響します。X509ExtendedTrustManagerの実装で、それはExtendedSSLSession.getRequestedServerNames()メソッドによって取得されたサーバー名の表示を使用します。例8-14を参照してください。

例8-14 Server Name Indicationを設定するサンプル・コード

この例では、サーバー名表示のホスト名(www.example.com)を使用して、エンド・エンティティのX.509証明書に提示されるピアのIDに対してエンドポイントを識別します。

    SSLSocketFactory factory = ...
    SSLSocket sslSocket = factory.createSocket("172.16.10.6", 443);
    // SSLEngine sslEngine = sslContext.createSSLEngine("172.16.10.6", 443);

    SNIHostName serverName = new SNIHostName("www.example.com");
    List<SNIServerName> serverNames = new ArrayList<>(1);
    serverNames.add(serverName);
 
    SSLParameters params = sslSocket.getSSLParameters();
    params.setServerNames(serverNames);
    sslSocket.setSSLParameters(params);
    // sslEngine.setSSLParameters(params);
暗号化方式群の優先順位

TLSハンドシェーク時に、クライアントは、それがサポートする暗号化オプションのリストの、最優先順位から暗号化方式群をネゴシエーションすることを要求します。次に、サーバーはクライアントによって要求された暗号化方式群のリストから、単一の暗号化方式群を選択します。通常、選択はクライアントの優先順位が尊重されます。ただし、弱い暗号化方式群の使用のリスクを緩和するため、サーバーはSSLParameters.setUseCipherSuitesOrder(true)メソッドを呼び出して、クライアントの優先順位ではなく、独自の優先順位に基づいて暗号化方式群を選択することがあります。

SSLSessionContextインタフェース

javax.net.ssl.SSLSessionContextインタフェースは、1つのエンティティに関連付けられているSSLSessionオブジェクトのグループです。たとえば、多数のセッションに同時に参加するサーバーやクライアントに関連付けることができます。このインタフェースのメソッドを使用すると、コンテキストの全セッションを列挙したり、セッションIDで特定のセッションを検索したりできます。

SSLSessionContextは、オプションで、SSLSessionのgetSessionContext()メソッドを呼び出してSSLSessionから取得することもできます。一部の環境では、コンテキストが使用できないことがあり、その場合、getSessionContextメソッドはnullを返します。

SSLSessionBindingListenerインタフェース

javax.net.ssl.SSLSessionBindingListenerインタフェースは、SSLSessionからバインドまたはアンバインドされるときに通知を受けるオブジェクトによって実装されます。

SSLSessionBindingEventクラス

javax.net.ssl.SSLSessionBindingEventクラスは、SSLSession (SSLSessionとExtendedSSLSessionを参照)からバインドまたはアンバインドされるときにSSLSessionBindingListener (SSLSessionBindingListenerインタフェースを参照)に伝えられるイベントを定義します。

HandShakeCompletedListenerインタフェース

javax.net.ssl.HandShakeCompletedListenerインタフェースは、指定のSSLSocket接続時にSSLプロトコル・ハンドシェークの完了通知を受け取る任意のクラスに実装されるインタフェースです。

HandShakeCompletedEventクラス

javax.net.ssl.HandShakeCompletedEventクラスは、指定のSSLSocket接続のSSLプロトコル・ハンドシェークの完了時にHandShakeCompletedListener (HandShakeCompletedListenerインタフェースを参照)に伝えられるイベントを定義します。

HostnameVerifierインタフェース

SSL/TLS実装の標準ホスト名検証ロジックが失敗した場合、実装は、このインタフェースを実装し、このHttpsURLConnectionインスタンスに割り当てられたクラスのverifyメソッドを呼び出します。コールバック・クラスは、指定のパラメータでホスト名が受け付け可能であると判断できる場合、接続を許可すべきであると報告します。応答が受け付けられない場合、接続は切断されます。例8-15を参照してください。

HostnameVerifierHttpsURLConnectionに割り当てる方法の詳細は、HttpsURLConnectionを参照してください。

例8-15 HostnameVerifierインタフェース実装のサンプル・コード

次の例では、HostnameVerifierインタフェースを実装するクラスを示します。

    public class MyHostnameVerifier implements HostnameVerifier {
    
        public boolean verify(String hostname, SSLSession session) {
            // pop up an interactive dialog box
            // or insert additional matching logic
            if (good_address) {
                return true;
            } else {
                return false;
            }
        }
    }
    
    //...deleted...
    
    HttpsURLConnection urlc = (HttpsURLConnection)
      (new URL("https://www.example.com/")).openConnection();
    urlc.setHostnameVerifier(new MyHostnameVerifier());

X509Certificateクラス

セキュアなソケット・プロトコルの多くは、X.509証明書という公開鍵証明書を使って認証を行います。これは、SSL/TLSプロトコルのデフォルト認証メカニズムです。

java.security.cert.X509Certificate抽象クラスは、X.509証明書の属性にアクセスする標準的な方法を提供します。

注意:

javax.security.cert.X509Certificateクラスは、以前のバージョン(1.0.xおよび1.1.x)のJSSEとの後方互換性のためにのみサポートされています。新しいアプリケーションでは、かわりにjava.security.cert.X509Certificateクラスを使用してください。

AlgorithmConstraintsインタフェース

java.security.AlgorithmConstraintsインタフェースは、許可される暗号化アルゴリズムを制御するために使用します。AlgorithmConstraintsは3つのpermits()メソッドを定義します。これらのメソッドは、ある暗号化関数について許可されるアルゴリズム名または鍵を指定します。暗号化関数は一連のCryptoPrimitiveで表現され、これはSTREAM_CIPHERMESSAGE_DIGESTSIGNATUREなどのフィールドを含む列挙です。

したがって、AlgorithmConstraints実装は、「この鍵とこのアルゴリズムを暗号化操作の目的で使用できるのか」といった質問に答えることができます。

新しいsetAlgorithmConstraints()メソッドを使用して、AlgorithmConstraintsオブジェクトをSSLParametersオブジェクトと関連付けることができます。SSLParametersオブジェクトに対する現在のAlgorithmConstraintsオブジェクトは、getAlgorithmConstraints()メソッドを使用して取得します。

StandardConstantsクラス

StandardConstantsクラスは、JSSEでの標準の定数定義を表すために使用します。

StandardConstants.SNI_HOST_NAMEServer Name Indication (SNI)拡張でのドメイン・ネーム・サーバー(DNS)ホスト名を表し、SNIServerNameまたはSNIMatcherオブジェクトのインスタンス化時に使用できます。

SNIServerNameクラス

抽象SNIServerNameクラスのインスタンスはServer Name Indication (SNI)拡張のサーバー名を表します。それは、指定したサーバー名のタイプとエンコード値を使用してインスタンス化されます。

getType()およびgetEncoded()メソッドを使用して、サーバー名のタイプとエンコードされたサーバー名の値のコピーをそれぞれ返します。equals()メソッドは他のオブジェクトがこのサーバー名と「等しい」かどうかをチェックするために使用できます。hashCode()メソッドはこのサーバー名のハッシュ・コード値を返します。サーバー名(サーバー名のタイプとエンコードされたサーバー名の値)の文字列表現を取得するには、toString()メソッドを使用します。

SNIMatcherクラス

抽象SNIMatcherクラスのインスタンスはSNIServerNameオブジェクトの一致操作を実行します。サーバーはServer Name Indication (SNI)拡張からの情報を使用して、特定のSSLSocketまたはSSLEngineで接続を受け付けるべきであるかどうかを判定できます。たとえば、単一の基礎となるネットワーク・アドレスで複数の「仮想」または「名前ベース」のサーバーがホストされている場合、サーバー・アプリケーションは、SNI情報を使用して、このサーバーが、クライアントがアクセスしようとしている正しいサーバーであるかどうかを判断できます。このクラスのインスタンスは、サーバーによって、ホスト名などの特定のタイプの受け付け可能なサーバー名を確認するために使用できます。

SNIMatcherクラスは、一致操作が実行される指定したサーバー名タイプを使用してインスタンス化されます。指定のSNIServerNameを照合するには、matches()メソッドを使用します。指定のSNIMatcherオブジェクトのサーバー名タイプを返すには、getType()メソッドを使用します。

SNIHostNameクラス

SNIHostNameクラス(SNIServerNameクラスを拡張する)のインスタンスは、Server Name Indication (SNI)拡張のタイプhost_name(StandardConstantsクラスを参照)のサーバー名を表します。SNIHostNameをインスタンス化するには、String引数で、サーバーの完全修飾DNSホスト名(クライアントから理解できる)を指定します。この引数は、次の場合に不正です。

  • 引数が空である。
  • 引数の末尾がピリオドで終わっている。
  • 引数がRFC 3490仕様に準拠した有効なInternationalized Domain Name (IDN)でない。

エンコードされたホスト名値をバイト配列で指定して、SNIHostNameをインスタンス化することもできます。このメソッドは一般に、要求されたSNI拡張でエンコードされた名前値を解釈するために使用します。そうでない場合、SNIHostName(String hostname)コンストラクタを使用します。encoded引数は、次の場合に不正です。

  • 引数が空である。
  • 引数の末尾がピリオドで終わっている。
  • 引数がRFC 3490仕様に準拠した有効なInternationalized Domain Name (IDN)でない。
  • 引数がUTF-8またはUS-ASCIIでエンコードされていない。

注意:

引数として渡されたencodedバイト配列は、以降の変更から保護するために、複製が作成されます。

US-ASCIIエンコーディングのSNIHostNameオブジェクトのホスト名を返すには、getAsciiName()メソッドを使用します。サーバー名を他のオブジェクトと比較するには、equals()メソッドを使用します(比較は大文字と小文字が区別されません)。SNIHostNameのハッシュ・コード値を返すには、hashCode()メソッドを使用します。DNSホスト名を含むSNIHostNameの文字列表現を返すには、toString()メソッドを使用します。

createSNIMatcher()メソッドに、1つ以上の照合するホスト名を表す正規表現を渡すことによって、SNIHostNameオブジェクトのSNIMatcherオブジェクトを作成します。

JSSEのカスタマイズ

JSSEには、様々な実装をプラグインしたり、デフォルトのキーストアを指定したりして、カスタマイズ可能な標準実装が含まれます。

表8-7表8-8では、カスタマイズが可能な側面、デフォルトの内容、およびカスタマイズを提供するために使用するメカニズムを要約しています。

一部の機能は、システム・プロパティやセキュリティ・プロパティの値を設定してカスタマイズできます。表に続くセクションでは、プロパティ値の設定方法について説明します。

注意:

この表に示すプロパティの多くは、現在JSSE実装で使用されていますが、それらの名前や型(システムまたはセキュリティ)が引き続き同じで、それらが将来のリリースにも存在するという保証はありません。それらのすべてのプロパティは「*」でフラグ付けされています。ここでは、JSSE実装で使用する場合の参考として、それらに言及しています。

表8-7では、java.security.Securityプロパティの設定によってカスタマイズされる項目を示します。java.security.Securityプロパティの指定方法を参照してください。

表8-7 セキュリティ・プロパティとカスタマイズされる項目

セキュリティ・プロパティ カスタマイズされる項目 デフォルト値 注意
cert.provider.x509v1 X509証明書実装のカスタマイズ OracleからのX509Certificate実装

なし

security.provider.n 暗号化サービス・プロバイダ。プロバイダ実装のカスタマイズ暗号化アルゴリズム・プロバイダのカスタマイズを参照してください。 優先度順の上位5つのプロバイダは、次のとおりです。
  1. SUN
  2. SunRsaSign
  3. SunEC
  4. SunJSSE
  5. SunJCE
セキュリティ・プロパティ・ファイル内のsecurity.provider.n=の行でプロバイダを指定します。ここでは、nは1以上の整数値です。
*ssl.SocketFactory.provider デフォルトのSSLSocketFactory実装 OracleからのSSLSocketFactory実装

なし

*ssl.ServerSocketFactory.provider デフォルトのSSLServerSocketFactory実装 OracleからのSSLServerSocketFactory実装

なし

ssl.KeyManagerFactory.algorithm デフォルトのキー・マネージャ・ファクトリ・アルゴリズム名(デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズを参照) SunX509

なし

*jdk.certpath.disabledAlgorithms 無効化された証明書検証暗号化アルゴリズム(無効化された制限付き暗号化アルゴリズムを参照)

MD2、MD5、SHA1 jdkCA & usage TLSServer、RSA keySize < 1024、DSA keySize < 1024、EC keySize < 224脚注4

なし

ssl.TrustManagerFactory.algorithm デフォルトのトラスト・マネージャ・ファクトリ・アルゴリズム名(デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズを参照) PKIX

なし

SunJSSEプロバイダが使用するJCE暗号化アルゴリズム 代替のJCEアルゴリズム・プロバイダにSunJCEプロバイダより古い高い優先順位を与えます。 SunJCE実装

なし

*jdk.tls.disabledAlgorithms
無効化された制限付き暗号化アルゴリズム

SSLv3、RC4、MD5withRSA、DH keySize < 1024、EC keySize < 224脚注4

特定のアルゴリズム(プロトコル・バージョン、暗号化方式群、鍵交換メカニズムなど)を無効化し、アプリケーションで明示的に有効化されてもSSL/TLS/DTLS接続でネゴシエーションされないようにします。
jdk.tls.server.defaultDHEParameters Diffie-Hellmanグループ OpenJDK SSL/TLS/DTLS実装での安全な主要Diffie-Hellmanグループ Transport Layer Security (SSL/TLS/DTLS)処理のためにデフォルトの有限フィールドDiffie-Hellman ephemeral (DHE)パラメータを定義します。

* このプロパティは現在JSSE実装で使用されていますが、他の実装で調査され、使用されている保証はありません。他の実装で調査する場合は、その実装で、JSSE実装と同じ方法でそれを処理すべきです。プロパティが今後も存在すること、またはシステム型やセキュリティ型が将来のリリースでも変更されないことの保証はされません。

脚注4

表8-8では、java.lang.Systemプロパティの設定によってカスタマイズされる項目を示します。java.lang.Systemプロパティの指定方法を参照してください。

表8-8 システム・プロパティとカスタマイズされる項目

システム・プロパティ カスタマイズされる項目 デフォルト 注意
java.protocol.handler.pkgs HTTPSプロトコルの代替実装の指定 Oracleからの実装

なし

*javax.net.ssl.keyStore デフォルトのキーストア(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照)

なし

NONEを指定できます。この設定は、キーストアがファイルベースでない場合に適切です(ハードウェア・トークンに存在する場合など)
*javax.net.ssl.keyStorePassword デフォルトのキーストア・パスワード(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照)

なし

他のユーザーに見つかるような方法でパスワードを指定することはお薦めできません。

たとえば、コマンド行でのパスワードの指定です。パスワードのセキュリティを維持するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します

*javax.net.ssl.keyStoreProvider デフォルトのキーストア・プロバイダ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照)

なし

なし

*javax.net.ssl.keyStoreType デフォルトのキーストア・タイプ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照) KeyStore.getDefaultType()

なし

*javax.net.ssl.trustStore デフォルトのトラストストア(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照) 存在する場合は、jssecacerts

そうでない場合、cacerts

なし

*javax.net.ssl.trustStorePassword デフォルトのトラストストア・パスワード(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照)

なし

他のユーザーに見つかるような方法でパスワードを指定することはお薦めできません。

たとえば、コマンド行でのパスワードの指定です。パスワードのセキュリティを維持するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します

*javax.net.ssl.trustStoreProvider デフォルトのトラストストア・プロバイダ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照)

なし

なし

*javax.net.ssl.trustStoreType デフォルトのトラストストア・タイプ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照) KeyStore.getDefaultType() NONEを指定できます。この設定は、トラストストアがファイルベースでない場合に適切です(ハードウェア・トークンに存在する場合など)
*https.proxyHost デフォルトのプロキシ・ホスト

なし

なし

*https.proxyPort デフォルトのプロキシ・ポート 80

なし

*jsse.enableSNIExtension Server Name Indicationオプション true Server Name Indication (SNI)はTLS拡張で、RFC 6066で定義されています。これは仮想サーバーへのTLS接続を可能にし、さまざまなネットワーク名に対して複数のサーバーが単一の基本ネットワーク・アドレスでホスティングされます。かなり古い一部のSSL/TLSベンダーは、SSL/TLS拡張を処理できないことがあります。この場合、このプロパティをfalseに設定してSNI拡張を無効化します
*https.cipherSuites デフォルトの暗号化方式群 ソケット・ファクトリによって決定

HttpsURLConnectionで使用できる暗号群を指定する暗号群名リスト(カンマ区切り形式)を含む。SSLSocket.setEnabledCipherSuites(String[])を参照してください。

*https.protocols デフォルトのハンドシェーク・プロトコル ソケット・ファクトリによって決定

HttpsURLConnectionで有効にするプロトコルを指定するプロトコル名リスト(カンマ区切り形式)を含む。SSLSocket.setEnabledProtocols(String[])を参照してください。

* HTTPS URL内のportフィールドによってカスタマイズします。 デフォルトのHTTPSポート 443

なし

*jsse.SSLEngine.acceptLargeFragments 大きいSSL/TLSパケット用のバッファのデフォルトのサイズ設定

なし

このシステム・プロパティをtrueに設定すると、SSLSessionはデフォルトで大きいデータ・パケットを処理するようにバッファをサイズ設定します。これにより、アプリケーションが不要な大きいSSLEngineバッファを割り当てる場合があります。代わりに、アプリケーションはバッファ・オーバーフロー条件を動的にチェックして、バッファを適宜サイズ変更する必要があります

*sun.security.ssl.allowUnsafeRenegotiation 安全ではないSSL/TLS再ネゴシエーションを許可します(フェーズ2修正の説明を参照) false

このシステム・プロパティをtrueに設定すると、完全な(安全でない)レガシーの再ネゴシエーションが許可されます。

このシステム・プロパティは推奨されておらず、将来のJDKリリースで削除される可能性があります。

*sun.security.ssl.allowLegacyHelloMessages 旧式のHelloメッセージを許可します(フェーズ2修正の説明を参照) true

このシステム・プロパティをtrueに設定すると、適切なRFC 5746メッセージを必要とすることなくピアがハンドシェークを実行できます。

このシステム・プロパティは推奨されておらず、将来のJDKリリースで削除される可能性があります。

jdk.tls.client.protocols SunJSSEプロバイダ

なし

クライアント上で特定のSunJSSEプロトコルを有効化するには、引用符で囲んでカンマ区切りリスト形式で指定します。それ以外のサポート対象プロトコルはクライアント上では有効になりません。

次に例を示します。
  • jdk.tls.client.protocols="TLSv1,TLSv1.1"の場合は、TLSv1およびTLSv1.1用のクライアント上のデフォルトのプロトコル設定が有効になり、SSLv3、TLSv1.2およびSSLv2Helloは有効になりません。

  • jdk.tls.client.protocols="DTLSv1.2"の場合は、DTLS1.2用のクライアント上のプロトコル設定が有効になり、DTLS1.0は有効になりません。

jdk.tls.ephemeralDHKeySize エフェメラルDiffie-Hellman鍵のサイズのカスタマイズ 1024ビット

なし

jsse.enableMFLNExtension 最大断片長ネゴシエーション(MFLN)拡張のカスタマイズ false

なし

* このプロパティは現在JSSE実装で使用されていますが、他の実装で調査され、使用されている保証はありません。他の実装で調査する場合は、その実装で、JSSE実装と同じ方法でそれを処理すべきです。プロパティが今後も存在すること、またはシステム型やセキュリティ型が将来のリリースでも変更されないことの保証はされません。

java.lang.Systemプロパティの指定方法

JSSEの一部の側面は、システム・プロパティを設定してカスタマイズできます。次のいくつかの方法によって、これらのプロパティを設定できます。
  • システム・プロパティを静的に設定するには、javaコマンドの-Dオプションを使用します。たとえば、MyAppというアプリケーションを実行して、javax.net.ssl.trustStoreシステム・プロパティを設定し、MyCacertsFileというトラストストアを指定します。トラストストアを参照してください。次のように入力します。
            java -Djavax.net.ssl.trustStore=MyCacertsFile MyApp
                    
    
  • システム・プロパティを動的に設定するには、次のコードでjava.lang.System.setProperty()メソッドを呼び出します。
            System.setProperty("propertyName", "propertyValue");
                    
    
    たとえば、システム・プロパティjavax.net.ssl.trustStoreを設定してMyCacertsFileというトラストストアを指定する、前の例に対応したsetProperty呼出しでは:
            System.setProperty("javax.net.ssl.trustStore", "MyCacertsFile");
                    
    
  • Java配備環境(プラグイン/Web Start)では、いくつかの方法でシステム・プロパティを設定できます。
    • Javaコントロール・パネルを使用して、Runtime Environment PropertyをローカルまたはVM単位で設定します。これにより、ローカルでdeployment.propertiesファイルが作成されます。配備担当開発者はdeployment.configメカニズムを使用して、企業全体のdeployment.propertiesファイルを配布することもできます。

    • 特定のアプレットにプロパティを設定するには、<APPLET>タグ内のHTMLサブタグ<PARAM> "java_arguments"を使用します。

    • 特定のJava Web Startアプリケーションまたはアプレット内でPlugin2を使用してプロパティを設定するには、resources要素のJNLP propertyサブ要素を使用します。Java Platform, Standard Editionデプロイメント・ガイドでresources要素を参照してください。

java.security.Securityプロパティの指定方法

JSSEの一部の側面は、セキュリティ・プロパティを設定してカスタマイズできます。セキュリティ・プロパティは静的または動的に設定できます。
  • セキュリティ・プロパティを静的に設定するには、セキュリティ・プロパティ・ファイルに1行追加します。セキュリティ・プロパティ・ファイルは、java-home/conf/security/java.securityにあります。
    java-home
    用語と定義を参照してください。

    セキュリティ・プロパティ・ファイルでセキュリティ・プロパティ値を指定するには、次の行を追加します。

    propertyName=propertyValue
    

    たとえば、デフォルトのSunX509以外のキー・マネージャ・ファクトリのアルゴリズム名を指定するとします。これを実行するには、ssl.KeyManagerFactory.algorithmというセキュリティ・プロパティの値として、アルゴリズム名を指定します。たとえば、値をMyX509に設定するには、次の行をセキュリティ・プロパティ・ファイルに追加します。

    ssl.KeyManagerFactory.algorithm=MyX509
    
  • セキュリティ・プロパティを動的に設定するには、自分のコードでjava.security.Security.setPropertyメソッドを呼び出します。
    Security.setProperty("propertyName," "propertyValue");
    
    たとえば、キー・マネージャ・ファクトリのアルゴリズム名を指定する、前の例に対応したsetProperty()メソッドの呼出しでは:
    Security.setProperty("ssl.KeyManagerFactory.algorithm", "MyX509");
    

X509証明書実装のカスタマイズ

X509Certificate.getInstance()メソッドで返されたX509証明書実装は、デフォルトでJSSE実装の実装です。

別の実装を返すようにするには、次の手順に従います。
他の実装のクラスの名前(およびパッケージ)を、cert.provider.x509v1という名前のjava.security.Securityプロパティの指定方法の値として指定します。
たとえば、クラスがMyX509CertificateImplと呼ばれ、com.cryptoxパッケージにある場合、セキュリティ・プロパティ・ファイルに次の行を追加してください。
    cert.provider.x509v1=com.cryptox.MyX509CertificateImpl

HTTPSプロトコルの代替実装の指定

java.net.URLクラスにHTTPS URLスキームを使用することで、SSL対応のWebサーバーでセキュアに通信できます。JDKは、デフォルトのHTTPS URL実装を提供します。

別のHTTPSプロトコル実装を使用する必要がある場合は、新しいクラス名を含めるようにjava.protocol.handler.pkgsjava.lang.Systemプロパティの指定方法を設定します。その結果、JDKのデフォルト・クラスより前に、指定したクラスが検索され、ロードされます。詳細は、URLクラスを参照してください。

注意:

過去のJSSEリリースでは、JSSEのインストール中にjava.protocol.handler.pkgsシステム・プロパティを設定する必要がありました。このステップは、com.sun.net.ssl.HttpsURLConnectionのインスタンスを取得する場合以外は不要になりました。

プロバイダ実装のカスタマイズ

JDKには、SunJSSEというJSSE暗号化サービス・プロバイダ(略称はプロバイダ)が付属しています。基本的に、プロバイダは特定の暗号化アルゴリズムのエンジン・クラスを実装するパッケージです。

JSSEのエンジン・クラスはSSLContextKeyManagerFactory、およびTrustManagerFactoryです。プロバイダとエンジン・クラスの詳細は、Java暗号化アーキテクチャ(JCA)リファレンス・ガイドを参照してください。

使用する前に、プロバイダを静的または動的に登録する必要があります。SunJSSEプロバイダは登録済なので、登録する必要はありません。ほかのプロバイダを使用する場合は、後述のセクションでプロバイダの登録方法を確認してください。

暗号化プロバイダの静的な登録

セキュリティ・プロパティ・ファイル<java-home>/conf/security/java.securityに次のような1行を追加することで、プロバイダを静的に登録します。

security.provider.n=provName|className 

これはプロバイダを宣言し、その優先順位nを指定します。優先順位とは、特定プロバイダの指定がないときに、要求されたアルゴリズムについてプロバイダを検索する順序です。順序は1が基準になり、1が最も優先されます。その後、2、3、...と続きます。

provNameはプロバイダの名前であり、classNameはプロバイダの完全修飾クラス名です。

標準のセキュリティ・プロバイダは、java.securityセキュリティ・プロパティ・ファイルに自動的に登録されます。

他のJSSEプロバイダを使用する場合は、行を追加して他のプロバイダを登録し、目的の優先順位を指定します。

複数のJSSEプロバイダを同時に登録できます。登録されたプロバイダには、様々なエンジン・クラスの、様々なアルゴリズムの様々な実装が含まれる場合があり、同じ型のアルゴリズムおよびエンジン・クラスの一部または全部をサポートする場合もあります。特定のアルゴリズムの特定のエンジン・クラス実装を検索するとき、その検索に特定のプロバイダが指定されていない場合、プロバイダは優先順位で検索され、指定したアルゴリズムの実装を提供する最初のプロバイダの実装が使用されます。

プロバイダの実装および統合までのステップステップ8.1: プロバイダの構成を参照してください。

暗号化サービス・プロバイダを動的に登録する

プロバイダを静的に登録するかわりに、SecurityクラスのaddProviderまたはinsertProviderAtメソッドを呼び出すことで実行時に動的にプロバイダを追加できます。こうした登録は持続的なものではなく、実行できるのはinsertProvider.<provider name>権限を付与されたコードのみです。

プロバイダ構成

一部のプロバイダは、構成が必要な場合があります。これは、SecurityクラスのaddProviderメソッドを呼び出す前に、Providerクラスのconfigureメソッドを使用して行われます。一例として、SunPKCS11の構成を参照してください。Provider.configure()メソッドは、Java SE 9の新機能です。

特定の複数のアルゴリズムのための推奨プロバイダの構成

jdk.security.provider.preferredセキュリティ・プロパティで特定のアルゴリズムのための推奨プロバイダを指定します。推奨プロバイダを指定することで、特定のアルゴリズムのパフォーマンスを向上させるプロバイダを構成できますが、それらは、他のアルゴリズムにとっては最善のプロバイダではありません。security.provider.nプロパティを使用して指定された順序付きプロバイダ・リストは、特定のアルゴリズムのパフォーマンスを向上させるが他のアルゴリズムにとっては最善ではないプロバイダを順序付けるには十分ではありません。パフォーマンスを向上させるには、プロバイダ・リストの順序付けの構成をより柔軟に行う必要があります。

jdk.security.provider.preferredセキュリティ・プロパティでは、登録済プロバイダのリストにアクセスする前に、特定のアルゴリズム、またはサービスの型を一連の推奨プロバイダから選択できます。java.security.Securityプロパティの指定方法を参照してください。

jdk.security.provider.preferredセキュリティ・プロパティでは、プロバイダは登録されません。順序付きプロバイダ・リストは、security.provider.nプロパティを使用して暗号化プロバイダを静的に登録している必要があります。登録されていないプロバイダは無視されます。

1つのアルゴリズムのための推奨プロバイダの指定

jdk.security.provider.preferredセキュリティ・プロパティで推奨プロバイダ文字列を指定するための構文は、ServiceType.Algorithm:Providerのカンマ区切りのリストです。

この構文の説明は次のとおりです。

ServiceType

サービスの型の名前。(例: "MessageDigest")ServiceTypeはオプションです。指定しない場合は、そのアルゴリズムがすべてのサービス型に適用されます。

Algorithm

標準アルゴリズム名。Javaセキュリティ標準アルゴリズム名仕様を参照してください。アルゴリズムは、標準名全体(AES/CBC/PKCS5Padding)または一部分(AES、AES/CBC、AES//PKCS5Padding)として指定できます。

Provider

プロバイダの名前。登録済リストに示されていないプロバイダは無視されます。JDKプロバイダを参照してください。

解析エラーなど、エラーを含むエントリは無視されます。エラーをデバッグするには、コマンドjava -Djava.security.debug=jcaを使用します。

推奨プロバイダとFIPS

FIPSプロバイダをsecurity.provider.nプロパティに追加し、jdk.security.provider.preferredプロパティで推奨プロバイダの順序付けを指定する場合は、jdk.security.provider.preferredで指定された推奨プロバイダが最初に選択されます。

したがって、FIPSプロバイダ構成のjdk.security.provider.preferredプロパティは構成しないようにすることをお薦めします。

jdk.security.provider.preferredのデフォルト値

jdk.security.provider.preferredプロパティは、デフォルトでは設定されておらず、アプリケーションのパフォーマンス・チューニングのためにのみ使用されます。

例8-16 jdk.security.provider.preferredプロパティのサンプル

jdk.security.provider.preferred プロパティを指定するための構文は、次のとおりです。

jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, MessageDigest.SHA-256:SUN

この構文の説明は次のとおりです。
ServiceType
MessageDigest
Algorithm
AES/GCM/NoPadding、SHA-256
Provider
SunJCE、SUN

デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ

SSLSocketFactory.getDefaultまたはSSLServerSocketFactory.getDefaultを呼び出すことでデフォルトのSSLSocketFactoryまたはSSLServerSocketFactoryが作成され、このデフォルトのSSLSocketFactory (またはSSLServerSocketFactory)がJSSEリファレンス実装に由来するものであれば、デフォルトのSSLContextは必ずソケット・ファクトリに関連付けられます。デフォルトのソケット・ファクトリは、JSSE実装に由来します。

デフォルトのSSLContextは、デフォルトのKeyManagerおよびデフォルトのTrustManagerで初期化されます。javax.net.ssl.keyStoreシステム・プロパティおよび適切なjavax.net.ssl.keyStorePasswordシステム・プロパティでキーストアを指定すると(java.lang.Systemプロパティの指定方法を参照)、デフォルトのSSLContextで作成したKeyManagerは、指定したキーストアを管理するKeyManager実装になります。(実際にはデフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズで説明したとおりに実装されます。)システム・プロパティが指定されない場合は、KeyManagerが管理するキーストアは新しい空のキーストアです。

一般に、ハンドシェークでサーバーとして動作するピアには、クライアントへの認証の資格を取得するため、KeyManagerのキーストアが必要です。ただし、匿名の暗号化方式群のいずれかを選択する場合、サーバーのKeyManagerキーストアは必要ありません。また、サーバーがクライアント認証を要求しないかぎり、クライアントとして動作するピアには、KeyManagerキーストアは必要ありません。したがって、このような状況では、javax.net.ssl.keyStoreのシステム・プロパティ値が定義されていなくてもかまわない場合があります。

同様に、トラスト・ストアをjavax.net.ssl.trustStoreシステム・プロパティで指定すると、デフォルトのSSLContextで作成したTrustManagerが、指定したトラスト・ストアを管理するTrustManager実装になります。この場合、そのようなプロパティが存在しても指定するファイルが存在しなければ、トラストストアは使用されません。javax.net.ssl.trustStoreプロパティが存在しない場合は、デフォルトのトラスト・ストアを検索します。java-home/lib/security/jssecacertsという名前のトラストストアが見つかった場合、それが使用されます。そうでない場合、java-home/lib/security/cacertsというトラストストアが検索され、それが存在していれば使用されます。トラスト・ストアが見つからない場合、TrustManagerは新しい空のトラスト・ストアを管理します。

注意:

JDKには、java-home/lib/security/cacertsファイルで、限定された数の信頼されたルート証明書が付属しています。Java Platform, Standard Editionツール・リファレンスのkeytoolに記載したとおり、このファイルをトラストストアとして使用する場合は、ユーザーにこのファイルに含まれる証明書を管理(追加または削除)する責任があります。

接続先のサーバーの証明書構成によっては、ルート証明書を追加する必要がある場合もあります。適切なベンダーから必要な特定のルート証明書を入手してください。

javax.net.ssl.keyStoreTypeまたはjavax.net.ssl.keyStorePasswordシステム・プロパティも指定されている場合、それぞれがデフォルトのKeyManagerキーストア・タイプとパスワードとして扱われます。タイプが指定されていない場合、デフォルトのタイプはKeyStore.getDefaultType()メソッドが返すもので、keystore.typeセキュリティ・プロパティの値か、または、そうしたセキュリティ・プロパティが指定されていない場合はjksになります。キーストアのパスワードが指定されていない場合は空白の文字列「」とみなされます。

同様に、javax.net.ssl.trustStoreTypeまたはjavax.net.ssl.trustStorePasswordシステム・プロパティも指定されている場合、それぞれがデフォルトのトラストストア・タイプとパスワードとして扱われます。タイプが指定されていない場合、デフォルトのタイプは、KeyStore.getDefaultType()メソッドによって返されるタイプです。トラストストアのパスワードが指定されていない場合は空白の文字列「」とみなされます。

注意:

この項では、現在のJSSEリファレンス実装の動作を説明します。このセクションで説明するシステム・プロパティの名前と型(システムまたはセキュリティ)が引き続き同じで、将来のリリースにも存在するという保証はありせん。また、他のJSSE実装での検証や使用も保証されていません。実装で検証された場合、ここで説明するように、実装では、JSSEリファレンス実装と同じ方法でそれらを処理してください。

デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズ

デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズで説明したように、デフォルトのSSLSocketFactoryまたはSSLServerSocketFactoryが作成され、このデフォルトのSSLSocketFactory (またはSSLServerSocketFactory)がJSSEリファレンス実装に由来する場合は、デフォルトのSSLContextは常にソケット・ファクトリに関連付けられます。

デフォルトのSSLContextは、KeyManagerおよびTrustManagerで初期化されます。デフォルトのSSLContextに提供されたKeyManagerTrustManagerの両方またはどちらか一方は、前のセクションで説明したように、指定したキーストアまたはトラストストアを管理するための実装になります。

選択されるKeyManager実装は、まずssl.KeyManagerFactory.algorithmセキュリティ・プロパティを調査することによって決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのKeyManagerFactory実装が検索されます。実装を提供する最初のプロバイダの実装が使用されます。そのgetKeyManagers()メソッドが呼び出され、デフォルトのSSLContextに提供するKeyManagerが決定されます。技術的には、getKeyManagers()は、鍵データの型ごとに1つずつのKeyManagerで、KeyManagerオブジェクトの配列を返します。そのようなセキュリティ・プロパティ値が指定されていない場合、SunX509のデフォルト値を使用して検索を実行します。

注意:

SunX509アルゴリズムのKeyManagerFactory実装はSunJSSEプロバイダによって提供されます。それが指定するKeyManagerjavax.net.ssl.X509KeyManager実装です。

同様に、選択されるTrustManager実装は、まずssl.TrustManagerFactory.algorithmセキュリティ・プロパティを調査することによって決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのTrustManagerFactory実装が検索されます。実装を提供する最初のプロバイダの実装が使用されます。そのgetTrustManagersメソッドが呼び出され、デフォルトのSSLContextに提供するTrustManagerが決定されます。技術的には、getTrustManagers()は、トラスト・データの型ごとに1つずつのTrustManagerで、TrustManagerオブジェクトの配列を返します。そのようなセキュリティ・プロパティ値が指定されていない場合、PKIXのデフォルト値を使用して検索を実行します。

注意:

PKIXアルゴリズムのTrustManagerFactory実装はSunJSSEプロバイダによって提供されます。それが指定するTrustManagerjavax.net.ssl.X509TrustManager実装です。

注意:

この項では、現在のJSSEリファレンス実装の動作を説明します。このセクションで説明するシステム・プロパティの名前と型(システムまたはセキュリティ)が引き続き同じで、将来のリリースにも存在するという保証はありせん。また、他のJSSE実装での検証や使用も保証されていません。実装で検証された場合、ここで説明するように、実装では、JSSEリファレンス実装と同じ方法でそれらを処理してください。

無効化された制限付き暗号化アルゴリズム

一部の環境では、SSL/TLS/DTLSの使用時は、特定のアルゴリズムまたは鍵の長さが不適切である場合があります。Oracle JDKでは、jdk.certpath.disabledAlgorithmsおよびjdk.tls.disabledAlgorithmセキュリティ・プロパティを使用して、バージョンのネゴシエーション、暗号化方式群の選択、ピア認証および鍵交換メカニズムなど、SSL/TLS/DTLSプロトコルのネゴシエーション中にアルゴリズムを無効にします。これらのセキュリティ・プロパティが他のJDK実装によって使用される保証はないことに注意してください。これらのセキュリティ・プロパティの構文とその現在アクティブな値については、<java-home>/conf/security/java.securityファイルを参照してください。

  • jdk.certpath.disabledAlgorithmsプロパティ: CertPathコードでは、jdk.certpath.disabledAlgorithmsセキュリティ・プロパティを使用して、CertPathチェック中に許可しないようにする必要があるアルゴリズムが決定されます。たとえば、TLSサーバーによって識別証明書チェーンが送信される場合、受け取ったチェーンをCertPath実装を使用して検証するクライアントTrustManagerでは、示された条件は許可されません。たとえば、次の行は、cacaertsキーストアにプレインストールされている信頼できるアンカーに連鎖するSHA1 TLSServer証明書と同様に、MD2ベースの証明書をブロックします。さらに、この行は、1024ビット未満のRSA鍵をブロックします。

    jdk.certpath.disabledAlgorithms=MD2, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024
  • jdk.tls.disabledAlgorithmsプロパティ: SunJSSEコードでは、jdk.tls.disabledAlgorithmsセキュリティ・プロパティを使用して、SSL/TLS/DTLSプロトコル、暗号化方式群、鍵などが無効にされます。この構文は、jdk.certpath.disabledAlgorithmsセキュリティ・プロパティに似ています。たとえば、次の行は、SSLv3アルゴリズムおよびすべてのTLS_*_RC4_*暗号化方式群を無効にします。

    jdk.tls.disabledAlgorithms=SSLv3, RC4

特定の条件が必要な場合は、java.securityファイル内のセキュリティ・プロパティで関連する値を削除するか、JSSEの初期化前に正しいセキュリティ・プロパティを動的に設定することで、それを再アクティブ化できます。

これらのセキュリティ・プロパティでは暗号化方式群の3番目のセットDisabledが事実上作成されることに注意してください。次のリストで、これら3つのセットを説明します。

  • Disabled: 暗号化方式群に無効リスト内のコンポーネント(RC4など)が含まれている場合(たとえば、RC4がjdk.tls.disabledAlgorithmsセキュリティ・プロパティで指定されている)、その暗号化方式群は無効になり、接続ハンドシェークに考慮されません

  • Enabled: 接続に考慮される特定の暗号化方式群のリストです。

  • Not Enabled: 接続に考慮されない、無効でない暗号化方式群のリストです。これらの暗号化方式群を再度有効にするには、適切なsetEnabledCipherSuites()またはsetSSLParameters()メソッドを呼び出します。

暗号化アルゴリズム・プロバイダのカスタマイズ

SunJSSEプロバイダは、その暗号化のすべてニーズに対してSunJCE実装を使用します。プロバイダは通常の位置に置くことが推奨されていますが、SunJCEプロバイダより前に登録することにより、他のJCAまたはJCEプロバイダからの実装を使用できます。

セキュリティ・プロパティ・ファイル<java-home>/conf/security/java.securityを介して静的に、またはjava.security.SecurityクラスのaddProvider()またはinsertProviderAt()メソッドを介して動的に、標準JCAメカニズム(プロバイダ実装の要求および獲得方法を参照)を使用してプロバイダを構成できます。

エフェメラルDiffie-Hellman鍵のサイズのカスタマイズ

SSL/TLS/DTLS接続では、ハンドシェーク中に内部的にephemeral Diffie-Hellman (DH)鍵が使用される場合があります。SunJSSEプロバイダでは、SSL/TLS/DTLSハンドシェーク中にephemeral DH鍵サイズの強度を柔軟にカスタマイズできます。

1024ビット未満のサイズのDiffie-Hellman (DH)鍵は強度が不十分なため、非推奨になりました。システム・プロパティjdk.tls.ephemeralDHKeySizeによって、ephemeral DH鍵のサイズをカスタマイズできます。このシステム・プロパティは、エクスポート可能な暗号化方式群のServerKeyExchangeメッセージ内のDH鍵のサイズには影響しません。これは、JSSE OracleプロバイダのDHE_RSA、DHE_DSSおよびDH_anonベースの暗号化方式群にのみ影響します。

このプロパティには次のいずれかの値を指定できます。

  • 未定義: 1024ビットのサイズのDH鍵は、常にエクスポート不可能な暗号化方式群に使用されます。これが、このプロパティのデフォルト値です。
  • legacy: JSSE Oracleプロバイダは、JDK 7以前のリリースのレガシーの動作を保持しています(512ビットおよび768ビットのサイズのephemeral DH鍵の使用など)。
  • matched: エクスポート不可能な匿名の暗号化方式群の場合、ServerKeyExchangeメッセージ内のDH鍵のサイズは1024ビットです。X.509証明書ベースの認証(エクスポート不可能な暗号化方式群の)の場合、サイズが1024ビットから2048ビットでなければならないことを除けば、対応する認証鍵に一致するDH鍵のサイズが使われます。たとえば、認証証明書の公開鍵サイズが2048ビットの場合、暗号化方式群がエクスポート可能でないかぎり、ephemeral DH鍵サイズは2048ビットにすべきです。この鍵サイズ設定スキームにより、認証鍵と鍵交換鍵間の暗号化強度の整合性を確保しています。
  • 1024以上2048以下の有効な整数: エクスポート不可能な暗号化方式群に、指定した値の固定のephemeral DH鍵サイズ(ビット単位)が使われます。

次の表に、システム・プロパティjdk.tls.ephemeralDHKeySizeの可能性のある各値について、DH鍵の最小および最大許容サイズをまとめています。

表8-9 システム・プロパティjdk.tls.ephemeralDHKeySizeのDH鍵サイズ

jdk.tls.ephemeralDHKeySizeの値 未定義 legacy matched 整数値(固定)
エクスポート可能なDH鍵サイズ 512 512 512 512
エクスポート不可能な匿名暗号化方式群 1024 768 1024 固定鍵サイズは有効な整数プロパティ値で指定し、1024以上2048以下である必要があります。
認証証明書 1024 768

鍵サイズは認証証明書と同じですが、1024ビット以上2048ビット以下である必要があります。ただし、1024ビットより大きい、SunJCEプロバイダでサポートされている唯一のDH鍵サイズは、2048ビットです。

結果として、使用できる値は1024または2048のみになります。

固定鍵サイズは有効な整数プロパティ値で指定し、1024以上2048以下である必要があります。

最大断片長ネゴシエーション(MFLN)拡張のカスタマイズ

より小さい最大断片長をネゴシエーションするために、クライアントは、ClientHelloメッセージにmax_fragment_lengthタイプの拡張情報を含めることを選択できます。システム・プロパティjsse.enableMFLNExtensionを使用して、SSL/TLS/DTLS用のMFLN拡張を有効または無効にできます。

最大断片長ネゴシエーション

制約があるSSL/TLS/DTLSクライアントでは、メモリー制限や帯域幅制限が原因で、より小さい最大断片長をネゴシエーションしたほうが望ましい場合があります。より小さい最大断片長をネゴシエーションするために、クライアントは、(拡張された) ClientHelloメッセージにmax_fragment_lengthタイプの拡張情報を含めることを選択できます。RFC 6066を参照してください。

最大断片長が正常にネゴシエーションされると、SSL/TLS/DTLSクライアントおよびサーバーで、すぐにメッセージ(ハンドシェーク・メッセージを含む)の断片化を開始して、ネゴシエーションされた長さより長い断片が送信されないようにすることができます。

システム・プロパティjsse.enableMFLNExtension

システム・プロパティjsse.enableMFLNExtensionは、MFLN拡張を有効または無効にするために定義されます。jsse.enableMFLNExtensionは、デフォルトでは無効になっています。

このシステム・プロパティの値は、次のように設定できます。

表8-10 jsse.enableMFLNExtensionシステム・プロパティ

システム・プロパティ 説明
jsse.enableMFLNExtension=true MFLN拡張を有効にします。SSLParameters.getMaximumPacketSize()で返された値が(2^12 + header-size)未満の場合、最大断片長ネゴシエーション拡張が有効になります。
jsse.enableMFLNExtension=false MFLN拡張を無効にします。

最大および最小パケット・サイズの構成

SSLParameters.setMaximumPacketSizeメソッドを使用して、SSL/TLS/DTLSレコードのための予期される最大ネットワーク・パケット・サイズ(バイト単位)を設定します。

HelloVerifyRequestsなど、小さいハンドシェーク・メッセージが断片化されないように、パケット・サイズは256バイト未満にしないようにすることをお薦めします。

Transport Layer Security (TLS)再ネゴシエーションの問題

2009年秋に、SSL/TLSプロトコルの問題が見つかりました。IETF TLS Working Groupによってプロトコルの修正が開発され、JDKの現行バージョンにはこの修正が含まれています。このセクションでは、このプロトコル修正を含まない以前の実装との通信時における相互運用性の問題を含め、状況をさらに詳しく説明します。

この脆弱性により、選択されたプレーン・テキストを接頭辞としてTLS接続に注入できるというMan-In-The-Middle (MITM)攻撃を許していました。この脆弱性は、クライアントとサーバーがセッションのネゴシエーションに成功した後、傍受されたネットワーク通信を攻撃者が復号化または変更することを許すものではありません。

SSL/TLSの脆弱性の詳細は、次のリンクを参照してください。

この問題を解決するためのフェーズ別アプローチ

この問題の修正は、2つのフェーズに分けて扱われています。

  • フェーズ1: プロトコル修正が開発されるまで、SSL/TLSの再ネゴシエーションをデフォルトで無効化する中間修正が、「March 30, 2010 Java SE and Java for Business Critical Patch Update」から利用できるようになりました。

  • フェーズ2: IETFによって、再ネゴシエーション・プロトコルの問題を扱うRFC 5746が発表されました。次の表に、RFC 5746を実装してセキュアな再ネゴシエーションをサポートする修正を含むJDKおよびJREリリースを示します。

    表8-11 TLS再ネゴシエーション問題の修正を含むJDKおよびJREリリース

    JDKファミリ 脆弱性のあるリリース フェーズ1の修正(再ネゴシエーションの無効化) フェーズ2の修正(RFC 5746)
    JDKおよびJRE 6 Update 18以前 Update 19-21 Update 22
    JDKおよびJRE 5.0 Update 23以前 Update 24-25 Update 26
    JDKおよびJRE 1.4.2 Update 25以前 Update 26-27 Update 28

注意:

再ネゴシエーションを必要としないアプリケーションはフェーズ2のデフォルト構成に影響を受けません。ただし、再ネゴシエーションを必要とするアプリケーション(最初は匿名のクライアント・ブラウズを許可するが、後でSSL/TLS認証済のクライアントを要求するWebサーバーなど)は:
  • ピアもRFC 5746に準拠している場合は影響を受けません
  • ピアがRFC 5746にアップグレードしていない場合は影響を受けます(詳細は次のセクションを参照してください)

フェーズ2修正の説明

SunJSSE実装は、RFC 5746に準拠したピアへの接続について、再ネゴシエーションをデフォルトで再び有効にします。つまり、セキュアに再ネゴシエーションを行うためには、クライアントとサーバーが両方ともRFC 5746をサポートする必要があります。まだアップグレードされていないピアとの接続について、SunJSSEではある程度の相互運用性モードが提供されていますが、ユーザーがクライアントとサーバーの両方の実装をできるだけ早く更新することを強く推奨します

フェーズ2修正により、SunJSSEは現在3つの再ネゴシエーション相互運用性モードを用意しています。どのモードもRFC 5746のセキュアな再ネゴシエーションを完全にサポートしていますが、アップグレードされていないピアと通信する場合、次のような意味合いが加わります。

  • 厳密モード: クライアントとサーバーの両方がRFC 5746にアップグレードされていること、および適切なRFC 5746メッセージを送信することが求められます。そうでない場合、初期の(または後続の)ハンドシェークが失敗して接続が切断されます。

  • 相互運用モード(デフォルト): 正しいRFC 5746メッセージの使用はオプションですが、適切なメッセージが使用されない場合はレガシーの(元のSSL/TLS仕様の)再ネゴシエーションが無効になります。最初のレガシー接続は許可されますが、レガシーの再ネゴシエーションは無効化されます。これはセキュリティと相互運用性の最適な組み合わせであるため、デフォルト設定です。

  • セキュアでないモード: レガシーの再ネゴシエーションを完全に許可します。レガシーのピアとの相互運用性がもっとも高いですが、本来のMITM攻撃に対して脆弱です。

3つのモード区分は、アップグレードされていないピアとの接続にのみ影響します。すべてのクライアントおよびサーバーで厳密モード(完全なRFC 5746モード)を使用することが望ましいのですが、配備されているすべてのSSL/TLS実装がRFC 5746をサポートするようになるまである程度時間がかかるため、今のところは相互運用モードがデフォルトになっています。

次の表に、クライアントまたはサーバー(あるいはその両方)がRFC 5746をサポートするように更新されている場合と更新されていない場合の様々な例でのモードに関する相互運用性情報を示しています。

表8-12 相互運用性情報

クライアント サーバー モード
更新済 更新済 すべてのモードで再ネゴシエーションがセキュリティ保護されます。
レガシー[1] 更新済
  • 厳密クライアントが適切なRFC 5746メッセージを送信しない場合、最初の接続がサーバーによってすぐに切断されます(SSLHandshakeExceptionまたはhandshake_failure)。
  • 相互運用可能 レガシー・クライアントからの初期接続(RFC 5746メッセージが欠落している)は許可されますが、再ネゴシエーションはサーバーによって許可されません。[3] [2]
  • セキュアでないレガシー・クライアントとの接続および再ネゴシエーションは許可されますが、元のMITM攻撃に対して脆弱です。
更新済 レガシー[1]
  • 厳密サーバーが正しいRFC 5746メッセージで応答しない場合、クライアントは接続をすぐに切断します(SSLHandshakeExceptionまたはhandshake_failure)。
  • 相互運用可能 レガシー・サーバーからの初期接続(RFC 5746メッセージが欠落している)は許可されますが、再ネゴシエーションはサーバーによって許可されません。[2] [3]
  • セキュアでないレガシー・サーバーとの接続および再ネゴシエーションは許可されますが、元のMITM攻撃に対して脆弱です。
レガシー[1] レガシー[1] 既存のSSL/TLS動作を行い、MITM攻撃に対して脆弱です。

脚注[1] レガシーとは元のSSL/TLS仕様を意味します(つまり、RFC 5746でない)。

脚注[2] SunJSSEフェーズ1実装は、明示的に再有効化されないかぎり再ネゴシエーションを拒否します。再ネゴシエーションが再有効化された場合、それらは正しいRFC 5746メッセージを送信しないため、RFC 5746に準拠したピアによって「レガシー」として扱われます。

脚注[3] SSL/TLSでは、再ネゴシエーションをどちら側からでも開始できます。フェーズ1修正のように、アップグレードされていないピアと相互運用モードで通信しているアプリケーションが(SSLSocket.startHandshake()またはSSLEngine.beginHandshake()を使用して)再ネゴシエーションを開始しようとすると、アプリケーションはSSLHandshakeException (IOException)を受け取り、接続は停止されます(handshake_failure)。まだアップグレードされていないピアから再ネゴシエーション要求を受け取ったアプリケーションは、現在の接続のタイプに応じて応答します。
  • TLSv1no_renegotiation(100)タイプの警告メッセージがピアに送信され、接続は開いたままになります。古いバージョンのSunJSSEは、no_renegotiationアラートを受け取ると接続を停止します。
  • SSLv3 アプリケーションはSSLHandshakeExceptionを受け取り、接続は閉じられます(handshake_failure)。no_renegotiationアラートはSSLv3仕様に定義されていません。

次のシステム・プロパティを使用してモードを設定します(java.lang.Systemプロパティの指定方法を参照)。

  • sun.security.ssl.allowUnsafeRenegotiation (フェーズ1で導入)は、レガシー(安全でない)再ネゴシエーションを許可するかどうかを制御します。
  • sun.security.ssl.allowLegacyHelloMessages (フェーズ2で導入)は、適切なRFC 5746メッセージを必要とすることなくピアがハンドシェーク・プロセスを実行することを許可します。

注意:

システム・プロパティsun.security.ssl.allowUnsafeRenegotiationおよびsun.security.ssl.allowLegacyHelloMessages推奨されておらず、将来のJDKリリースで削除される可能性があります。

表8-13 相互運用性モードを設定するためのシステム・プロパティの値

モード allowLegacyHelloMessages allowUnsafeRenegotiation
厳密 false false
相互運用(デフォルト) true false
セキュアでない true true

注意:

セキュアでないSSL/TLS再ネゴシエーションは、脆弱性が再確立されるため、再有効化しないでください。

SSL/TLS再ネゴシエーションに対する回避方法と代替方法

すべてのピアは、できるだけ早くRFC 5746準拠の実装に更新する必要があります。このRFC 5746修正を適用しても、再ネゴシエーションが必要な場合は、アップグレードされていないピアとの通信に影響が生じます。推奨されるいくつかの方法を次に示します。

  • ピアを再構築して再ネゴシエーションを要求しないようにする。

    再ネゴシエーションは通常、Webサーバーが最初は匿名のクライアント・ブラウズを許可するが、後でSSL/TLS認証済クライアントを要求する場合や、Webサーバーが最初は弱い暗号化方式群を許可するが、後で強い暗号化方式群を必要とする場合に、Webサーバーによって使用されます。代替策は、最初のネゴシエーション中にクライアント認証および強い暗号化方式群を必要とすることです。これを行うには、2つの選択肢があります。

    • アプリケーションに、あるポイントに到達して、再ネゴシエーションが必要になるまでの「ブラウズ・モード」がある場合、「ブラウズ・モード」を削除し、すべての初期接続を強化するようにサーバーを再構築できます。

    • サーバーを2つのエンティティに分割して、1つのエンティティ上でブラウズ・モードを実行し、2つ目のエンティティをよりセキュアなモードで使用します。ネゴシエーション・ポイントに到達したら、関連情報をサーバー間で転送します。

    これらのどちらのオプションも、ある程度の作業が必要ですが、元のセキュリティ上の欠陥が再度発生することはありません。

  • システム・プロパティを使用して、再ネゴシエーション相互運用性モードを「セキュアでない」に設定します。

    フェーズ2修正の説明を参照してください。

TLS実装の詳細

RFC 5746では2つの新しいデータ構造が定義されており、上級ユーザーのために、ここで説明します

  • Signaling Cipher Suite Value (SCSV)と呼ばれる擬似暗号化方式群、「TLS_EMPTY_RENEGOTIATION_INFO_SCSV」
  • Renegotiation Info (RI)と呼ばれるTLS拡張。

これらのいずれも、実装がRFC 5746に準拠していることと、セキュアな再ネゴシエーションが実行できることを通知するために使用できます。2009年11月から2010年2月までのIETF電子メール・ディスカッションを参照してください。

RFC 5746により、クライアントは最初のClientHelloでSCSVまたはRIを送信できます。相互運用性を最大限に高めるため、SunJSSEはデフォルトでSCSVを使用しますが、これは、いくつかのTLSサーバー/SSLサーバーが不明な拡張機能を正しく処理できないためです。有効化された暗号化方式群(SSLSocket.setEnabledCipherSuites()またはSSLEngine.setEnabledCipherSuites())にSCSVが存在することによって、最初のClientHello内でSCSVを送信するか、あるいはRIをかわりに送信すべきかどうかが判別されます。

SSLv2はSSL/TLS拡張機能をサポートしません。SSLv2Helloプロトコルが有効化された場合、SCSVが最初のClientHello内で送信されます。

フェーズ1修正の説明

前述のとおり、フェーズ1修正は、RFC 5746に準拠した修正が開発されるまでの間、再ネゴシエーションをデフォルトで無効にするためのものでした。再ネゴシエーションは、sun.security.ssl.allowUnsafeRenegotiationシステム・プロパティを設定することによって再び有効化できました。フェーズ2修正では同じsun.security.ssl.allowUnsafeRenegotiationシステム・プロパティを使用するだけでなく、それにRFC 5746メッセージを使用させる必要もあります。

すべてのアプリケーションを、できるだけ早くフェーズ2 RFC 5746修正にアップグレードする必要があります。

注意:

システム・プロパティsun.security.ssl.allowUnsafeRenegotiationおよびsun.security.ssl.allowLegacyHelloMessages推奨されておらず、将来のJDKリリースで削除される可能性があります。

SSL/TLS再ネゴシエーションにおける安全でないサーバー証明書変更の許可

次の場合、SSL/TLS再ネゴシエーションでサーバー証明書を変更することは、安全でないことがあります。

  1. エンドポイント識別がSSL/TLSハンドシェークで有効でない場合、および

  2. 以前のハンドシェークがセッション再開省略初期ハンドシェークである場合、および

  3. 両方の証明書によって表されるアイデンティティが異なると見なせる場合。

2つの証明書は、次の場合に、同じアイデンティティを表すと見なせます。

  1. IPアドレスのサブジェクトの代替名が両方の証明書に存在する場合、同一であるはずです。または、

  2. DNS名のサブジェクトの代替名が両方の証明書に存在する場合、同一であるはずです。または、

  3. サブジェクト・フィールドが両方の証明書に存在する場合、証明書のサブジェクトと発行人は同一であるはずです。

JDK 8u25以降では、SSL/TLS再ネゴシエーションでの安全でないサーバー証明書の変更は、デフォルトでできません。新しいシステム・プロパティjdk.tls.allowUnsafeServerCertChangeを使用して、SSL/TLS再ネゴシエーションにおける安全でないサーバー証明書変更を制限するかどうかを定義できます。

このシステム・プロパティのデフォルト値はfalseです。

注意:

どうしても必要でないかぎり、このシステム・プロパティをtrueに設定しないでください。安全でないサーバー証明書変更の脆弱性が再び確立される可能性があります。

ハードウェア高速化およびスマート・カードのサポート

Java暗号化アーキテクチャ(JCA)は、暗号化、鍵生成と鍵合意およびメッセージ認証コード(MAC)アルゴリズム用のフレームワークと実装を提供するパッケージ・セットです。(Java暗号化アーキテクチャ(JCA)リファレンス・ガイドを参照。)SunJSSEプロバイダは、すべての暗号化操作にJCAを排他的に使用するので、JCAのRSA PKCS#11のサポートを含め、JCEの機能や拡張機能を自動的に利用できます。このサポートによりSunJSSEプロバイダは、ハードウェア暗号化アクセラレータを使用してパフォーマンスを大幅に向上させ、キーストアとしてスマート・カードを使用し、鍵および信頼性管理の柔軟性を高めることができます。

基盤となるアクセラレータ・ハードウェアを使用するようにOracle PKCS#11プロバイダが構成され、そのPKCS#11プロバイダを使用するようにJCAが構成されていれば、ハードウェア暗号化アクセラレータは自動的に使用されます。プロバイダは、プロバイダ・リストにある他のJCAプロバイダより前に構成する必要があります。Oracle PKCS#11プロバイダの構成方法の詳細は、PKCS#11リファレンス・ガイドを参照してください。

スマートカードをキーストアおよびトラストストアとして使用するためのJSSEの構成

JCAでのPKCS#11のサポートにより、キーストアとしてスマートカードにアクセスすることもできます。JSSEによって使用されるキーストアのタイプと場所の構成方法の詳細は、JSSEのカスタマイズを参照してください。スマートカードをキーストアまたはトラストストアとして使用するには、javax.net.ssl.keyStoreTypeおよびjavax.net.ssl.trustStoreTypeシステム・プロパティをそれぞれpkcs11に設定し、javax.net.ssl.keyStoreおよびjavax.net.ssl.trustStoreシステム・プロパティをそれぞれNONEに設定します。特定のプロバイダを使用するように指定するには、javax.net.ssl.keyStoreProviderおよびjavax.net.ssl.trustStoreProviderシステム・プロパティを使用します(たとえば、それらをSunPKCS11-joeに設定します)。これらのプロパティを使用することにより、以前はファイルベースのキーストアにアクセスするためにこれらのプロパティに依存していたアプリケーションを構成して、アプリケーションに変更を加えずにスマートカードのキーストアを使用できます。

アプリケーションによっては、キーストアをプログラムで使用する必要があります。こうしたアプリケーションでは、引き続き既存のAPIを使用してKeystoreをインスタンス化し、キー・マネージャとトラスト・マネージャに渡すことができます。Keystoreインスタンスがスマートカードに基づくPKCS#11キーストアを参照する場合は、JSSEアプリケーションがスマートカードの鍵にアクセスすることになります。

複数の動的キーストア

スマートカードおよびその他の取り外し可能トークンには、X509KeyManagerについて追加の要件があります。Javaアプリケーションの存続期間の間、異なるスマートカードをスマートカード・リーダーに入れることができ、それらのスマートカードは異なるパスワードを使用して保護できます。

KeyStore.Builderクラスは、KeyStoreオブジェクトの構造と初期化を抽象化します。パスワードのプロンプト用にCallbackHandlerの使用をサポートし、そのサブクラスを使用して、アプリケーションに望まれる追加機能をサポートできます。たとえば、Builderを実装して、個々のKeyStoreエントリを異なるパスワードで保護するようにすることが可能です。その後、KeyStoreBuilderParametersクラスを使用し、これらのBuilderオブジェクトを1つ以上使用してKeyManagerFactoryを初期化できます。

NewSunX509と呼ばれる、SunJSSEプロバイダのX509KeyManager実装は、これらのパラメータをサポートしています。複数の証明書が使用可能な場合は、適切な鍵を使用する証明書を選択し、期限切れの証明書より有効な証明書を優先させます。

例8-17では、PKCS#11キーストア(スマートカードを使用できる)とPKCS#12ファイルベース・キーストアの両方を使用するようJSSEに指示する方法を示します。

例8-17 PKCS#11およびPKCS#12ファイルベース・キーストアを使用するサンプル・コード

import javax.net.ssl.*;
import java.security.KeyStore.*;
// ...

// Specify keystore builder parameters for PKCS#11 keystores
Builder scBuilder = Builder.newInstance("PKCS11", null,
    new CallbackHandlerProtection(myGuiCallbackHandler));

// Specify keystore builder parameters for a specific PKCS#12 keystore
Builder fsBuilder = Builder.newInstance("PKCS12", null,
    new File(pkcsFileName), new PasswordProtection(pkcsKsPassword));

// Wrap them as key manager parameters
ManagerFactoryParameters ksParams = new KeyStoreBuilderParameters(
    Arrays.asList(new Builder[] { scBuilder, fsBuilder }) );

// Create KeyManagerFactory
KeyManagerFactory factory = KeyManagerFactory.getInstance("NewSunX509");

// Pass builder parameters to factory
factory.init(ksParams);

// Use factory
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(factory.getKeyManagers(), null, null);

Kerberos暗号化方式群

SunJSSEプロバイダは、RFC 2712で規定されるKerberos暗号化方式群をサポートします。次の暗号化方式群がサポートされていますが、デフォルトでは有効になっていません。

注意:

DTLSバージョン1.0DTLSバージョン1.2によると、RC4暗号化方式群はDTLSとは使用できません。
  • TLS_KRB5_WITH_RC4_128_SHA
  • TLS_KRB5_WITH_RC4_128_MD5
  • TLS_KRB5_WITH_3DES_EDE_CBC_SHA
  • TLS_KRB5_WITH_3DES_EDE_CBC_MD5
  • TLS_KRB5_WITH_DES_CBC_SHA
  • TLS_KRB5_WITH_DES_CBC_MD5
  • TLS_KRB5_EXPORT_WITH_RC4_40_SHA
  • TLS_KRB5_EXPORT_WITH_RC4_40_MD5
  • TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA
  • TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5

これらの暗号化方式群を使用できるようにするには、明示的に指定する必要があります。SSLEngine.setEnabledCipherSuites(String[])メソッドとSSLSocket.setEnabledCipherSuites(String[])メソッドについては、APIドキュメントを参照してください。その他のすべてのSSL/TLS/DTLS暗号化方式群と同様、暗号化方式群がピアによってサポートされていない場合は、暗号化のネゴシエーション時に選択されません。また、アプリケーションまたはサーバーが必要なKerberos資格を取得できない場合は、Kerberos符号化方式も選択されません。

次に、TLS_KRB5_WITH_DES_CBC_SHA暗号化方式群のみを使用するTLSクライアントの例を示します。

// Create socket
SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(tlsServer, serverPort);

// Enable only one cipher suite
String enabledSuites[] = { "TLS_KRB5_WITH_DES_CBC_SHA" };
sslSocket.setEnabledCipherSuites(enabledSuites);

Kerberos要件

JSSEでKerberos符号化方式を使用する前に、配備されている環境でKerberosインフラストラクチャを設定しておく必要があります。特に、TLSクライアントとサーバーの両方に、Kerberos Key Distribution Center (KDC)によるアカウントが設定されていことが必要です。実行時にKerberos暗号化方式群の1つ以上が有効化されると、TLSクライアントとサーバーは、それぞれのアカウントに関連付けられている自身のKerberosクレデンシャルをKDCから取得します。たとえば、Kerberos領域IMC.ORGのマシンmach1.imc.orgで動作するTLSサーバーは、host/mach1.imc.org@IMC.ORGという名前のアカウントを持ち、IMC.ORG用のKDCを使用するように構成されている必要があります。Kerberos要件を参照してください。

アプリケーションは、Java Authentication and Authorization Service (JAAS)リファレンス・ガイドとKerberosログイン・モジュールを使用して、自身のKerberos資格を取得できます。JDKには、Krb5LoginModuleが付属しています。JSSEでのKerberos暗号化方式群は、JAASプログラミングありまたはなしでJAASおよびJava GSS-APIチュートリアルを使用する方法と同様に、JAASプログラミングありでもなしでも使用できます。

JAASプログラミングなしでJSSEでKerberos暗号化方式群を使用するには、TLSサーバーJAAS構成エントリ用にcom.sun.net.ssl.serverまたはother、およびTLSクライアント用にcom.sun.net.ssl.clientまたはotherというインデックス名を使用し、javax.security.auth.useSubjectCredsOnlyシステム・プロパティをfalseに設定する必要があります。たとえば、JAASプログラミングを使用しないTLSサーバーには次のJAAS構成ファイルを使用できます。

com.sun.net.ssl.server {
  com.sun.security.auth.module.Krb5LoginModule required
    principal="host/mach1.imc.org@IMC.ORG"
    useKeyTab=true
    keyTab=mach1.keytab
    storeKey=true;
};

JAASプログラミングなしでJava GSSおよびKerberosを使用する方法の例は、JDK 8ドキュメント内のチュートリアルJAASプログラミングなしでの安全なメッセージ交換のためのJava GSS-APIの使用で説明されています。Java GSS呼出しをJSSE呼出しに置き換えることにより、JSSEの使用例に適応できます。

JAASプログラミングありでKerberos暗号化方式群を使用するには、任意のインデックス名を使用できます。これは、アプリケーションが、インデックス名を使用してJAAS LoginContextを作成し、JSSE呼出しをSubject.doAs()またはSubject.doAsPrivileged()呼出しの内部にラップする役割を持つためです。Java GSSおよびKerberosでJAASを使用する方法の例は、JDK 8ドキュメント内のチュートリアル安全なメッセージ交換のためのJAASログイン・ユーティリティおよびJava GSS-APIの使用で説明されています。Java GSS呼出しをJSSE呼出しに置き換えることにより、JSSEの使用例に適応できます。

Kerberosを使用するJSSEアプリケーションを使用または構成する場合の問題については、JDK 8ドキュメント内のJava GSSチュートリアルのトラブルシューティングを参照してください。

ピアのアイデンティティ情報

SSL/TLS/DTLS接続のピアの識別情報を判別するには、次のクラスで、getPeerPrincipal()メソッドを使用します。

  • javax.net.ssl.SSLSession
  • javax.net.ssl.HttpsURLConnection
  • javax.net.HandshakeCompletedEvent

同様に、(ローカル・エンティティを識別するために)ピアに送信された識別情報を取得するには、これらのクラスでgetLocalPrincipal()メソッドを使用します。X509ベースの暗号化方式群の場合、これらのメソッドはjavax.security.auth.x500.X500Principalのインスタンスを返します。Kerberos暗号化方式群の場合、これらのメソッドはjavax.security.auth.kerberos.KerberosPrincipalのインスタンスを返します。

JSSEアプリケーションは、getPeerCertificates()と、javax.net.ssl.SSLSessionjavax.net.ssl.HttpsURLConnectionjavax.net.HandshakeCompletedEventの類似のメソッドを使用して、ピアに関する情報を取得します。ピアに証明書がない場合、SSLPeerUnverifiedExceptionがスローされます。

アプリケーションでピアの識別情報またはピアに送信された識別情報のみを判別する必要がある場合は、それぞれgetPeerPrincipal()およびgetLocalPrincipal()メソッドを使用してください。getPeerCertificates()およびgetLocalCertificates()メソッドは、それらの証明書の内容を調べる必要がある場合にのみ使用してください。また、アプリケーションでは、認証されたピアに証明書がない場合の処理を準備しておく必要があります。

セキュリティ・マネージャ

セキュリティ・マネージャが有効な場合、ピアとの通信に必要なSocketPermissionに加えて、Kerberos暗号化方式群を使用するTLSクライアント・アプリケーションには次のアクセス権も必要です。

javax.security.auth.kerberos.ServicePermission(serverPrincipal, "initiate");

説明は次のとおりです。

serverPrincipal
TLSクライアントが通信するTLSサーバーのKerberosプリンシパル名を示します(host/mach1.imc.org@IMC.ORGなど)。

TLSサーバー・アプリケーションには、次のアクセス権が必要です。

javax.security.auth.kerberos.ServicePermission(serverPrincipal, "accept");

説明は次のとおりです。

serverPrincipal
TLSサーバーのKerberosプリンシパル名を示します(host/mach1.imc.org@IMC.ORGなど)。

サーバーまたはクライアントがKDCに接続する必要がある場合(そのクレデンシャルがローカルにキャッシュされていない場合など)、次のアクセス権も必要です。

javax.security.auth.kerberos.ServicePermission(tgtPrincipal, "initiate");

説明は次のとおりです。

tgtPrincipal
KDCのプリンシパル名を示します(krbtgt/IMC.ORG@IMC.ORGなど)。

その他のキーストア形式(PKCS12)

PKCS#12 (Personal Information Exchange Syntax Standard)では、移植可能な保存形式、およびユーザーの非公開鍵、証明書、その他の秘密およびほかの項目の転送について規定されています。SunJSSEプロバイダは、PKCS12ファイルの読取りおよび書込みのためのPKCS12 java.security.KeyStore形式の完全な実装を提供します。この形式は、鍵と証明書のインポートおよびエクスポートのために、Mozilla Firefox、Microsoft Internet ExplorerおよびOpenSSLなど、他のツールキットやアプリケーションでもサポートされています。たとえば、これらの実装は、クライアントの証明書と鍵を.p12ファイル名拡張子を使用してファイルにエクスポートできます。

SunJSSEプロバイダでは、PKCS12のキーストア・タイプを使用して、KeyStore APIを介してPKCS12鍵にアクセスできます。さらにkeytoolコマンドと、pkcs12に設定された-storetypeオプションを使用して、インストールされた鍵および関連する証明書を表示できます。Java Platform, Standard Editionツール・リファレンスでkeytoolを参照してください。

Server Name Indication (SNI)拡張

SNI拡張は、SSL/TLS/DTLSプロトコルを拡張し、クライアントがハンドシェーク時に接続を試みるサーバー名を示す機能です。サーバーはServer Name Indicationの情報を使って、特定のSSLSocketまたはSSLEngineインスタンスが接続を受け入れる必要があるかどうかを判定できます。たとえば、単一の基礎となるネットワーク・アドレスで複数の仮想または名前ベースのサーバーがホストされている場合、サーバー・アプリケーションは、SNI情報を使用して、このサーバーが、クライアントがアクセスしようとしている正しいサーバーであるかどうかを判断できます。このクラスのインスタンスは、サーバーによって、ホスト名などの特定のタイプの受け付け可能なサーバー名を確認するために使用できます。TLS拡張(RFC 6066)の第3項を参照してください。

クライアント・アプリケーションの開発者は、SSLParameters.setServerNames(List<SNIServerName> serverNames)メソッドを使用して、サーバー名の表示を明示的に設定できます。例8-18を参照してください。

サーバー・アプリケーションの開発者はSNIMatcherクラスを使用して、サーバー名の表示を認識する方法を決定できます。例8-19例8-20では、この機能を示します。

例8-18 Server Name Indicationを設定するサンプル・コード

次のコード例では、メソッドSSLParameters.setServerNames(List<SNIServerName> serverNames)を使用してサーバー名表示を設定する方法を示します。

SSLSocketFactory factory = ...
SSLSocket sslSocket = factory.createSocket("172.16.10.6", 443);
// SSLEngine sslEngine = sslContext.createSSLEngine("172.16.10.6", 443);

SNIHostName serverName = new SNIHostName("www.example.com");
List<SNIServerName> serverNames = new ArrayList<>(1);
serverNames.add(serverName);

SSLParameters params = sslSocket.getSSLParameters();
params.setServerNames(serverNames);
sslSocket.setSSLParameters(params);
// sslEngine.setSSLParameters(params);

例8-19 SSLSocketクラスを使用してSNIを認識するサンプル・コード

次のコード例では、サーバー・アプリケーションでSNIMatcherクラスを使用してサーバー名表示の認識方法を決定する方法を示します。

SSLSocket sslSocket = sslServerSocket.accept();

SNIMatcher matcher = SNIHostName.createSNIMatcher("www\\.example\\.(com|org)");
Collection<SNIMatcher> matchers = new ArrayList<>(1);
matchers.add(matcher);

SSLParameters params = sslSocket.getSSLParameters();
params.setSNIMatchers(matchers);
sslSocket.setSSLParameters(params);

例8-20 SSLServerSocketクラスを使用してSNIを認識するサンプル・コード

次のコード例では、サーバー・アプリケーションでSNIMatcherクラスを使用してサーバー名表示の認識方法を決定する方法を示します。

 
SSLServerSocket sslServerSocket = ...;

SNIMatcher matcher = SNIHostName.createSNIMatcher("www\\.example\\.(com|org)");
Collection<SNIMatcher> matchers = new ArrayList<>(1);
matchers.add(matcher);

SSLParameters params = sslServerSocket.getSSLParameters();
params.setSNIMatchers(matchers);
sslServerSocket.setSSLParameters(params);

SSLSocket sslSocket = sslServerSocket.accept();

次のリストは、ClientHelloメッセージで様々なサーバー名表示要求を受け取った場合のSNIMatcherの動作の例を示しています。

  • www\\.example\\.comに構成されたマッチャ:

    • 要求されたホスト名がwww.example.comの場合、それは受け付けられ、ServerHelloメッセージで確認が送信されます。
    • 要求されたホスト名がwww.example.orgの場合、それはunrecognized_name致命的エラーで拒否されます。
    • 要求されたホスト名がないか、空の場合、要求は受け付けられますが、ServerHelloメッセージで確認が送信されません。
  • www\\.invalid\\.comに構成されたマッチャ:

    • 要求されたホスト名がwww.example.comの場合、それはunrecognized_name致命的エラーで拒否されます。
    • 要求されたホスト名がwww.example.orgの場合、それは受け付けられ、ServerHelloメッセージで確認が送信されます。
    • 要求されたホスト名がないか、空の場合、要求は受け付けられますが、ServerHelloメッセージで確認が送信されません。
  • マッチャが構成されていない:

    要求されたすべてのホスト名が受け付けられますが、ServerHelloメッセージで確認は送信されません。

SNI拡張を実装する新しいクラスの説明については、次を参照してください。

たとえば、「Server Name Indication (SNI)拡張の使用」を参照してください。

TLSのアプリケーション層プロトコル・ネゴシエーション

アプリケーション層プロトコル・ネゴシエーション(ALPN)を使用してTLS接続のためにアプリケーション・プロトコルをネゴシエーションします。

ALPNとは

アプリケーションによっては、TLSハンドシェークが完了する前に、共有アプリケーション・レベル値のネゴシエーションが必要な場合があります。たとえば、HTTP/2では、特定のTCPまたはUDPポートで使用されるか使用できるHTTPバージョン(h2、spdy/3、http/1.1)の確立に役立つように、アプリケーション層プロトコル・ネゴシエーションのメカニズムが使用されます。ALPN (RFC 7301)では、クライアントとサーバーとの間のネットワーク・ラウンドトリップを増やすことなく、これが行われます。HTTP/2の場合、プロトコルは、接続をネゴシエーションする前に確立される必要があります。これは、クライアントとサーバーが、通信を開始する前に、使用するHTTPのバージョンを把握する必要があるためです。ALPNを使用しないと、アプリケーション・プロトコルHTTP/1とHTTP/2を同じポートで使用できません。

クライアントは、TLSハンドシェークの開始時にALPN拡張を使用して、サポートされているアプリケーション・プロトコルのリストをClientHelloの一部としてサーバーに送信します。サーバーは、ClientHello内のサポートされているアプリケーション・プロトコルのリストを読み取り、サポートされているプロトコルのうちどれが望ましいかを判断します。次に、ネゴシエーション結果とともにServerHelloメッセージをクライアントに送り返します。メッセージには、選択されているプロトコルの名前、またはプロトコルが選択されていないことが示されている場合があります。

そのようにして、アプリケーション・プロトコル・ネゴシエーションは、ネットワーク・ラウンドトリップを増やすことなく、TLSハンドシェーク内で行うことができ、必要に応じてサーバーで異なる証明書を各アプリケーション・プロトコルに関連付けることができるようにします。

他の多くのTLS拡張と異なり、この拡張では、セッションのプロパティは確立されず、接続のプロパティのみとなります。それが、ネゴシエーションした値がSSLSessionではなくSSLSocket/SSLEngineで見つかる理由です。セッション再開またはセッション・チケットが使用される場合(サーバー側の状態なしでのTLSセッション再開を参照)、前にネゴシエーションした値は無関係であり、新しいハンドシェーク・メッセージ内の値のみが考慮されます。

クライアントでのALPNの設定

クライアントによってサポートされているアプリケーション層プロトコル・ネゴシエーション(ALPN)値を設定します。サーバーとのハンドシェーク中に、サーバーは、クライアントのアプリケーション・プロトコル・リストを読み取り、どれが最も適切かを判断します。

クライアントの場合は、SSLParameters.setApplicationProtocols(String[])メソッドの次にSSLSocketまたはSSLEnginesetSSLParametersメソッドを使用して、サーバーに送信するためのアプリケーション・プロトコルを設定します。

例8-21 JavaクライアントでのALPN値の設定および取得のサンプル・コード

たとえば、ここでは、クライアントでthreetwoというALPN値を設定する手順を示します。

コードを実行するには、プロパティjavax.net.ssl.trustStoreを有効なルート証明書に設定する必要があります。(これはコマンド行で実行できます)。

import java.io.*; 
import java.util.*;
import javax.net.ssl.*; 
public class SSLClient {
    public static void main(String[] args) throws Exception {

        // Code for creating a client side SSLSocket
        SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket sslSocket = (SSLSocket) sslsf.createSocket("localhost", 9999);

        // Get an SSLParameters object from the SSLSocket
        SSLParameters sslp = sslSocket.getSSLParameters();

        // Populate SSLParameters with the ALPN values
        // On the client side the order doesn't matter as
        // when connecting to a JDK server, the server's list takes priority
        String[] clientAPs = {"three", "two"};
        sslp.setApplicationProtocols(clientAPs);

        // Populate the SSLSocket object with the SSLParameters object
        // containing the ALPN values
        sslSocket.setSSLParameters(sslp);

        sslSocket.startHandshake();

        // After the handshake, get the application protocol that has been negotiated
        String ap = sslSocket.getApplicationProtocol();
        System.out.println("Application Protocol client side: \"" + ap + "\"");

        // Do simple write/read
        InputStream sslIS = sslSocket.getInputStream();
        OutputStream sslOS = sslSocket.getOutputStream();
        sslOS.write(280);
        sslOS.flush();
        sslIS.read();
        sslSocket.close();
    }
}
このコードを実行し、ALPN値onetwoおよびthreeが設定されているJavaサーバーにClientHelloが送信されると、出力は次のようになります。
Application Protocol client side: two
ハンドシェークの詳細は、SSLハンドシェークを参照してください。ハンドシェーク中にネゴシエーションの結果を確認することもできます。ハンドシェーク中のネゴシエーション済ALPN値の特定を参照してください。

サーバーでのデフォルトALPNの設定

サーバーでALPN値を設定することで、デフォルトのALPNメカニズムを使用して、適切なアプリケーション・プロトコルを決定します。

サーバーでALPNのデフォルト・メカニズムを使用するには、クライアントでALPNを設定したときに行ったように(クライアントでのALPNの設定の項を参照)、設定するALPN値をSSLParametersオブジェクトに移入してから、このSSLParametersオブジェクトを使用してSSLSocketオブジェクトかSSLEngineオブジェクトにこれらのパラメータを移入します。サーバーで設定されたALPN値のうち、ClientHelloに含まれているALPN値のいずれかに一致する最初の値が選択され、ServerHelloの一部としてクライアントに返されます。

例8-22 サーバーでのデフォルトALPN値ネゴシエーションのサンプル・コード

次に、プロトコル・ネゴシエーションにデフォルトの手法を使用するJavaサーバー用コードを示します。コードを実行するには、プロパティjavax.net.ssl.keyStoreを有効なキーストアに設定する必要があります。(これはコマンド行で実行できます。JSSEで使用するキーストアの作成を参照)。

import java.util.*; 
import javax.net.ssl.*; 
public class SSLServer {
    public static void main(String[] args) throws Exception {

        // Code for creating a server side SSLSocket
        SSLServerSocketFactory sslssf = 
            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        SSLServerSocket sslServerSocket = 
            (SSLServerSocket) sslssf.createServerSocket(9999);
        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();

        // Get an SSLParameters object from the SSLSocket
        SSLParameters sslp = sslSocket.getSSLParameters();

        // Populate SSLParameters with the ALPN values
        // As this is server side, put them in order of preference
        String[] serverAPs ={ "one", "two", "three" };
        sslp.setApplicationProtocols(serverAPs);

        // If necessary at any time, get the ALPN values set on the 
        // SSLParameters object with:
        // String serverAPs = sslp.setApplicationProtocols();

        // Populate the SSLSocket object with the ALPN values
        sslSocket.setSSLParameters(sslp);

        sslSocket.startHandshake();

        // After the handshake, get the application protocol that 
        // has been negotiated

        String ap = sslSocket.getApplicationProtocol();
        System.out.println("Application Protocol server side: \"" + ap + "\"");

        // Continue with the work of the server
        InputStream sslIS = sslSocket.getInputStream();
        OutputStream sslOS = sslSocket.getOutputStream();
        sslIS.read();
        sslOS.write(85);
        sslOS.flush();
        sslSocket.close();
    }
}
このコードを実行し、Javaクライアントによって、ALPN値threeおよびtwoを含むClientHelloが送信されると、出力は次のようになります。
Application Protocol server side: two
ハンドシェークの詳細は、SSLハンドシェークを参照してください。ハンドシェーク中にネゴシエーションの結果を確認することもできます。ハンドシェーク中のネゴシエーション済ALPN値の特定を参照してください。

サーバーでのカスタムALPNの設定

コールバック・メソッドを設定することで、カスタムのALPNメカニズムを使用して、適切なアプリケーション・プロトコルを決定します。

サーバーのデフォルト・ネゴシエーション・プロトコルを使用しない場合は、SSLEngineまたはSSLSocketsetHandshakeApplicationProtocolSelectorメソッドを使用して、現在までのハンドシェーク状態を確認できるBiFunction (ラムダ)コールバックを登録し、クライアントのアプリケーション・プロトコル・リストおよびその他の関連情報に基づいて選択できます。たとえば、推奨されている暗号化方式群、または選択に当たって取得できるServer Name Indication (SNI)やその他のデータの使用を検討できます。カスタム・ネゴシエーションを使用する場合は、setApplicationProtocolsメソッドによって設定された値(デフォルト・ネゴシエーション)は無視されます。

例8-23 サーバーでのカスタムALPN値ネゴシエーションのサンプル・コード

次に、プロトコル・ネゴシエーションにカスタム・メカニズムを使用するJavaサーバー用コードを示します。コードを実行するには、プロパティjavax.net.ssl.keyStoreを有効な証明書に設定する必要があります。(これはコマンド行で実行できます。JSSEで使用するキーストアの作成を参照)。

import java.util.*; 
import javax.net.ssl.*; 
public class SSLServer {
    public static void main(String[] args) throws Exception {

        // Code for creating a server side SSLSocket
        SSLServerSocketFactory sslssf =
            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        SSLServerSocket sslServerSocket = 
            (SSLServerSocket) sslssf.createServerSocket(9999);
        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();

        // Code to set up a callback function
        // Pass in the current SSLSocket to be inspected and client AP values
        sslSocket.setHandshakeApplicationProtocolSelector(
            (serverSocket, clientProtocols) -> {
                SSLSession handshakeSession = serverSocket.getHandshakeSession();
                // callback function called with current SSLSocket and client AP values
                // plus any other useful information to help determine appropriate
                // application protocol. Here the protocol and ciphersuite are also
                // passed to the callback function.
                return chooseApplicationProtocol(
                    serverSocket,
                    clientProtocols,
                    handshakeSession.getProtocol(),
                    handshakeSession.getCipherSuite());
         }); 

        sslSocket.startHandshake();

        // After the handshake, get the application protocol that has been
        // returned from the callback method.

        String ap = sslSocket.getApplicationProtocol();
        System.out.println("Application Protocol server side: \"" + ap + "\"");

        // Continue with the work of the server
        InputStream sslIS = sslSocket.getInputStream();
        OutputStream sslOS = sslSocket.getOutputStream();
        sslIS.read();
        sslOS.write(85);
        sslOS.flush();
        sslSocket.close();
    }

    // The callback method. Note how the parameters match the call within 
    // the setHandshakeApplicationProtocolSelector method above.
    public static String chooseApplicationProtocol(SSLSocket serverSocket,
            List<String> clientProtocols, String protocol, String cipherSuite ) {
        // For example, check the cipher suite and return an application protocol
        // value based on that.
        if (cipherSuite.equals("<--a_particular_ciphersuite-->")) { 
            return "three";
        } else {
            return "";
        }
    } 
}

暗号化方式群が、このコードの実行時に条件文で指定されたものと一致する場合は、値threeが返されます。そうでない場合は、空の文字列が返されます。

BiFunctionオブジェクトの戻り値がStringであることに注意してください。これは、アプリケーション・プロトコル名になるか、通知された値をどれも受け入れられないことを示すnullになります。戻り値が空のStringである場合は、アプリケーション・プロトコルの指示は使用されません。戻り値がnull (選択値なし)であるか、ピアによって通知されていない値である場合は、基になるプロトコルで、実行するアクションが決定されます。(たとえば、サーバー・コードでno_application_protocolアラートが送信され、接続が終了されます。)

クライアントとサーバーの両方でハンドシェークが完了した後、SSLSocketオブジェクトまたはSSLEngineオブジェクトでgetApplicationProtocolメソッドを呼び出すことで、ネゴシエーションの結果を確認できます。ハンドシェークの詳細は、SSLハンドシェークを参照してください。

ハンドシェーク中のネゴシエーション済ALPN値の特定

ハンドシェーク中にネゴシエーションされたALPN値を特定するには、カスタムのKeyManagerまたはTrustManagerクラスを作成し、このカスタム・クラスにgetHandshakeApplicationProtocolメソッドの呼出しを含めます。

選択したALPN値とSNI値がKeyManagerまたはTrustManagerによる選択内容に影響するユースケースがいくつかあります。たとえば、アプリケーションが、サーバーの属性および選択されたALPN/SNI/暗号化方式群値に応じて、異なる証明書/公開鍵のセットを選択する必要がある場合があります。

与えられたサンプル・コードでは、KeyManagerオブジェクトとして作成し登録するカスタムX509ExtendedKeyManager内から、getHandshakeApplicationProtocolメソッドを呼び出す方法を示します。

例8-24 カスタムKeyManagerのサンプル・コード

この例では、X509ExtendedKeyManagerを拡張するカスタムKeyManagerのコード全体を示します。大部分のメソッドは、このMyX509ExtendedKeyManagerクラスによってラップされているKeyManagerクラスから返された値を返すのみです。ただし、chooseServerAliasメソッドは、SSLSocketオブジェクトでgetHandshakeApplicationProtocolを呼び出し、それにより、ネゴシエーションされた現在のALPN値を特定できます。


import java.net.Socket;
import java.security.*;
import javax.net.ssl.*;

public class MyX509ExtendedKeyManager extends X509ExtendedKeyManager {

    // X509ExtendedKeyManager is an abstract class so your new class 
    // needs to implement all the abstract methods in this class. 
    // The easiest way to do this is to wrap an existing KeyManager
    // and call its methods for each of the methods you need to implement.   

    X509ExtendedKeyManager akm;
    
    public MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
        this.akm = akm;
    }

    @Override
    public String[] getClientAliases(String keyType, Principal[] issuers) {
        return akm.getClientAliases(keyType, issuers);
    }

    @Override
    public String chooseClientAlias(String[] keyType, Principal[] issuers, 
        Socket socket) {
        return akm.chooseClientAlias(keyType, issuers, socket);
    }

    @Override
    public String chooseServerAlias(String keyType, Principal[] issuers, 
        Socket socket) {
        
        // This method has access to a Socket, so it is possible to call the
        // getHandshakeApplicationProtocol method here. Note the cast from 
        // a Socket to an SSLSocket
        String ap = ((SSLSocket) socket).getHandshakeApplicationProtocol();
        System.out.println("In chooseServerAlias, ap is: " + ap);
        return akm.chooseServerAlias(keyType, issuers, socket);
    }

    @Override
    public String[] getServerAliases(String keyType, Principal[] issuers) {
        return akm.getServerAliases(keyType, issuers);
    }

    @Override
    public X509Certificate[] getCertificateChain(String alias) {
        return akm.getCertificateChain(alias);
    }

    @Override
    public PrivateKey getPrivateKey(String alias) {
        return akm.getPrivateKey(alias);
    }
}
このコードがJavaサーバー用のKeyManagerとして登録されており、Javaクライアントによって、ALPN値を含むClientHelloが送信される場合、出力は次のようになります。
    In chooseServerAlias, ap is: <negotiated value>

例8-25 JavaサーバーでのカスタムKeyManagerの使用のサンプル・コード

この例では、デフォルトのALPNネゴシエーション戦略、および前のコード例で示されたカスタムKeyManagerMyX509ExtendedKeyManagerを使用する単純なJavaサーバーを示します。

import java.io.*;
import java.util.*;
import javax.net.ssl.*;
import java.security.KeyStore;

public class SSLServerHandshake {
    
    public static void main(String[] args) throws Exception {
        SSLContext ctx = SSLContext.getInstance("TLS");

        // You need to explicitly create a create a custom KeyManager

        // Keystores
        KeyStore keyKS = KeyStore.getInstance("PKCS12");
        keyKS.load(new FileInputStream("serverCert.p12"), 
            "password".toCharArray());

        // Generate KeyManager
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
        kmf.init(keyKS, "password".toCharArray());
        KeyManager[] kms = kmf.getKeyManagers();

        // Code to substitute MyX509ExtendedKeyManager
        if (!(kms[0] instanceof X509ExtendedKeyManager)) {
            throw new Exception("kms[0] not X509ExtendedKeyManager");
        }

        // Create a new KeyManager array and set the first index 
        // of the array to an instance of MyX509ExtendedKeyManager.
        // Notice how creating this object is done by passing in the 
        // existing default X509ExtendedKeyManager 
        kms = new KeyManager[] { 
            new MyX509ExtendedKeyManager((X509ExtendedKeyManager) kms[0])};

        // Initialize SSLContext using the new KeyManager
        ctx.init(kms, null, null);

        // Instead of using SSLServerSocketFactory.getDefault(), 
        // get a SSLServerSocketFactory based on the SSLContext
        SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
        SSLServerSocket sslServerSocket = 
            (SSLServerSocket) sslssf.createServerSocket(9999);
        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
        SSLParameters sslp = sslSocket.getSSLParameters();
        String[] serverAPs ={"one","two","three"};
        sslp.setApplicationProtocols(serverAPs);
        sslSocket.setSSLParameters(sslp);
        sslSocket.startHandshake();

        String ap = sslSocket.getApplicationProtocol();
        System.out.println("Application Protocol server side: \"" + ap + "\"");

        InputStream sslIS = sslSocket.getInputStream();
        OutputStream sslOS = sslSocket.getOutputStream();
        sslIS.read();
        sslOS.write(85);
        sslOS.flush();

        sslSocket.close();
        sslServerSocket.close();
    }
}

カスタムX509ExtendedKeyManagerの準備が整い、ハンドシェーク中にchooseServerAliasが呼び出されると、KeyManagerは、ネゴシエーションされたアプリケーション・プロトコル値を確認できるようになります。示されている例の場合、この値はコンソールに出力されます。

たとえば、このコードを実行し、Javaクライアントによって、ALPN値threeおよびtwoを含むClientHelloが送信されると、出力は次のようになります。
Application Protocol server side: two

ALPN関連のクラスとメソッド

これらのクラスとメソッドは、アプリケーション層プロトコル・ネゴシエーション(ALPN)の使用時に使用されます。

使用するクラスとメソッド

SSLEngineSSLSocketには同じALPN関連メソッドが含まれており、それらには同じ機能があります。

クラス メソッド 用途
SSLParameters public String[] getApplicationProtocols(); クライアント側とサーバー側: 各プロトコル・セットを含むString配列を返すには、このメソッドを使用します。
SSLParameters public void setApplicationProtocols([] protocols);

クライアント側: サーバーに選択可能なプロトコルを設定するには、このメソッドを使用します。

サーバー側: サーバーで使用可能なプロトコルを設定するには、このメソッドを使用します。String配列には、プロトコルが優先度順に含まれている必要があります。

SSLEngine

SSLSocket
public String getApplicationProtocol(); クライアント側とサーバー側: 接続のために選択されているプロトコルを含むStringを返すには、TLSプロトコル・ネゴシエーションが完了したに、このメソッドを使用します。
SSLEngine

SSLSocket
public String getHandshakeApplicationProtocol(); クライアント側とサーバー側: 接続のために選択されているプロトコルを含むStringを返すには、ハンドシェークにこのメソッドを使用します。ハンドシェークの前または後にこのメソッドが呼び出された場合は、nullが返されます。このメソッドの呼出し方法の詳細は、ハンドシェーク中のネゴシエーション済ALPN値の特定を参照してください。
SSLEngine

SSLSocket
public void setHandshakeApplicationProtocolSelector(BiFunction,String> selector) サーバー側: コールバック関数を登録するには、このメソッドを使用します。その後、プロトコルや暗号化方式群など、利用可能な任意の情報に基づいて、アプリケーション・プロトコル値をコールバック内で設定できます。このメソッドの使用方法の詳細は、サーバーでのカスタムALPNの設定を参照してください。

JSSEのトラブルシューティング

このセクションにはJSSEのトラブルシューティングに関する情報が含まれます。構成に関する一般的な問題の解決策を提供します。

まず、一般的な構成の問題とそれらの解決方法を説明し、次に、役に立つデバッグ・ユーティリティについて説明します。

構成の問題

構成に関するいくつかの一般的問題のための解決策。

ハンドシェーク時のCertificateException

問題: SSL/TLS/DTLS接続のネゴシエーション中に、クライアントまたはサーバーがCertificateExceptionをスローします。

原因1: 一般に、リモート側がローカル側に不明な証明書を送信することが原因です。

解決法1: このタイプの問題をデバッグするもっともよい方法は、デバッグをオンにして(「デバッグ・ユーティリティ」を参照)、証明書のロード時およびネットワーク接続経由での証明書の受信時に観察することです。多くの場合、間違ったトラスト・ファイルをロードしたため、受信した証明書がトラスト・メカニズムにとって不明です。

次の項を参照してください。

原因2: システム・クロックが正しく設定されていません。この場合、認識された時間が証明書の有効期間外になっている可能性があります。トラストストアからの有効な証明書と置き換えないかぎり、システムはこの証明書を無効とみなすため、例外をスローします。

解決法2: システム・クロックの時間を修正します。

実行時例外: SSL Service Not Available

問題: JSSEを使用するプログラムを実行すると、SSLサービスが利用できないという例外が発生します。たとえば、次のような例外がスローされます。

    Exception in thread "main" java.net.SocketException:
        no SSL Server Sockets
    
    Exception in thread "main":
        SSL implementation not available

原因: キーストア上の誤ったパスワードやキーストアの破損などのため、SSLContextの初期化で問題が発生しました(かつてあるベンダーが不明な形式のキーストアを出荷し、それが原因でこのタイプのエラーが発生しました。)

解決法: 初期化パラメータを確認します。指定したキーストアが有効であり、指定したパスワードが正しいことを確認します。これをチェックできる1つの方法は、keytoolを使用して、キーストアと関連の内容を調べることです。Java Platform, Standard Editionツール・リファレンスでkeytoolを参照してください。

実行時例外: "No available certificate corresponding to the SSL cipher suites which are enabled"

問題: 単純なSSLサーバー・プログラムを実行しようとすると、次の例外がスローされます。

    Exception in thread "main" javax.net.ssl.SSLException:
        No available certificate corresponding to the SSL cipher suites which are enabled...

原因: 様々な暗号化方式群では特定のタイプの鍵データが必要です。たとえば、RSA暗号化方式群が有効になっている場合、キーストアでRSAのkeyEntryを有効にする必要があります。該当する鍵を使用できない場合、その暗号化方式群を使用することはできません。有効になっているすべての暗号化方式群の鍵エントリが使用できない場合、この例外がスローされます。

解決法: 様々な暗号化方式群タイプの鍵エントリを作成するか、匿名の暗号化方式群を使用します。匿名の暗号化方式群には、MITM (man-in-the-middle)攻撃に対して脆弱であるため、潜在的に危険です。RFC 2246を参照してください。

正しいキーストアおよび証明書を渡す方法については、次のセクションを参照してください。

実行時例外: No Cipher Suites in Common

問題1: ハンドシェーク時にクライアントやサーバーがこの例外をスローします。

原因1: SSL接続の両側が共通の暗号化方式群について合意している必要があります。クライアントの暗号化方式群セットとサーバーの暗号化方式群セットの共通点がない場合、この例外がスローされます。

解決法1: 有効な暗号化方式群を構成し、共通の暗号化方式群を含めます。さらに、非対称の暗号化方式群に適切なkeyEntryが提供されるようにします。この項の実行時例外: "No available certificate corresponding to the SSL cipher suites which are enabled"も参照してください。

問題2: DSAベースの証明書しかないサーバーのファイルにMozilla FirefoxやMicrosoft Internet Explorerでアクセスすると、共通の暗号化方式群がないことを示す実行時例外が発生します。

原因2: デフォルトでは、keytoolで作成されたkeyEntriesはDSA公開鍵を使用します。キーストア内にDSAのkeyEntriesのみが存在する場合、使用できるのはDSAベースの暗号化方式群のみです。デフォルトでは、NavigatorとInternet ExplorerはRSAベースの暗号化方式群のみを送信します。クライアントとサーバーの暗号化方式群セットの共通点がないため、この例外がスローされます。

解決法2: NavigatorやInternet Explorerと対話するには、RSAベースの鍵を使用する証明書を作成してください。そのためには、keytool使用時に-keyalg RSAオプションを指定します。次に例を示します。

keytool -genkeypair -alias duke -keystore testkeys -keyalg rsa

ClientHelloメッセージの送信後ソケットが切断される

問題: ソケットが接続を試み、ClientHelloメッセージを送信すると、ただちに切断されます。

原因: SSL/TLSサーバーの中には、理解できない形式や、サポートしていないプロトコル・バージョン番号でClientHelloメッセージを受信した場合、接続を切断するものがあります。

解決法: クライアント側で、有効なプロトコルの調整を試みてください。これには、次のシステム・プロパティやメソッドの変更や呼び出しが含まれます。

後方互換性のため、一部のSSL/TLS実装(SunJSSEなど)はSSL/TLSのClientHelloメッセージをSSLv2のClientHello形式にカプセル化して送信できます。SunJSSEプロバイダはこの機能をサポートしています。この機能を使用する場合は、必要に応じて「SSLv2Hello」を有効なプロトコル・リストに追加します。(「JDKプロバイダ」で「プロトコル」を参照してください。ここでは、SunJSSEプロバイダでデフォルトで有効になっているプロトコルがリストされています。)

SSL/TLS RFC標準で、実装は、両側で使用されている最新バージョンとネゴシエーションする必要がありますが、認識できないバージョンを提示されると、一部の非準拠実装は単にハングアップします。たとえば、SSLv3のみを認識する一部の古いサーバー実装は、TLSv1.2を要求されると、シャットダウンします。この状況では、SSL/TLSバージョンのフォールバック・スキームを使用することを検討してください。

  1. サーバーでTLSv1.2を理解しない場合、TLSv1.2からTLSv1.1にフォールバックします。
  2. 前のステップが機能しない場合は、TLSv1.1からTLSv1.0にフォールバックします。

たとえば、クライアントの有効なプロトコル・リストがTLSv1、TLSv1.1およびTLSv1.2の場合、一般的なSSL/TLSバージョンのフォールバック・スキームが次のように見えます。

  1. サーバーに接続を試みます。サーバーがSSL/TLS接続要求をただちに拒否した場合は、ステップ2に進みます。
  2. 有効なプロトコル・リスト内の最高のプロトコル・バージョン(最初の失敗の場合TLSv1.2など)を削除して、バージョン・フォールバック・スキームを試行します。
  3. 再度サーバーに接続を試みます。サーバーが接続を拒否した場合、サーバーがフォールバックできるバージョンがない場合を除いて、ステップ2に進みます。
  4. 接続が失敗し、SSLv2Helloが有効なプロトコル・リストにない場合は、有効なプロトコル・リストを復元して、SSLv2Helloを有効にします。(たとえば、有効なプロトコル・リストは、SSLv2Hello、TLSv1、TLSv1.1およびTLSv1.2となる必要があります。)ステップ1から再度開始します。

注意:

以前のバージョンにフォールバックすることは、通常、セキュリティ強度が弱いプロトコルにダウングレードすることを意味します。本当に必要で、サーバーが上位のプロトコル・バージョンをサポートしていないことが確実にわかっている場合でないかぎり、フォールバック・スキームを使用することはお薦めしません。

注意:

一部のサーバーはSSLv3無効化の過程でSSLv2Helloも無効にしていますが、それは、SSLv2Helloがアクティブなクライアント(JDK 6u95)との通信が失敗することを意味します。JDK 7以降では、デフォルトで、SSLv2Helloはクライアント上では無効、サーバー上では有効です。

必要なアルゴリズムをサポートするJCAプロバイダをSunJSSEが見つけられず、NoSuchAlgorithmExceptionが発生する

問題: ハンドシェークが試行され、必要なアルゴリズムが見つからない場合は失敗します。例は次のとおりです。

Exception in thread ...deleted...
    ...deleted...
    Caused by java.security.NoSuchAlgorithmException: Cannot find any
        provider supporting RSA/ECB/PKCS1Padding

または

Caused by java.security.NoSuchAlgorithmException: Cannot find any
    provider supporting AES/CBC/NoPadding

原因: SunJSSEは、その暗号化アルゴリズムすべてでJCEを使用します。SunJCEプロバイダがProviderメカニズムから登録解除されており、JCEからの代替実装を利用できない場合、この例外がスローされます。

解決法: プロバイダがProviderインタフェースで登録されていることをチェックして、SunJCEが使用可能であることを確認します。SSL接続のコンテキストで次のコードを実行してみます。

import javax.crypto.*;

System.out.println("=====Where did you get AES=====");
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
System.out.println(c.getProvider());

WebサーバーからSSLでアプリケーション・リソースを取得しようとするとFailedDownloadExceptionがスローされる

問題: WebサーバーからSSLでアプリケーション・リソースを取得しようとしたときにcom.sun.deploy.net.FailedDownloadExceptionを受け取り、WebサーバーではServer Name Indication (SNI)拡張を持つ仮想ホストが使用されている場合(Apache HTTPサーバーなど)、Webサーバーが正しく構成されていないことがあります。

原因: Java SE 7では、JSSEクライアントのSNI拡張がサポートされているため、要求された仮想サーバーのホスト名は、SSLハンドシェーク中にクライアントからサーバーに送信された最初のメッセージに含まれています。要求されたホスト名(Server Name Indication)が、仮想ホストの構成に指定されているはずの期待されるサーバー名と一致しない場合、サーバーはクライアントの接続要求を拒否することがあります。これにより、SSLハンドシェークの認識されない名前の警告がトリガーされ、FailedDownloadExceptionがスローされます。

解決法: 問題を適切に診断するために、Javaコンソールを使用してトレースを有効にします。Java Platform, Standard Editionデプロイメント・ガイドでデバッグおよびJavaコンソールを参照してください。問題の原因がjavax.net.ssl.SSLProtocolException: handshake alert: unrecognized_nameの場合、SNIのための仮想ホスト構成が正しくない可能性があります。Apache HTTPサーバーを使用している場合、仮想ホストの構成については、名前ベースの仮想ホストのサポートを参照してください。特に、<VirtualHostブロック内でServerNameディレクティブが正しく構成されていることを確認してください。

次を参照してください。

RC4暗号化方式群がDTLS用に構成されている場合のIllegalArgumentException

問題: SSLEngine.setEnabledCipherSuites(String[] suites)メソッドでRC4暗号化方式群アルゴリズムが指定されており、SSLEngineがDTLSエンジンである場合に、IllegalArgumentException例外がスローされます。

sslContext = SSLContext.getInstance("DTLS");

// Create the engine
SSLEngine engine = sslContext.createSSLengine(hostname, port);

String enabledSuites[] = { "SSL_RSA_WITH_RC4_128_SHA" };
engine.setEnabledCipherSuites(enabledSuites);

原因: DTLSバージョン1.0DTLSバージョン1.2によると、RC4暗号化方式群はDTLSとは使用できません。

解決法: DTLS接続にはRC4ベースの暗号化方式群は使用しないでください。Javaセキュリティ標準アルゴリズム名JSSE暗号化方式群の名前を参照してください。

デバッグ・ユーティリティ

JSSEには、動的デバッグのトレースをサポートする機能があります。これは、Java SE プラットフォームでデバッグのアクセス制御に失敗した場合に使用するサポート機能に似ています。一般的なJava動的デバッグ・トレースのサポートにはjava.security.debugシステム・プロパティを使用してアクセスしますが、JSSE固有の動的デバッグ・トレースのサポートにはjavax.net.debugシステム・プロパティを使用してアクセスします。

注意:

debugユーティリティは、JSSEの公式にサポートされている機能ではありません。

JSSE動的デバッグ・ユーティリティのオプションを表示するには、javaコマンドで次のコマンド行オプションを使用します。

-Djavax.net.debug=help

注意:

ユーティリティがデバッグするように設計されたクラスを使用しないプログラムの実行中に、いずれかの動的デバッグ・ユーティリティで値helpを指定しても、デバッグ・オプションは得られません。

次の完全な例では、いくつかのJSSEクラスを使用するMyAppというアプリケーションのデバッグ・オプションのリストを取得する方法を示しています。

java -Djavax.net.debug=help MyApp

MyAppアプリケーションは、デバッグのヘルプ情報が表示されると動作しなくなりますが、これはヘルプコードによりアプリケーションが終了するためです。

現在のオプション:

  • all: すべてのデバッグを有効にします
  • ssl: SSLデバッグを有効にします

sslオプションとともに次のオプションを使用できます:

  • record: レコードごとのトレースを有効にします
  • handshake: 各ハンドシェーク・メッセージを出力します
  • keygen: 鍵生成データを出力します
  • session: セッション・アクティビティを出力します
  • defaultctx: デフォルトのSSL初期化を出力します
  • sslctx: SSLContextのトレースを出力します
  • sessioncache: セッション・キャッシュのトレースを出力します
  • keymanager: キー・マネージャのトレースを出力します
  • trustmanager: トラスト・マネージャのトレースを出力します

handshakeオプションによって生成されるメッセージは、次のオプションで拡張できます:

  • data: 各ハンドシェイク・メッセージの16進ダンプ
  • verbose: ハンドシェイク・メッセージの詳細出力

recordオプションによって生成されるメッセージは、次のオプションで拡張できます:

  • plaintext: レコードのプレーン・テキストの16進ダンプ
  • packet: raw SSL/TLSパケットを出力します

javax.net.debugプロパティ値は、allまたはsslを指定する必要があり、オプションでデバッグ指定子をその後に続けます。1つまたは複数のオプションが使用できます。オプションをセパレータで区切る必要はありませんが、コロン(:)やカンマ(,)などの区切り文字を使用すると読みやすくなります。どのセパレータでも使用でき、オプション・キーワードの順序も重要ではありません。

このデバッグ情報の見方の説明は、ガイド「SSL/TLS接続のデバッグ」を参照してください。

次に、javax.net.debugプロパティの使用例を示します。

  • デバッグ・メッセージをすべて表示する場合は、次のように入力します。

    java -Djavax.net.debug=all MyApp        
  • 各ハンドシェーク・メッセージを16進ダンプで表示するには、次のように入力します(コロンはオプションです)。

    java -Djavax.net.debug=ssl:handshake:data MyApp
    
  • 各ハンドシェーク・メッセージを16進ダンプで表示し、さらにトラスト・マネージャのトレース状態を表示するには、次のように入力します(カンマはオプションです)。

    java -Djavax.net.debug=SSL,handshake,data,trustmanager MyApp
    

SSL/TLS接続のデバッグ

SSL/TLS接続における問題は、理解するのが難しい場合があり、実際に送受信されたメッセージが明確でない場合は特に面倒です。SunJSSEにはデバッグ機能が組み込まれており、javax.net.debugシステム・プロパティによって起動されます。

javax.net.debugシステム・プロパティの詳細は、デバッグ・ユーティリティを参照してください。

デバッグ出力ファイルの読み方を例示する短いサンプルを次に示します。出力は標準的なものではなく、リリースによって変化することがあります。例では、デフォルトのSunJSSE X509KeyManagerとX509TrustManagerを使用してデバッグ情報を出力しています。

この例では、SSL/TLSプロトコルの基礎を理解していることを前提としています。プロトコルの詳細(ハンドシェーク・メッセージなど)は、Secure Sockets Layer (SSL)プロトコルの概要を参照してください。

次の例では、SSLSocketClientWithClientAuthサンプル・アプリケーションを使用してクライアント認証を必要とする簡単なHTTPSサーバーに接続し、HTTPS要求を送信して応答を受信します。

    java  -Djavax.net.debug=all  \
        -Djavax.net.ssl.trustStore=trustStore
        SSLSocketClientWithClientAuth bongos 2001 /index.html

まずX509KeyManagerが初期化され、「duke」と呼ばれる被認証者のKeyStoreに1つのkeyEntryがあることを発見します。サーバーがクライアントに対してクライアント自体の認証を要求すると、X509KeyManagerはkeyEntryのリストを検索して適切な資格を見つけます。

***
found key for : duke
chain [0] = [
[
  Version: V1
  Subject: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
  L=Cupertino, ST=CA, C=US
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  Sun RSA public key, 1024 bits
  modulus: 134968166047563266914058280571444028986498087544923991226919517
  667593269213420979048109900052353578998293280426361122296881234393722020
  704208851688212064483570055963805034839797994154526862998272017486468599
  962268346037652120279791547218281230795146025359480589335682217749874703
  510467348902637769973696151441
  public exponent: 65537
  Validity: [From: Tue May 22 16:46:46 PDT 2001,
               To: Sun May 22 16:46:46 PDT 2011]
  Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
  L=Cupertino, ST=CA, C=US
  SerialNumber: [    3b0afa66]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 5F B5 62 E9 A0 26 1D 8E   A2 7E 7C 02 08 36 3A 3E  _.b..&.......6:>
0010: C9 C2 45 03 DD F9 BC 06   FC 25 CF 30 92 91 B1 4E  ..E......%.0...N
0020: 62 17 08 48 14 68 80 CF   DD 89 11 EA 92 7F CE DD  b..H.h..........
0030: B4 FD 12 A8 71 C7 9E D7   C3 D0 E3 BD BB DE 20 92  ....q......... .
0040: C2 3B C8 DE CB 25 23 C0   8B B6 92 B9 0B 64 80 63  .;...%#......d.c
0050: D9 09 25 2D 7A CF 0A 31   B6 E9 CA C1 37 93 BC 0D  ..%-z..1....7...
0060: 4E 74 95 4F 58 31 DA AC   DF D8 BD 89 BD AF EC C8  Nt.OX1..........
0070: 2D 18 A2 BC B2 15 4F B7   28 6F D3 00 E1 72 9B 6C  -.....O.(o...r.l

]
***

次にX509TrustManagerが初期化され、「JSSE Test CA」という名前の証明書発行局(CA)の証明書を見つけます。このCAによって署名された

有効な

クレデンシャルを提示しているサーバーが信頼されます。

trustStore is: trustkeys
trustStore type is : jks
trustStore provider is : 
init truststore
adding as trusted cert:
  Subject: CN=JSSE Test CA, OU=JWS, O=Sun,
      L=Santa Clara, ST=CA, C=US
  Issuer:  CN=JSSE Test CA, OU=JWS, O=Sun,
      L=Santa Clara, ST=CA, C=US
  Algorithm: RSA; Serial number: 0x0
  Valid from Mon Jul 19 13:30:15 PDT 2004 until Fri Dec 05 12:30:15 PST 2031

付加的な初期化コードの一部が終了しました。このあと、いよいよサーバーに接続することができます。

trigger seeding of SecureRandom
done seeding SecureRandom
export control - checking the cipher suites
export control - no cached value available...
export control - storing legal entry into cache...
%% No cached client session

サーバーへの接続が確立されて、初期ClientHelloメッセージが表示されます。メッセージには次の情報が含まれています。

  • 暗号化ルーチンを初期化するランダム情報
  • SessionID。nullでない場合は、前のセッションを再確立する際に使用
  • クライアントが要求する暗号群のリスト
  • および非圧縮アルゴリズム。

このあと、SSLv2Helloヘッダー形式でのTLSv1ヘッダーのカプセル化(setEnabledProtocols()参照)など、さまざまなフィルタ出力が続きます。

*** ClientHello, TLSv1
RandomCookie:  GMT: 1073239164 bytes = { 10, 80, 71, 86, 124, 135, 104,
151, 72, 153, 70, 28, 97, 232, 160, 217, 146, 178, 87, 255, 122, 147, 83,
197, 60, 187, 227, 76 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA,
SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5,
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA]
Compression Methods:  { 0 }
***
[write] MD5 and SHA1 hashes:  len = 73
0000: 01 00 00 45 03 01 40 F8   54 7C 0A 50 47 56 7C 87  ...E..@.T..PGV..
0010: 68 97 48 99 46 1C 61 E8   A0 D9 92 B2 57 FF 7A 93  h.H.F.a.....W.z.
0020: 53 C5 3C BB E3 4C 00 00   1E 00 04 00 05 00 2F 00  S.<..L......../.
0030: 33 00 32 00 0A 00 16 00   13 00 09 00 15 00 12 00  3.2.............
0040: 03 00 08 00 14 00 11 01   00                       .........
main, WRITE: TLSv1 Handshake, length = 73
[write] MD5 and SHA1 hashes:  len = 98
0000: 01 03 01 00 39 00 00 00   20 00 00 04 01 00 80 00  ....9... .......
0010: 00 05 00 00 2F 00 00 33   00 00 32 00 00 0A 07 00  ..../..3..2.....
0020: C0 00 00 16 00 00 13 00   00 09 06 00 40 00 00 15  ............@...
0030: 00 00 12 00 00 03 02 00   80 00 00 08 00 00 14 00  ................
0040: 00 11 40 F8 54 7C 0A 50   47 56 7C 87 68 97 48 99  ..@.T..PGV..h.H.
0050: 46 1C 61 E8 A0 D9 92 B2   57 FF 7A 93 53 C5 3C BB  F.a.....W.z.S.<.
0060: E3 4C                                              .L
main, WRITE: SSLv2 client hello message, length = 98

「[Raw write]」というラベルのセクションは、raw出力オブジェクト(この場合はOutputStream)に送信される実際のデータを表します。

[Raw write]: length = 100
0000: 80 62 01 03 01 00 39 00   00 00 20 00 00 04 01 00  .b....9... .....
0010: 80 00 00 05 00 00 2F 00   00 33 00 00 32 00 00 0A  ....../..3..2...
0020: 07 00 C0 00 00 16 00 00   13 00 00 09 06 00 40 00  ..............@.
0030: 00 15 00 00 12 00 00 03   02 00 80 00 00 08 00 00  ................
0040: 14 00 00 11 40 F8 54 7C   0A 50 47 56 7C 87 68 97  ....@.T..PGV..h.
0050: 48 99 46 1C 61 E8 A0 D9   92 B2 57 FF 7A 93 53 C5  H.F.a.....W.z.S.
0060: 3C BB E3 4C                                        <..L

初期ClientHelloを送信したあと、サーバーの応答であるServerHelloを待ちます。「[Raw read]」は、処理が実行される前に、入力デバイス(InputStream)から読み取ったrawデータを表示します。

[Raw read]: length = 5
0000: 16 03 01 06 F0                                     .....
[Raw read]: length = 1776
0000: 02 00 00 46 03 01 40 FC   31 10 79 AB 17 66 FA 8B  ...F..@.1.y..f..
0010: 3F AA FD 5E 48 23 FA 90   31 D8 3C B9 A3 2C 8C F5  ?..^H#..1.<..,..
0020: E9 81 9B A2 63 6C 20 40   FC 31 10 BD 8D A5 91 06  ....cl @.1......
0030: 8B E1 E6 80 C6 5A 5C D9   8D 0A AE CA 58 4A BA 36  .....Z\.....XJ.6
0040: B1 3D 04 8D 82 21 B4 00   04 00 0B 00 06 1B 00 06  .=...!..........
0050: 18 00 03 11 30 82 03 0D   30 82 02 76 A0 03 02 01  ....0...0..v....
0060: 02 02 01 01 30 0D 06 09   2A 86 48 86 F7 0D 01 01  ....0...*.H.....
0070: 04 05 00 30 63 31 0B 30   09 06 03 55 04 06 13 02  ...0c1.0...U....
0080: 55 53 31 0B 30 09 06 03   55 04 08 13 02 43 41 31  US1.0...U....CA1
0090: 14 30 12 06 03 55 04 07   13 0B 53 61 6E 74 61 20  .0...U....Santa 
00A0: 43 6C 61 72 61 31 0C 30   0A 06 03 55 04 0A 13 03  Clara1.0...U....
00B0: 53 75 6E 31 0C 30 0A 06   03 55 04 0B 13 03 4A 57  Sun1.0...U....JW
00C0: 53 31 15 30 13 06 03 55   04 03 13 0C 4A 53 53 45  S1.0...U....JSSE
00D0: 20 54 65 73 74 20 43 41   30 1E 17 0D 30 34 30 37   Test CA0...0407
00E0: 31 39 32 30 33 30 35 31   5A 17 0D 33 31 31 32 30  19203051Z..31120
00F0: 35 32 30 33 30 35 31 5A   30 48 31 0B 30 09 06 03  5203051Z0H1.0...
0100: 55 04 06 13 02 55 53 31   0B 30 09 06 03 55 04 08  U....US1.0...U..
0110: 13 02 43 41 31 0C 30 0A   06 03 55 04 0A 13 03 53  ..CA1.0...U....S
0120: 75 6E 31 0D 30 0B 06 03   55 04 0B 13 04 4A 61 76  un1.0...U....Jav
0130: 61 31 0F 30 0D 06 03 55   04 03 13 06 62 6F 6E 67  a1.0...U....bong
0140: 6F 73 30 81 9F 30 0D 06   09 2A 86 48 86 F7 0D 01  os0..0...*.H....
0150: 01 01 05 00 03 81 8D 00   30 81 89 02 81 81 00 CC  ........0.......
0160: 09 74 CB 43 AB 6D ED F6   35 AA 0E 49 29 D9 E0 F0  .t.C.m..5..I)...
0170: A1 D5 E2 3E 8F 5E C5 CE   F4 DE C1 A4 F3 CB 8C 45  ...>.^.........E
0180: 0B 0F 6E 21 E1 00 65 CB   3C D1 5C EF 6A FB 5D 96  ..n!..e.<.\.j.].
0190: 93 F4 71 41 41 45 FF 37   86 4C AB F9 EA 9A 3F A5  ..qAAE.7.L....?.
01A0: 82 60 BF 0A 81 84 C9 3E   AC 0F 3D 20 3D AC A0 69  .`.....>..= =..i
01B0: EF CA 4A A7 94 AD C8 A5   CE 37 66 52 D1 25 43 CB  ..J......7fR.%C.
01C0: 10 44 07 1E 93 74 D9 68   01 D7 06 48 C9 0D 52 2D  .D...t.h...H..R-
01D0: D5 6A 2E A6 48 4C 59 E2   5C C6 C1 5C C8 4C 1B 02  .j..HLY.\..\.L..
01E0: 03 01 00 01 A3 81 EB 30   81 E8 30 09 06 03 55 1D  .......0..0...U.
01F0: 13 04 02 30 00 30 2C 06   09 60 86 48 01 86 F8 42  ...0.0,..`.H...B
0200: 01 0D 04 1F 16 1D 4F 70   65 6E 53 53 4C 20 47 65  ......OpenSSL Ge
0210: 6E 65 72 61 74 65 64 20   43 65 72 74 69 66 69 63  nerated Certific
0220: 61 74 65 30 1D 06 03 55   1D 0E 04 16 04 14 58 D7  ate0...U......X.
0230: 3A A9 37 AA 3E 14 27 FC   EC CC 45 08 04 8E 2A 8B  :.7.>.'...E...*.
0240: 77 28 30 81 8D 06 03 55   1D 23 04 81 85 30 81 82  w(0....U.#...0..
0250: 80 14 08 A3 7E 35 96 15   FA B0 F5 1B 5F CD 4F 54  .....5......_.OT
0260: EF 31 33 70 E4 A7 A1 67   A4 65 30 63 31 0B 30 09  .13p...g.e0c1.0.
0270: 06 03 55 04 06 13 02 55   53 31 0B 30 09 06 03 55  ..U....US1.0...U
0280: 04 08 13 02 43 41 31 14   30 12 06 03 55 04 07 13  ....CA1.0...U...
0290: 0B 53 61 6E 74 61 20 43   6C 61 72 61 31 0C 30 0A  .Santa Clara1.0.
02A0: 06 03 55 04 0A 13 03 53   75 6E 31 0C 30 0A 06 03  ..U....Sun1.0...
02B0: 55 04 0B 13 03 4A 57 53   31 15 30 13 06 03 55 04  U....JWS1.0...U.
02C0: 03 13 0C 4A 53 53 45 20   54 65 73 74 20 43 41 82  ...JSSE Test CA.
02D0: 01 00 30 0D 06 09 2A 86   48 86 F7 0D 01 01 04 05  ..0...*.H.......
02E0: 00 03 81 81 00 05 3E 17   DA F2 05 CB 4E 9E BF 12  ......>.....N...
02F0: CE 13 76 FF B2 FB 7F 9C   3D 45 28 43 6C 98 28 E3  ..v.....=E(Cl.(.
0300: 92 17 C2 C6 F1 62 CA 60   C2 B0 EC E6 7E 4C 2F C2  .....b.`.....L/.
0310: 40 FE 06 CB 34 60 B1 F4   26 1C E8 46 39 24 E1 8A  @...4`..&..F9$..
0320: 71 F2 13 90 A4 0A 7B 0B   13 AB 51 68 53 D9 7A 31  q.........QhS.z1
0330: 5A C1 7E 3C 44 2C 49 70   57 25 F9 18 FE 5D A5 42  Z..<D,IpW%...].B
0340: 7F 3E 61 1F 29 A3 31 46   02 C6 D2 8C 27 79 40 76  .>a.).1F....'y@v
0350: 97 B6 25 19 BE 6C 6A 92   DC EF 11 BE E7 4A FF 2A  ..%..lj......J.*
0360: E6 D6 AC 39 31 00 03 01   30 82 02 FD 30 82 02 66  ...91...0...0..f
0370: A0 03 02 01 02 02 01 00   30 0D 06 09 2A 86 48 86  ........0...*.H.
0380: F7 0D 01 01 04 05 00 30   63 31 0B 30 09 06 03 55  .......0c1.0...U
0390: 04 06 13 02 55 53 31 0B   30 09 06 03 55 04 08 13  ....US1.0...U...
03A0: 02 43 41 31 14 30 12 06   03 55 04 07 13 0B 53 61  .CA1.0...U....Sa
03B0: 6E 74 61 20 43 6C 61 72   61 31 0C 30 0A 06 03 55  nta Clara1.0...U
03C0: 04 0A 13 03 53 75 6E 31   0C 30 0A 06 03 55 04 0B  ....Sun1.0...U..
03D0: 13 03 4A 57 53 31 15 30   13 06 03 55 04 03 13 0C  ..JWS1.0...U....
03E0: 4A 53 53 45 20 54 65 73   74 20 43 41 30 1E 17 0D  JSSE Test CA0...
03F0: 30 34 30 37 31 39 32 30   33 30 31 35 5A 17 0D 33  040719203015Z..3
0400: 31 31 32 30 35 32 30 33   30 31 35 5A 30 63 31 0B  11205203015Z0c1.
0410: 30 09 06 03 55 04 06 13   02 55 53 31 0B 30 09 06  0...U....US1.0..
0420: 03 55 04 08 13 02 43 41   31 14 30 12 06 03 55 04  .U....CA1.0...U.
0430: 07 13 0B 53 61 6E 74 61   20 43 6C 61 72 61 31 0C  ...Santa Clara1.
0440: 30 0A 06 03 55 04 0A 13   03 53 75 6E 31 0C 30 0A  0...U....Sun1.0.
0450: 06 03 55 04 0B 13 03 4A   57 53 31 15 30 13 06 03  ..U....JWS1.0...
0460: 55 04 03 13 0C 4A 53 53   45 20 54 65 73 74 20 43  U....JSSE Test C
0470: 41 30 81 9F 30 0D 06 09   2A 86 48 86 F7 0D 01 01  A0..0...*.H.....
0480: 01 05 00 03 81 8D 00 30   81 89 02 81 81 00 9A 0A  .......0........
0490: B6 45 66 D5 DE 4A D9 3C   8C AC A6 B5 A5 88 B4 CF  .Ef..J.<........
04A0: 14 E1 A6 1B 25 25 4F 44   C9 1F 22 38 32 29 CF A1  ....%%OD.."82)..
04B0: 7C 18 30 93 DC 2B EC 2B   67 EE 2E 08 66 2D 0F 47  ..0..+.+g...f-.G
04C0: E0 12 3A DC E0 03 E9 65   16 F6 18 C6 16 14 56 24  ..:....e......V$
04D0: 55 7D 32 3E F9 66 A2 DD   55 EB 4D 0A 67 C7 5D 21  U.2>.f..U.M.g.]!
04E0: 9B 29 EA 2E 51 C5 83 A3   55 FF 35 CA A6 99 8F 46  .)..Q...U.5....F
04F0: F8 8E 56 BB A2 B1 39 83   D8 61 42 79 E0 95 78 FA  ..V...9..aBy..x.
0500: C6 E3 65 B0 FD 74 2D 64   51 71 04 F2 A1 91 02 03  ..e..t-dQq......
0510: 01 00 01 A3 81 C0 30 81   BD 30 1D 06 03 55 1D 0E  ......0..0...U..
0520: 04 16 04 14 08 A3 7E 35   96 15 FA B0 F5 1B 5F CD  .......5......_.
0530: 4F 54 EF 31 33 70 E4 A7   30 81 8D 06 03 55 1D 23  OT.13p..0....U.#
0540: 04 81 85 30 81 82 80 14   08 A3 7E 35 96 15 FA B0  ...0.......5....
0550: F5 1B 5F CD 4F 54 EF 31   33 70 E4 A7 A1 67 A4 65  .._.OT.13p...g.e
0560: 30 63 31 0B 30 09 06 03   55 04 06 13 02 55 53 31  0c1.0...U....US1
0570: 0B 30 09 06 03 55 04 08   13 02 43 41 31 14 30 12  .0...U....CA1.0.
0580: 06 03 55 04 07 13 0B 53   61 6E 74 61 20 43 6C 61  ..U....Santa Cla
0590: 72 61 31 0C 30 0A 06 03   55 04 0A 13 03 53 75 6E  ra1.0...U....Sun
05A0: 31 0C 30 0A 06 03 55 04   0B 13 03 4A 57 53 31 15  1.0...U....JWS1.
05B0: 30 13 06 03 55 04 03 13   0C 4A 53 53 45 20 54 65  0...U....JSSE Te
05C0: 73 74 20 43 41 82 01 00   30 0C 06 03 55 1D 13 04  st CA...0...U...
05D0: 05 30 03 01 01 FF 30 0D   06 09 2A 86 48 86 F7 0D  .0....0...*.H...
05E0: 01 01 04 05 00 03 81 81   00 73 6A 46 A2 05 E3 D8  .........sjF....
05F0: 6E 5C F4 18 A2 74 BC CF   EB 0C 5B FF 81 1C 28 85  n\...t....[...(.
0600: C7 FA E4 ED 5C 4F 71 22   FB 26 E3 01 3D 0C 10 AA  ....\Oq".&..=...
0610: BB 3E 90 ED 0E 1F 0C 9B   B1 8C 49 6A 51 E4 C3 52  .>........IjQ..R
0620: D6 FB 42 6C B4 A9 A9 57   A5 84 00 42 6D 37 37 6D  ..Bl...W...Bm77m
0630: C7 6C 23 BC DC 60 D1 9D   6F B3 75 47 3A 15 33 1A  .l#..`..o.uG:.3.
0640: EC 90 09 9D F9 EB BD 88   96 E7 1D 41 BC 01 8D CA  ...........A....
0650: 88 D9 5B 04 09 8F 3E EA   C8 15 A0 AA 4E 85 95 AE  ..[...>.....N...
0660: 2F 0E 31 92 AC 3C FB 2F   C4 0D 00 00 7F 02 01 02  /.1..<./........
0670: 00 7A 00 78 30 76 31 0B   30 09 06 03 55 04 06 13  .z.x0v1.0...U...
0680: 02 55 53 31 0B 30 09 06   03 55 04 08 13 02 43 41  .US1.0...U....CA
0690: 31 12 30 10 06 03 55 04   07 13 09 43 75 70 65 72  1.0...U....Cuper
06A0: 74 69 6E 6F 31 1F 30 1D   06 03 55 04 0A 13 16 53  tino1.0...U....S
06B0: 75 6E 20 4D 69 63 72 6F   73 79 73 74 65 6D 73 2C  un Microsystems,
06C0: 20 49 6E 63 2E 31 16 30   14 06 03 55 04 0B 13 0D   Inc.1.0...U....
06D0: 4A 61 76 61 20 53 6F 66   74 77 61 72 65 31 0D 30  Java Software1.0
06E0: 0B 06 03 55 04 03 13 04   44 75 6B 65 0E 00 00 00  ...U....Duke....
main, READ: TLSv1 Handshake, length = 1776

データは展開され、メッセージがSSL/TLS形式の場合はServerHelloに解析されます。非SSL/TLSソケット(プレーン・テキスト)に接続した場合、受信データはSSL/TLS形式ではないので、正常に接続できません。

ServerHelloは、次の事柄を指定します。

  • サーバーのランダム・データ。暗号化アルゴリズムの初期化にも使用される
  • このセッションの識別子(別の接続を使用してクライアントがこのセッションに再び参加する場合は、ClientHelloにあるこのIDを送信できる。クライアント・セッションIDとサーバー・セッションIDが等しい場合は、省略されたハンドシェークが実行され、以前に確立されたパラメータが使用される)
  • 選択された符号化方式
  • 圧縮方法。この場合はなし。

最後に、ServerHelloは、接続において「SSLv3」ではなく「TLSv1」を使用するように指定しています。

                                           
*** ServerHello, TLSv1
RandomCookie:  GMT: 1073492240 bytes = { 121, 171, 23, 102, 250, 139, 63,
170, 253, 94, 72, 35, 250, 144, 49, 216, 60, 185, 163, 44, 140, 245, 233,
129, 155, 162, 99, 108 }
Session ID:  {64, 252, 49, 16, 189, 141, 165, 145, 6, 139, 225, 230, 128,
198, 90, 92, 217, 141, 10, 174, 202, 88, 74, 186, 54, 177, 61, 4, 141, 130,
33, 180}
Cipher Suite: SSL_RSA_WITH_RC4_128_MD5
Compression Method: 0
***
%% Created:  [Session-1, SSL_RSA_WITH_RC4_128_MD5]
** SSL_RSA_WITH_RC4_128_MD5
[read] MD5 and SHA1 hashes:  len = 74
0000: 02 00 00 46 03 01 40 FC   31 10 79 AB 17 66 FA 8B  ...F..@.1.y..f..
0010: 3F AA FD 5E 48 23 FA 90   31 D8 3C B9 A3 2C 8C F5  ?..^H#..1.<..,..
0020: E9 81 9B A2 63 6C 20 40   FC 31 10 BD 8D A5 91 06  ....cl @.1......
0030: 8B E1 E6 80 C6 5A 5C D9   8D 0A AE CA 58 4A BA 36  .....Z\.....XJ.6
0040: B1 3D 04 8D 82 21 B4 00   04 00                    .=...!....

次にサーバーは、証明書チェーンを渡すことによってクライアントに自身の身元を証明します。この例では、発行者「JSSE Test CA」によって署名された被認証者「bongos」の証明書を使用します。「JSSE Test CA」は信頼されるCAであることがわかっているので、証明書チェーンがX509TrustManagerによって正常に検証されれば、この接続を受け入れることができます。

信頼関係を確立する方法は数多く存在するので、デフォルトのX509TrustManagerが必要とする信頼管理を実行しない場合は、独自のX509TrustManagerをSSLContextに設定できます。

*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: 
  CN=bongos, OU=Java, O=Sun, ST=CA, C=US
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  Sun RSA public key, 1024 bits
  modulus: 143279610700427050704216702734995283650706638118826657356308087
  682552751165540126665070195006746918193702313900836063802045448392771274
  463088345157808670190122017153821642985630288017629294930800445939721128
  735250668515619736933648548512047941708018130926985936894512063397816602
  623867976474763783110866258971
  public exponent: 65537
  Validity: [From: Mon Jul 19 13:30:51 PDT 2004,
               To: Fri Dec 05 12:30:51 PST 2031]
  Issuer: CN=JSSE Test CA, OU=JWS, O=Sun,
      L=Santa Clara, ST=CA, C=US
  SerialNumber: [    01]

Certificate Extensions: 3

[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 58 D7 3A A9 37 AA 3E 14   27 FC EC CC 45 08 04 8E  X.:.7.>.'...E...
0010: 2A 8B 77 28                                        *.w(
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 08 A3 7E 35 96 15 FA B0   F5 1B 5F CD 4F 54 EF 31  ...5......_.OT.1
0010: 33 70 E4 A7                                        3p..
]

[CN=JSSE Test CA, OU=JWS, O=Sun, L=Santa Clara, ST=CA, C=US]
SerialNumber: [    00]
]

[3]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 05 3E 17 DA F2 05 CB 4E   9E BF 12 CE 13 76 FF B2  .>.....N.....v..
0010: FB 7F 9C 3D 45 28 43 6C   98 28 E3 92 17 C2 C6 F1  ...=E(Cl.(......
0020: 62 CA 60 C2 B0 EC E6 7E   4C 2F C2 40 FE 06 CB 34  b.`.....L/.@...4
0030: 60 B1 F4 26 1C E8 46 39   24 E1 8A 71 F2 13 90 A4  `..&..F9$..q....
0040: 0A 7B 0B 13 AB 51 68 53   D9 7A 31 5A C1 7E 3C 44  .....QhS.z1Z..<D
0050: 2C 49 70 57 25 F9 18 FE   5D A5 42 7F 3E 61 1F 29  ,IpW%...].B.>a.)
0060: A3 31 46 02 C6 D2 8C 27   79 40 76 97 B6 25 19 BE  .1F....'y@v..%..
0070: 6C 6A 92 DC EF 11 BE E7   4A FF 2A E6 D6 AC 39 31  lj......J.*...91

]
chain [1] = [
[
  Version: V3
  Subject: CN=JSSE Test CA, OU=JWS, O=Sun,
      L=Santa Clara, ST=CA, C=US
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  Sun RSA public key, 1024 bits
  modulus: 108171861314934294923646852258201093253619460299818135230481040
  615923025149195168140458238629251726950220398889722590740552079782864577
  976838691751841449679901644183317203824143803940037883199193775839934767
  304560313841716869284745769157293013188246601563271959824290073095150730
  505329011956986145636520993169
  public exponent: 65537
  Validity: [From: Mon Jul 19 13:30:15 PDT 2004,
               To: Fri Dec 05 12:30:15 PST 2031]
  Issuer: CN=JSSE Test CA, OU=JWS, O=Sun,
      L=Santa Clara, ST=CA, C=US
  SerialNumber: [    00]

Certificate Extensions: 3
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 08 A3 7E 35 96 15 FA B0   F5 1B 5F CD 4F 54 EF 31  ...5......_.OT.1
0010: 33 70 E4 A7                                        3p..
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 08 A3 7E 35 96 15 FA B0   F5 1B 5F CD 4F 54 EF 31  ...5......_.OT.1
0010: 33 70 E4 A7                                        3p..
]

[CN=JSSE Test CA, OU=JWS, O=Sun, L=Santa Clara, ST=CA, C=US]
SerialNumber: [    00]
]

[3]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 73 6A 46 A2 05 E3 D8 6E   5C F4 18 A2 74 BC CF EB  sjF....n\...t...
0010: 0C 5B FF 81 1C 28 85 C7   FA E4 ED 5C 4F 71 22 FB  .[...(.....\Oq".
0020: 26 E3 01 3D 0C 10 AA BB   3E 90 ED 0E 1F 0C 9B B1  &..=....>.......
0030: 8C 49 6A 51 E4 C3 52 D6   FB 42 6C B4 A9 A9 57 A5  .IjQ..R..Bl...W.
0040: 84 00 42 6D 37 37 6D C7   6C 23 BC DC 60 D1 9D 6F  ..Bm77m.l#..`..o
0050: B3 75 47 3A 15 33 1A EC   90 09 9D F9 EB BD 88 96  .uG:.3..........
0060: E7 1D 41 BC 01 8D CA 88   D9 5B 04 09 8F 3E EA C8  ..A......[...>..
0070: 15 A0 AA 4E 85 95 AE 2F   0E 31 92 AC 3C FB 2F C4  ...N.../.1..<./.

]

この証明書を認識します。証明書を信頼してハンドシェークを続行できます。

***
Found trusted certificate:
[
[
  Version: V3
  Subject: CN=JSSE Test CA, OU=JWS, O=Sun, L=Santa Clara, ST=CA, C=US
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  Sun RSA public key, 1024 bits
  modulus: 108171861314934294923646852258201093253619460299818135230481040
  615923025149195168140458238629251726950220398889722590740552079782864577
  976838691751841449679901644183317203824143803940037883199193775839934767
  304560313841716869284745769157293013188246601563271959824290073095150730
  505329011956986145636520993169
  public exponent: 65537
  Validity: [From: Mon Jul 19 13:30:15 PDT 2004,
               To: Fri Dec 05 12:30:15 PST 2031]
  Issuer: CN=JSSE Test CA, OU=JWS, O=Sun, L=Santa Clara, ST=CA, C=US
  SerialNumber: [    00]

Certificate Extensions: 3
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 08 A3 7E 35 96 15 FA B0   F5 1B 5F CD 4F 54 EF 31  ...5......_.OT.1
0010: 33 70 E4 A7                                        3p..
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 08 A3 7E 35 96 15 FA B0   F5 1B 5F CD 4F 54 EF 31  ...5......_.OT.1
0010: 33 70 E4 A7                                        3p..
]

[CN=JSSE Test CA, OU=JWS, O=Sun, L=Santa Clara, ST=CA, C=US]
SerialNumber: [    00]
]

[3]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen:2147483647
]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 73 6A 46 A2 05 E3 D8 6E   5C F4 18 A2 74 BC CF EB  sjF....n\...t...
0010: 0C 5B FF 81 1C 28 85 C7   FA E4 ED 5C 4F 71 22 FB  .[...(.....\Oq".
0020: 26 E3 01 3D 0C 10 AA BB   3E 90 ED 0E 1F 0C 9B B1  &..=....>.......
0030: 8C 49 6A 51 E4 C3 52 D6   FB 42 6C B4 A9 A9 57 A5  .IjQ..R..Bl...W.
0040: 84 00 42 6D 37 37 6D C7   6C 23 BC DC 60 D1 9D 6F  ..Bm77m.l#..`..o
0050: B3 75 47 3A 15 33 1A EC   90 09 9D F9 EB BD 88 96  .uG:.3..........
0060: E7 1D 41 BC 01 8D CA 88   D9 5B 04 09 8F 3E EA C8  ..A......[...>..
0070: 15 A0 AA 4E 85 95 AE 2F   0E 31 92 AC 3C FB 2F C4  ...N.../.1..<./.

]

次のハンドシェークの数バイトを読み取ります。

[read] MD5 and SHA1 hashes:  len = 1567
0000: 0B 00 06 1B 00 06 18 00   03 11 30 82 03 0D 30 82  ..........0...0.
0010: 02 76 A0 03 02 01 02 02   01 01 30 0D 06 09 2A 86  .v........0...*.
0020: 48 86 F7 0D 01 01 04 05   00 30 63 31 0B 30 09 06  H........0c1.0..
0030: 03 55 04 06 13 02 55 53   31 0B 30 09 06 03 55 04  .U....US1.0...U.
0040: 08 13 02 43 41 31 14 30   12 06 03 55 04 07 13 0B  ...CA1.0...U....
0050: 53 61 6E 74 61 20 43 6C   61 72 61 31 0C 30 0A 06  Santa Clara1.0..
0060: 03 55 04 0A 13 03 53 75   6E 31 0C 30 0A 06 03 55  .U....Sun1.0...U
0070: 04 0B 13 03 4A 57 53 31   15 30 13 06 03 55 04 03  ....JWS1.0...U..
0080: 13 0C 4A 53 53 45 20 54   65 73 74 20 43 41 30 1E  ..JSSE Test CA0.
0090: 17 0D 30 34 30 37 31 39   32 30 33 30 35 31 5A 17  ..040719203051Z.
00A0: 0D 33 31 31 32 30 35 32   30 33 30 35 31 5A 30 48  .311205203051Z0H
00B0: 31 0B 30 09 06 03 55 04   06 13 02 55 53 31 0B 30  1.0...U....US1.0
00C0: 09 06 03 55 04 08 13 02   43 41 31 0C 30 0A 06 03  ...U....CA1.0...
00D0: 55 04 0A 13 03 53 75 6E   31 0D 30 0B 06 03 55 04  U....Sun1.0...U.
00E0: 0B 13 04 4A 61 76 61 31   0F 30 0D 06 03 55 04 03  ...Java1.0...U..
00F0: 13 06 62 6F 6E 67 6F 73   30 81 9F 30 0D 06 09 2A  ..bongos0..0...*
0100: 86 48 86 F7 0D 01 01 01   05 00 03 81 8D 00 30 81  .H............0.
0110: 89 02 81 81 00 CC 09 74   CB 43 AB 6D ED F6 35 AA  .......t.C.m..5.
0120: 0E 49 29 D9 E0 F0 A1 D5   E2 3E 8F 5E C5 CE F4 DE  .I)......>.^....
0130: C1 A4 F3 CB 8C 45 0B 0F   6E 21 E1 00 65 CB 3C D1  .....E..n!..e.<.
0140: 5C EF 6A FB 5D 96 93 F4   71 41 41 45 FF 37 86 4C  \.j.]...qAAE.7.L
0150: AB F9 EA 9A 3F A5 82 60   BF 0A 81 84 C9 3E AC 0F  ....?..`.....>..
0160: 3D 20 3D AC A0 69 EF CA   4A A7 94 AD C8 A5 CE 37  = =..i..J......7
0170: 66 52 D1 25 43 CB 10 44   07 1E 93 74 D9 68 01 D7  fR.%C..D...t.h..
0180: 06 48 C9 0D 52 2D D5 6A   2E A6 48 4C 59 E2 5C C6  .H..R-.j..HLY.\.
0190: C1 5C C8 4C 1B 02 03 01   00 01 A3 81 EB 30 81 E8  .\.L.........0..
01A0: 30 09 06 03 55 1D 13 04   02 30 00 30 2C 06 09 60  0...U....0.0,..`
01B0: 86 48 01 86 F8 42 01 0D   04 1F 16 1D 4F 70 65 6E  .H...B......Open
01C0: 53 53 4C 20 47 65 6E 65   72 61 74 65 64 20 43 65  SSL Generated Ce
01D0: 72 74 69 66 69 63 61 74   65 30 1D 06 03 55 1D 0E  rtificate0...U..
01E0: 04 16 04 14 58 D7 3A A9   37 AA 3E 14 27 FC EC CC  ....X.:.7.>.'...
01F0: 45 08 04 8E 2A 8B 77 28   30 81 8D 06 03 55 1D 23  E...*.w(0....U.#
0200: 04 81 85 30 81 82 80 14   08 A3 7E 35 96 15 FA B0  ...0.......5....
0210: F5 1B 5F CD 4F 54 EF 31   33 70 E4 A7 A1 67 A4 65  .._.OT.13p...g.e
0220: 30 63 31 0B 30 09 06 03   55 04 06 13 02 55 53 31  0c1.0...U....US1
0230: 0B 30 09 06 03 55 04 08   13 02 43 41 31 14 30 12  .0...U....CA1.0.
0240: 06 03 55 04 07 13 0B 53   61 6E 74 61 20 43 6C 61  ..U....Santa Cla
0250: 72 61 31 0C 30 0A 06 03   55 04 0A 13 03 53 75 6E  ra1.0...U....Sun
0260: 31 0C 30 0A 06 03 55 04   0B 13 03 4A 57 53 31 15  1.0...U....JWS1.
0270: 30 13 06 03 55 04 03 13   0C 4A 53 53 45 20 54 65  0...U....JSSE Te
0280: 73 74 20 43 41 82 01 00   30 0D 06 09 2A 86 48 86  st CA...0...*.H.
0290: F7 0D 01 01 04 05 00 03   81 81 00 05 3E 17 DA F2  ............>...
02A0: 05 CB 4E 9E BF 12 CE 13   76 FF B2 FB 7F 9C 3D 45  ..N.....v.....=E
02B0: 28 43 6C 98 28 E3 92 17   C2 C6 F1 62 CA 60 C2 B0  (Cl.(......b.`..
02C0: EC E6 7E 4C 2F C2 40 FE   06 CB 34 60 B1 F4 26 1C  ...L/.@...4`..&.
02D0: E8 46 39 24 E1 8A 71 F2   13 90 A4 0A 7B 0B 13 AB  .F9$..q.........
02E0: 51 68 53 D9 7A 31 5A C1   7E 3C 44 2C 49 70 57 25  QhS.z1Z..<D,IpW%
02F0: F9 18 FE 5D A5 42 7F 3E   61 1F 29 A3 31 46 02 C6  ...].B.>a.).1F..
0300: D2 8C 27 79 40 76 97 B6   25 19 BE 6C 6A 92 DC EF  ..'y@v..%..lj...
0310: 11 BE E7 4A FF 2A E6 D6   AC 39 31 00 03 01 30 82  ...J.*...91...0.
0320: 02 FD 30 82 02 66 A0 03   02 01 02 02 01 00 30 0D  ..0..f........0.
0330: 06 09 2A 86 48 86 F7 0D   01 01 04 05 00 30 63 31  ..*.H........0c1
0340: 0B 30 09 06 03 55 04 06   13 02 55 53 31 0B 30 09  .0...U....US1.0.
0350: 06 03 55 04 08 13 02 43   41 31 14 30 12 06 03 55  ..U....CA1.0...U
0360: 04 07 13 0B 53 61 6E 74   61 20 43 6C 61 72 61 31  ....Santa Clara1
0370: 0C 30 0A 06 03 55 04 0A   13 03 53 75 6E 31 0C 30  .0...U....Sun1.0
0380: 0A 06 03 55 04 0B 13 03   4A 57 53 31 15 30 13 06  ...U....JWS1.0..
0390: 03 55 04 03 13 0C 4A 53   53 45 20 54 65 73 74 20  .U....JSSE Test 
03A0: 43 41 30 1E 17 0D 30 34   30 37 31 39 32 30 33 30  CA0...0407192030
03B0: 31 35 5A 17 0D 33 31 31   32 30 35 32 30 33 30 31  15Z..31120520301
03C0: 35 5A 30 63 31 0B 30 09   06 03 55 04 06 13 02 55  5Z0c1.0...U....U
03D0: 53 31 0B 30 09 06 03 55   04 08 13 02 43 41 31 14  S1.0...U....CA1.
03E0: 30 12 06 03 55 04 07 13   0B 53 61 6E 74 61 20 43  0...U....Santa C
03F0: 6C 61 72 61 31 0C 30 0A   06 03 55 04 0A 13 03 53  lara1.0...U....S
0400: 75 6E 31 0C 30 0A 06 03   55 04 0B 13 03 4A 57 53  un1.0...U....JWS
0410: 31 15 30 13 06 03 55 04   03 13 0C 4A 53 53 45 20  1.0...U....JSSE 
0420: 54 65 73 74 20 43 41 30   81 9F 30 0D 06 09 2A 86  Test CA0..0...*.
0430: 48 86 F7 0D 01 01 01 05   00 03 81 8D 00 30 81 89  H............0..
0440: 02 81 81 00 9A 0A B6 45   66 D5 DE 4A D9 3C 8C AC  .......Ef..J.<..
0450: A6 B5 A5 88 B4 CF 14 E1   A6 1B 25 25 4F 44 C9 1F  ..........%%OD..
0460: 22 38 32 29 CF A1 7C 18   30 93 DC 2B EC 2B 67 EE  "82)....0..+.+g.
0470: 2E 08 66 2D 0F 47 E0 12   3A DC E0 03 E9 65 16 F6  ..f-.G..:....e..
0480: 18 C6 16 14 56 24 55 7D   32 3E F9 66 A2 DD 55 EB  ....V$U.2>.f..U.
0490: 4D 0A 67 C7 5D 21 9B 29   EA 2E 51 C5 83 A3 55 FF  M.g.]!.)..Q...U.
04A0: 35 CA A6 99 8F 46 F8 8E   56 BB A2 B1 39 83 D8 61  5....F..V...9..a
04B0: 42 79 E0 95 78 FA C6 E3   65 B0 FD 74 2D 64 51 71  By..x...e..t-dQq
04C0: 04 F2 A1 91 02 03 01 00   01 A3 81 C0 30 81 BD 30  ............0..0
04D0: 1D 06 03 55 1D 0E 04 16   04 14 08 A3 7E 35 96 15  ...U.........5..
04E0: FA B0 F5 1B 5F CD 4F 54   EF 31 33 70 E4 A7 30 81  ...._.OT.13p..0.
04F0: 8D 06 03 55 1D 23 04 81   85 30 81 82 80 14 08 A3  ...U.#...0......
0500: 7E 35 96 15 FA B0 F5 1B   5F CD 4F 54 EF 31 33 70  .5......_.OT.13p
0510: E4 A7 A1 67 A4 65 30 63   31 0B 30 09 06 03 55 04  ...g.e0c1.0...U.
0520: 06 13 02 55 53 31 0B 30   09 06 03 55 04 08 13 02  ...US1.0...U....
0530: 43 41 31 14 30 12 06 03   55 04 07 13 0B 53 61 6E  CA1.0...U....San
0540: 74 61 20 43 6C 61 72 61   31 0C 30 0A 06 03 55 04  ta Clara1.0...U.
0550: 0A 13 03 53 75 6E 31 0C   30 0A 06 03 55 04 0B 13  ...Sun1.0...U...
0560: 03 4A 57 53 31 15 30 13   06 03 55 04 03 13 0C 4A  .JWS1.0...U....J
0570: 53 53 45 20 54 65 73 74   20 43 41 82 01 00 30 0C  SSE Test CA...0.
0580: 06 03 55 1D 13 04 05 30   03 01 01 FF 30 0D 06 09  ..U....0....0...
0590: 2A 86 48 86 F7 0D 01 01   04 05 00 03 81 81 00 73  *.H............s
05A0: 6A 46 A2 05 E3 D8 6E 5C   F4 18 A2 74 BC CF EB 0C  jF....n\...t....
05B0: 5B FF 81 1C 28 85 C7 FA   E4 ED 5C 4F 71 22 FB 26  [...(.....\Oq".&
05C0: E3 01 3D 0C 10 AA BB 3E   90 ED 0E 1F 0C 9B B1 8C  ..=....>........
05D0: 49 6A 51 E4 C3 52 D6 FB   42 6C B4 A9 A9 57 A5 84  IjQ..R..Bl...W..
05E0: 00 42 6D 37 37 6D C7 6C   23 BC DC 60 D1 9D 6F B3  .Bm77m.l#..`..o.
05F0: 75 47 3A 15 33 1A EC 90   09 9D F9 EB BD 88 96 E7  uG:.3...........
0600: 1D 41 BC 01 8D CA 88 D9   5B 04 09 8F 3E EA C8 15  .A......[...>...
0610: A0 AA 4E 85 95 AE 2F 0E   31 92 AC 3C FB 2F C4     ..N.../.1..<./.

それから解析を行い、CertificateRequestメッセージを探し出します。

サーバーは、共通名(CN=)「Duke」を持つX509証明書の被認証者により、自身の身元を証明するようクライアントに要求しています。サーバーのX509TrustManagerには、クライアントによって提供される資格、または資格がない場合を拒否するオプションがあります。実際の使用状況では、CAによって署名された証明書を使用することがほとんどであり、代わりに、信頼されるCAのリストがこのメッセージに含まれています。

*** CertificateRequest
Cert Types: RSA, DSS, 
Cert Authorities:
CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
L=Cupertino, ST=CA, C=US>
[read] MD5 and SHA1 hashes:  len = 131
0000: 0D 00 00 7F 02 01 02 00   7A 00 78 30 76 31 0B 30  ........z.x0v1.0
0010: 09 06 03 55 04 06 13 02   55 53 31 0B 30 09 06 03  ...U....US1.0...
0020: 55 04 08 13 02 43 41 31   12 30 10 06 03 55 04 07  U....CA1.0...U..
0030: 13 09 43 75 70 65 72 74   69 6E 6F 31 1F 30 1D 06  ..Cupertino1.0..
0040: 03 55 04 0A 13 16 53 75   6E 20 4D 69 63 72 6F 73  .U....Sun Micros
0050: 79 73 74 65 6D 73 2C 20   49 6E 63 2E 31 16 30 14  ystems, Inc.1.0.
0060: 06 03 55 04 0B 13 0D 4A   61 76 61 20 53 6F 66 74  ..U....Java Soft
0070: 77 61 72 65 31 0D 30 0B   06 03 55 04 03 13 04 44  ware1.0...U....D
0080: 75 6B 65                                           uke
*** ServerHelloDone
[read] MD5 and SHA1 hashes:  len = 4
0000: 0E 00 00 00                                        ....

クライアントのクレデンシャルをサーバーに返信し、クライアントのX509KeyManagerが調べられるようにする必要があります。受け入れられる発行者のリスト(上述)と、KeyStoreに保管された証明書が一致することが期待されます。この場合は(運良く)一致しました。これで、「duke」としてクレデンシャルを有することになります。これらのクレデンシャルが受け入れられるかどうかは、サーバーのX509TrustManagerしだいです。

matching alias: duke
*** Certificate chain
chain [0] = [
[
  Version: V1
  Subject: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
  L=Cupertino, ST=CA, C=US
  Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

  Key:  Sun RSA public key, 1024 bits
  modulus: 134968166047563266914058280571444028986498087544923991226919517
  667593269213420979048109900052353578998293280426361122296881234393722020
  704208851688212064483570055963805034839797994154526862998272017486468599
  962268346037652120279791547218281230795146025359480589335682217749874703
  510467348902637769973696151441
  public exponent: 65537
  Validity: [From: Tue May 22 16:46:46 PDT 2001,
               To: Sun May 22 16:46:46 PDT 2011]
  Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.",
  L=Cupertino, ST=CA, C=US
  SerialNumber: [    3b0afa66]

]
  Algorithm: [MD5withRSA]
  Signature:
0000: 5F B5 62 E9 A0 26 1D 8E   A2 7E 7C 02 08 36 3A 3E  _.b..&.......6:>
0010: C9 C2 45 03 DD F9 BC 06   FC 25 CF 30 92 91 B1 4E  ..E......%.0...N
0020: 62 17 08 48 14 68 80 CF   DD 89 11 EA 92 7F CE DD  b..H.h..........
0030: B4 FD 12 A8 71 C7 9E D7   C3 D0 E3 BD BB DE 20 92  ....q......... .
0040: C2 3B C8 DE CB 25 23 C0   8B B6 92 B9 0B 64 80 63  .;...%#......d.c
0050: D9 09 25 2D 7A CF 0A 31   B6 E9 CA C1 37 93 BC 0D  ..%-z..1....7...
0060: 4E 74 95 4F 58 31 DA AC   DF D8 BD 89 BD AF EC C8  Nt.OX1..........
0070: 2D 18 A2 BC B2 15 4F B7   28 6F D3 00 E1 72 9B 6C  -.....O.(o...r.l

]
***

この符号化方式の場合は、サーバーとクライアントの間で共有する秘密鍵を確立するために使用される、ClientKeyExchangeと呼ばれるメッセージを渡す必要があります。

このデータ全体は最終的に収集され、rawデバイスに書き込まれます。

*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
Random Secret:  { 3, 1, 132, 84, 245, 214, 235, 245, 168, 8, 186, 250,
122, 34, 97, 45, 117, 220, 64, 232, 152, 249, 14, 178, 135, 128, 184,
26, 143, 104, 37, 184, 81, 208, 84, 69, 97, 138, 80, 201, 187, 14, 57,
83, 69, 120, 190, 121 }
[write] MD5 and SHA1 hashes:  len = 754
0000: 0B 00 02 68 00 02 65 00   02 62 30 82 02 5E 30 82  ...h..e..b0..^0.
0010: 01 C7 02 04 3B 0A FA 66   30 0D 06 09 2A 86 48 86  ....;..f0...*.H.
0020: F7 0D 01 01 04 05 00 30   76 31 0B 30 09 06 03 55  .......0v1.0...U
0030: 04 06 13 02 55 53 31 0B   30 09 06 03 55 04 08 13  ....US1.0...U...
0040: 02 43 41 31 12 30 10 06   03 55 04 07 13 09 43 75  .CA1.0...U....Cu
0050: 70 65 72 74 69 6E 6F 31   1F 30 1D 06 03 55 04 0A  pertino1.0...U..
0060: 13 16 53 75 6E 20 4D 69   63 72 6F 73 79 73 74 65  ..Sun Microsyste
0070: 6D 73 2C 20 49 6E 63 2E   31 16 30 14 06 03 55 04  ms, Inc.1.0...U.
0080: 0B 13 0D 4A 61 76 61 20   53 6F 66 74 77 61 72 65  ...Java Software
0090: 31 0D 30 0B 06 03 55 04   03 13 04 44 75 6B 65 30  1.0...U....Duke0
00A0: 1E 17 0D 30 31 30 35 32   32 32 33 34 36 34 36 5A  ...010522234646Z
00B0: 17 0D 31 31 30 35 32 32   32 33 34 36 34 36 5A 30  ..110522234646Z0
00C0: 76 31 0B 30 09 06 03 55   04 06 13 02 55 53 31 0B  v1.0...U....US1.
00D0: 30 09 06 03 55 04 08 13   02 43 41 31 12 30 10 06  0...U....CA1.0..
00E0: 03 55 04 07 13 09 43 75   70 65 72 74 69 6E 6F 31  .U....Cupertino1
00F0: 1F 30 1D 06 03 55 04 0A   13 16 53 75 6E 20 4D 69  .0...U....Sun Mi
0100: 63 72 6F 73 79 73 74 65   6D 73 2C 20 49 6E 63 2E  crosystems, Inc.
0110: 31 16 30 14 06 03 55 04   0B 13 0D 4A 61 76 61 20  1.0...U....Java 
0120: 53 6F 66 74 77 61 72 65   31 0D 30 0B 06 03 55 04  Software1.0...U.
0130: 03 13 04 44 75 6B 65 30   81 9F 30 0D 06 09 2A 86  ...Duke0..0...*.
0140: 48 86 F7 0D 01 01 01 05   00 03 81 8D 00 30 81 89  H............0..
0150: 02 81 81 00 C0 33 77 E7   1F D0 CE CE BD 43 2F 8D  .....3w......C/.
0160: EB C6 D3 07 A9 00 F5 75   4D C8 4B 04 52 42 EE 69  .......uM.K.RB.i
0170: F3 30 E9 A0 C6 07 B7 C8   55 2D B9 5B 57 7A 4C AD  .0......U-.[WzL.
0180: 1A 30 63 5C 7D 6D 16 BF   ED 54 13 49 8A 1B E6 29  .0c\.m...T.I...)
0190: 26 20 85 F9 5E 2B 2F A7   12 9C 98 2D 83 F6 EE B1  &..^+/....-....
01A0: 85 68 DA B5 8E 4C 1D 2D   8E 21 97 B0 30 C8 3A 57  .h...L.-.!..0.:W
01B0: F4 E1 18 9E F6 98 B2 D5   3D 8E D5 2B 09 E2 E1 A0  ........=..+....
01C0: 49 C1 A6 43 CE EA 57 7F   3B 5C 3A C9 BA DB B7 F0  I..C..W.;\:.....
01D0: 89 69 BF 91 02 03 01 00   01 30 0D 06 09 2A 86 48  .i.......0...*.H
01E0: 86 F7 0D 01 01 04 05 00   03 81 81 00 5F B5 62 E9  ............_.b.
01F0: A0 26 1D 8E A2 7E 7C 02   08 36 3A 3E C9 C2 45 03  .&.......6:>..E.
0200: DD F9 BC 06 FC 25 CF 30   92 91 B1 4E 62 17 08 48  .....%.0...Nb..H
0210: 14 68 80 CF DD 89 11 EA   92 7F CE DD B4 FD 12 A8  .h..............
0220: 71 C7 9E D7 C3 D0 E3 BD   BB DE 20 92 C2 3B C8 DE  q......... ..;..
0230: CB 25 23 C0 8B B6 92 B9   0B 64 80 63 D9 09 25 2D  .%#......d.c..%-
0240: 7A CF 0A 31 B6 E9 CA C1   37 93 BC 0D 4E 74 95 4F  z..1....7...Nt.O
0250: 58 31 DA AC DF D8 BD 89   BD AF EC C8 2D 18 A2 BC  X1..........-...
0260: B2 15 4F B7 28 6F D3 00   E1 72 9B 6C 10 00 00 82  ..O.(o...r.l....
0270: 00 80 4E DD E7 77 F1 91   6B 31 4E FA D6 61 D9 69  ..N..w..k1N..a.i
0280: 82 BD 22 40 83 FD 76 E6   FF A7 18 95 A0 04 28 0D  .."@..v.......(.
0290: 0D F7 44 6F 0C 42 4F 17   77 A0 99 56 2A 13 77 28  ..Do.BO.w..V*.w(
02A0: 0B 09 48 C1 B9 8C 09 ED   9F C6 2E 32 18 DB BD ED  ..H........2....
02B0: AF C3 AB E7 AD 8F DF 9E   AB 07 43 B4 50 EF 74 98  ..........C.P.t.
02C0: EA FC E8 4D C9 DA FC B0   B2 C7 D4 83 50 B5 84 B8  ...M........P...
02D0: 44 86 7B 5D 8A C2 F8 04   80 06 E6 84 42 33 B2 EE  D..]........B3..
02E0: 05 E6 D3 48 0E 23 E5 1F   63 4C 53 98 B8 8C 45 BA  ...H.#..cLS...E.
02F0: C8 19                                              ..
main, WRITE: TLSv1 Handshake, length = 754
[Raw write]: length = 759
0000: 16 03 01 02 F2 0B 00 02   68 00 02 65 00 02 62 30  ........h..e..b0
0010: 82 02 5E 30 82 01 C7 02   04 3B 0A FA 66 30 0D 06  ..^0.....;..f0..
0020: 09 2A 86 48 86 F7 0D 01   01 04 05 00 30 76 31 0B  .*.H........0v1.
0030: 30 09 06 03 55 04 06 13   02 55 53 31 0B 30 09 06  0...U....US1.0..
0040: 03 55 04 08 13 02 43 41   31 12 30 10 06 03 55 04  .U....CA1.0...U.
0050: 07 13 09 43 75 70 65 72   74 69 6E 6F 31 1F 30 1D  ...Cupertino1.0.
0060: 06 03 55 04 0A 13 16 53   75 6E 20 4D 69 63 72 6F  ..U....Sun Micro
0070: 73 79 73 74 65 6D 73 2C   20 49 6E 63 2E 31 16 30  systems, Inc.1.0
0080: 14 06 03 55 04 0B 13 0D   4A 61 76 61 20 53 6F 66  ...U....Java Sof
0090: 74 77 61 72 65 31 0D 30   0B 06 03 55 04 03 13 04  tware1.0...U....
00A0: 44 75 6B 65 30 1E 17 0D   30 31 30 35 32 32 32 33  Duke0...01052223
00B0: 34 36 34 36 5A 17 0D 31   31 30 35 32 32 32 33 34  4646Z..110522234
00C0: 36 34 36 5A 30 76 31 0B   30 09 06 03 55 04 06 13  646Z0v1.0...U...
00D0: 02 55 53 31 0B 30 09 06   03 55 04 08 13 02 43 41  .US1.0...U....CA
00E0: 31 12 30 10 06 03 55 04   07 13 09 43 75 70 65 72  1.0...U....Cuper
00F0: 74 69 6E 6F 31 1F 30 1D   06 03 55 04 0A 13 16 53  tino1.0...U....S
0100: 75 6E 20 4D 69 63 72 6F   73 79 73 74 65 6D 73 2C  un Microsystems,
0110: 20 49 6E 63 2E 31 16 30   14 06 03 55 04 0B 13 0D   Inc.1.0...U....
0120: 4A 61 76 61 20 53 6F 66   74 77 61 72 65 31 0D 30  Java Software1.0
0130: 0B 06 03 55 04 03 13 04   44 75 6B 65 30 81 9F 30  ...U....Duke0..0
0140: 0D 06 09 2A 86 48 86 F7   0D 01 01 01 05 00 03 81  ...*.H..........
0150: 8D 00 30 81 89 02 81 81   00 C0 33 77 E7 1F D0 CE  ..0.......3w....
0160: CE BD 43 2F 8D EB C6 D3   07 A9 00 F5 75 4D C8 4B  ..C/........uM.K
0170: 04 52 42 EE 69 F3 30 E9   A0 C6 07 B7 C8 55 2D B9  .RB.i.0......U-.
0180: 5B 57 7A 4C AD 1A 30 63   5C 7D 6D 16 BF ED 54 13  [WzL..0c\.m...T.
0190: 49 8A 1B E6 29 26 20 85   F9 5E 2B 2F A7 12 9C 98  I...)& ..^+/....
01A0: 2D 83 F6 EE B1 85 68 DA   B5 8E 4C 1D 2D 8E 21 97  -.....h...L.-.!.
01B0: B0 30 C8 3A 57 F4 E1 18   9E F6 98 B2 D5 3D 8E D5  .0.:W........=..
01C0: 2B 09 E2 E1 A0 49 C1 A6   43 CE EA 57 7F 3B 5C 3A  +....I..C..W.;\:
01D0: C9 BA DB B7 F0 89 69 BF   91 02 03 01 00 01 30 0D  ......i.......0.
01E0: 06 09 2A 86 48 86 F7 0D   01 01 04 05 00 03 81 81  ..*.H...........
01F0: 00 5F B5 62 E9 A0 26 1D   8E A2 7E 7C 02 08 36 3A  ._.b..&.......6:
0200: 3E C9 C2 45 03 DD F9 BC   06 FC 25 CF 30 92 91 B1  >..E......%.0...
0210: 4E 62 17 08 48 14 68 80   CF DD 89 11 EA 92 7F CE  Nb..H.h.........
0220: DD B4 FD 12 A8 71 C7 9E   D7 C3 D0 E3 BD BB DE 20  .....q......... 
0230: 92 C2 3B C8 DE CB 25 23   C0 8B B6 92 B9 0B 64 80  ..;...%#......d.
0240: 63 D9 09 25 2D 7A CF 0A   31 B6 E9 CA C1 37 93 BC  c..%-z..1....7..
0250: 0D 4E 74 95 4F 58 31 DA   AC DF D8 BD 89 BD AF EC  .Nt.OX1.........
0260: C8 2D 18 A2 BC B2 15 4F   B7 28 6F D3 00 E1 72 9B  .-.....O.(o...r.
0270: 6C 10 00 00 82 00 80 4E   DD E7 77 F1 91 6B 31 4E  l......N..w..k1N
0280: FA D6 61 D9 69 82 BD 22   40 83 FD 76 E6 FF A7 18  ..a.i.."@..v....
0290: 95 A0 04 28 0D 0D F7 44   6F 0C 42 4F 17 77 A0 99  ...(...Do.BO.w..
02A0: 56 2A 13 77 28 0B 09 48   C1 B9 8C 09 ED 9F C6 2E  V*.w(..H........
02B0: 32 18 DB BD ED AF C3 AB   E7 AD 8F DF 9E AB 07 43  2..............C
02C0: B4 50 EF 74 98 EA FC E8   4D C9 DA FC B0 B2 C7 D4  .P.t....M.......
02D0: 83 50 B5 84 B8 44 86 7B   5D 8A C2 F8 04 80 06 E6  .P...D..].......
02E0: 84 42 33 B2 EE 05 E6 D3   48 0E 23 E5 1F 63 4C 53  .B3.....H.#..cLS
02F0: 98 B8 8C 45 BA C8 19                               ...E...

この時点で、実際の秘密鍵を生成するために必要な情報がすべてそろいます。

SESSION KEYGEN:
PreMaster Secret:
0000: 03 01 84 54 F5 D6 EB F5   A8 08 BA FA 7A 22 61 2D  ...T........z"a-
0010: 75 DC 40 E8 98 F9 0E B2   87 80 B8 1A 8F 68 25 B8  u.@..........h%.
0020: 51 D0 54 45 61 8A 50 C9   BB 0E 39 53 45 78 BE 79  Q.TEa.P...9SEx.y
CONNECTION KEYGEN:
Client Nonce:
0000: 40 FC 30 AE 2D 63 84 BB   C5 4B 27 FD 58 21 CA 90  @.0.-c...K'.X!..
0010: 05 F6 A7 7B 37 BB 72 E1   FC 1D 1B 6A F5 1C C8 9F  ....7.r....j....
Server Nonce:
0000: 40 FC 31 10 79 AB 17 66   FA 8B 3F AA FD 5E 48 23  @.1.y..f..?..^H#
0010: FA 90 31 D8 3C B9 A3 2C   8C F5 E9 81 9B A2 63 6C  ..1.<..,......cl
Master Secret:
0000: B0 00 22 34 59 03 16 B7   7A 6C 56 9B 89 D2 7A CC  .."4Y..<.c.
Server MAC write Secret:
0000: 1E 4D D1 D3 0A 78 EE B7   4F EC 15 79 B2 59 18 40  .M...x..O..y.Y.@
Client write key:
0000: 10 D0 D6 C2 D9 B7 62 CB   2C 74 BF 5F 85 3C 6F E7  ......b.,t._.<o.
Server write key:
0000: 06 65 DF BD 16 4B A5 7D   8C 66 2A 80 C1 45 B4 F3  .e...K...f*..E..
... no IV for cipher
>

サーバーに簡単な確認メッセージを送信し、送信したばかりのクライアント証明書に対応する非公開鍵を持っていることを確証します。

*** CertificateVerify
[write] MD5 and SHA1 hashes:  len = 134
0000: 0F 00 00 82 00 80 45 41   43 4B 47 1D F0 EE D1 14  ......EACKG.....
0010: AE F9 B3 2C 1F B9 FE 7B   3E 91 50 C5 0F F1 57 4F  ...,....>.P...WO
0020: 55 F1 4B C3 79 16 A8 F1   72 6B 10 CA CC 83 02 FC  U.K.y...rk......
0030: 97 3D 04 29 44 4C 58 74   84 94 19 63 BB 8A 2C 78  .=.)DLXt...c..,x
0040: 43 A0 DD 5E 54 52 AA 97   15 92 1C 39 6B 10 2E BF  C..^TR.....9k...
0050: F2 DA AE 2D 8F FB 50 44   9E E2 1F 7D C9 C5 CB A0  ...-..PD........
0060: 31 A0 F9 AA 93 2D 1B 07   1B FA E0 EE 95 E7 88 D7  1....-..........
0070: AD 4A 3A 40 DC FB DF 9E   EB 75 04 14 E2 F2 BB DC  .J:@.....u......
0080: 1B 7E 6E D5 8C 62                                  ..n..b
main, WRITE: TLSv1 Handshake, length = 134
[Raw write]: length = 139
0000: 16 03 01 00 86 0F 00 00   82 00 80 45 41 43 4B 47  ...........EACKG
0010: 1D F0 EE D1 14 AE F9 B3   2C 1F B9 FE 7B 3E 91 50  ........,....>.P
0020: C5 0F F1 57 4F 55 F1 4B   C3 79 16 A8 F1 72 6B 10  ...WOU.K.y...rk.
0030: CA CC 83 02 FC 97 3D 04   29 44 4C 58 74 84 94 19  ......=.)DLXt...
0040: 63 BB 8A 2C 78 43 A0 DD   5E 54 52 AA 97 15 92 1C  c..,xC..^TR.....
0050: 39 6B 10 2E BF F2 DA AE   2D 8F FB 50 44 9E E2 1F  9k......-..PD...
0060: 7D C9 C5 CB A0 31 A0 F9   AA 93 2D 1B 07 1B FA E0  .....1....-.....
0070: EE 95 E7 88 D7 AD 4A 3A   40 DC FB DF 9E EB 75 04  ......J:@.....u.
0080: 14 E2 F2 BB DC 1B 7E 6E   D5 8C 62                 .......n..b

大部分が終了しました。新しく確立した符号化方式に変更することをサーバーに知らせます。それ以後のすべてのメッセージは、確立したばかりのパラメータを使用して暗号化されます。暗号化された終了メッセージを送信して、すべての処理が終了したことを確証します。

main, WRITE: TLSv1 Change Cipher Spec, length = 1 
[Raw write]: length = 6
0000: 14 03 01 00 01 01                                  ......
*** Finished
verify_data:  { 242, 98, 66, 170, 124, 124, 204, 231, 73, 15, 237, 172 }
***
[write] MD5 and SHA1 hashes:  len = 16
0000: 14 00 00 0C F2 62 42 AA   7C 7C CC E7 49 0F ED AC  .....bB.....I...
Padded plaintext before ENCRYPTION:  len = 32
0000: 14 00 00 0C F2 62 42 AA   7C 7C CC E7 49 0F ED AC  .....bB.....I...
0010: FA 06 3C 9F 8C 41 1D ED   2B 06 D0 5A ED 31 F2 80  ..<..A..+..Z.1..  
main, WRITE: TLSv1 Handshake, length = 32

上記メッセージが、5バイトのヘッダー情報に続いてraw出力デバイスに実際に書き込まれるときには、メッセージは暗号化されます。

[Raw write]: length = 37
0000: 16 03 01 00 20 15 8C 25   BA 4E 73 F5 27 79 49 B1  .... ..%.Ns.'yI.
0010: E9 F5 7E C8 48 A7 D3 A6   9B BD 6F 8E A5 8E 2B B7  ....H.....o...+.
0020: EE DC BD F4 D7                                     .....

サーバーが同じChange Cipher Spec/Finishedメッセージを送信するのを待ちます。これにより、ネゴシエーションが正常に完了したことがわかります。

[Raw read]: length = 5
0000: 14 03 01 00 01                                     .....
[Raw read]: length = 1
0000: 01                                                 .
main, READ: TLSv1 Change Cipher Spec, length = 1
[Raw read]: length = 5
0000: 16 03 01 00 20                                     .... 
[Raw read]: length = 32
0000: 1F F5 FA C8 79 20 CE 91   AA 68 7F 6C F3 5A DB 7B  ....y ...h.l.Z..
0010: A5 1C 31 1F 6F 41 50 C5   C6 25 25 8D 48 50 3F F1  ..1.oAP..%%.HP?.
main, READ: TLSv1 Handshake, length = 32
Padded plaintext after DECRYPTION:  len = 32
0000: 14 00 00 0C 07 38 46 5F   62 AD 41 B3 DC 79 30 FD  .....8F_b.A..y0.
0010: 34 F2 3B 54 1C D4 68 0E   92 0B 9C 7E ED 47 9F 3B  4.;T..h......G.;
*** Finished
verify_data:  { 7, 56, 70, 95, 98, 173, 65, 179, 220, 121, 48, 253 }
***
[read] MD5 and SHA1 hashes:  len = 16
0000: 14 00 00 0C 07 38 46 5F   62 AD 41 B3 DC 79 30 FD  .....8F_b.A..y0.

すべてが正常に完了しました。この接続が切断されたあと、もう一度このセッションを確立する場合に備えて、確立されたセッションをキャッシュします。

この時点で、SSL/TLSクライアントはピアの資格を調べ、意図するサーバーと通信していることを確認します。HttpsURLConnectionは、問題が生じた場合にホスト名とcall HostnameVerifierをチェックしますが、raw SSLSocketはチェックしません。この検証動作は手動で行いますが、ここでは省略します。

ここまでで、アプリケーション・データを交換する準備が整います。Get /index.html HTTP1.1コマンドを送信します。

%% Cached client session: [Session-1, SSL_RSA_WITH_RC4_128_MD5]
Padded plaintext before ENCRYPTION:  len = 42
0000: 47 45 54 20 2F 69 6E 64   65 78 2E 68 74 6D 6C 20  GET /index.html
0010: 48 54 54 50 2F 31 2E 31   0A 0A CA CB D1 10 9D 0E  HTTP/1.1........
0020: 13 3C D9 66 6B 9E 36 87   ED 9B                    .<.fk.6...
main, WRITE: TLSv1 Application Data, length = 42

送信中のデータは、5バイトのヘッダー情報をスキップして暗号化されています。

[Raw write]: length = 47
0000: 17 03 01 00 2A 8A E9 EC   2C 8D 19 B6 E2 50 C1 E2  ....*...,....P..
0010: 22 1A C0 97 95 23 99 E1   20 DD F3 2A B4 DC 14 57  "....#.. ..*...W
0020: 32 71 58 98 01 BE 70 11   A3 FC 8E 3A 7C 8D BF     2qX...p....:...

アプリケーション・データを取り戻します。最初にHTTPSヘッダー、次に実際のデータが戻されます。

[Raw read]: length = 5
0000: 17 03 01 00 50                                     ....P
[Raw read]: length = 80
0000: 70 10 0D D6 FA ED 51 FC   C2 7E CE 24 2E F1 2F F7  p.....Q....$../.
0010: E7 CD A5 D6 2D 1B 10 FD   48 56 9C 1B B5 EC 8F 1E  ....-...HV......
0020: DB DA F9 83 62 52 15 38   70 4B C1 85 13 EF CA 17  ....bR.8pK......
0030: 89 37 D3 45 C0 88 BB 92   63 F6 9C DE 69 E6 60 3E  .7.E....c...i.`>
0040: 1F F7 4D C1 56 61 79 01   49 55 FB 38 6B 16 81 BC  ..M.Vay.IU.8k...
main, READ: TLSv1 Application Data, length = 80
Padded plaintext after DECRYPTION:  len = 80
0000: 48 54 54 50 2F 31 2E 30   20 32 30 30 20 4F 4B 0D  HTTP/1.0 200 OK.
0010: 0A 43 6F 6E 74 65 6E 74   2D 4C 65 6E 67 74 68 3A  .Content-Length:
0020: 20 35 38 0D 0A 43 6F 6E   74 65 6E 74 2D 54 79 70   58..Content-Typ
0030: 65 3A 20 74 65 78 74 2F   68 74 6D 6C 0D 0A 0D 0A  e: text/html....
0040: 40 18 A1 FF 1D 5A D4 55   98 DB E3 95 01 A0 91 AF  @....Z.U........
HTTP/1.0 200 OK
Content-Length: 58
Content-Type: text/html 
[Raw read]: length = 5
0000: 17 03 01 00 4A                                     ....J
[Raw read]: length = 74
0000: 75 DA F2 58 C3 5E 58 DE   14 AD FE 71 A3 78 07 58  u..X.^X....q.x.X
0010: EB E9 2B A2 D7 82 5C 6E   C9 9C 58 84 D7 A8 C6 F8  ..+...\n..X.....
0020: DE C6 5B BA 10 59 DF CC   11 AE 35 F7 C7 0F F6 C2  ..[..Y....5.....
0030: 3E 67 4E 95 30 AA 91 0B   E4 4F 5C C7 BF 50 AC 61  >gN.0....O\..P.a
0040: 87 B7 80 75 F0 81 F1 00   63 C9                    ...u....c.
main, READ: TLSv1 Application Data, length = 74
Padded plaintext after DECRYPTION:  len = 74
0000: 3C 48 54 4D 4C 3E 0A 3C   48 31 3E 48 65 6C 6C 6F  <HTML>.<H1>Hello
0010: 20 57 6F 72 6C 64 3C 2F   48 31 3E 0A 54 68 65 20   World</H1>.The 
0020: 74 65 73 74 20 69 73 20   63 6F 6D 70 6C 65 74 65  test is complete
0030: 21 0A 3C 2F 48 54 4D 4C   3E 0A 38 2E 68 72 F1 47  !.</HTML>.8.hr.G
0040: E8 56 D1 EA A6 FC 3C 30   6F F3                    .V....<0o.
 <HTML>
<H1>Hello World<H1>
The test is complete!
<HTML>

ソケットからもう一度読み出し、さらにデータがあるかどうかを確認します。close_notifyメッセージを受け取ります。このメッセージは、この接続が正常に切断されることを意味します。応答メッセージを返し、ソケットを閉じます。

[Raw read]: length = 5
0000: 15 03 01 00 12                                     .....
[Raw read]: length = 18
0000: 09 AB 95 00 43 8D C8 7C   83 18 EB C4 8C 99 43 A6  ....C.........C.
0010: 76 49                                              vI
main, READ: TLSv1 Alert, length = 18
Padded plaintext after DECRYPTION:  len = 18
0000: 01 00 FA 44 D5 57 71 5C   CC C7 D9 D0 04 23 10 D8  ...D.Wq\.....#..
0010: 21 7B                                              !.
main, RECV TLSv1 ALERT:  warning, close_notify
main, called closeInternal(false)
main, SEND TLSv1 ALERT:  warning, description = close_notify
Padded plaintext before ENCRYPTION:  len = 18
0000: 01 00 8A 2C A2 36 9C 88   22 50 6E BC 95 3B B2 C4  ...,.6.."Pn..;..
0010: FE F2                                              ..
main, WRITE: TLSv1 Alert, length = 18
[Raw write]: length = 23
0000: 15 03 01 00 12 19 BE 10   8D FA F1 CA DD AB CC 91  ................
0010: 2E 49 08 71 2B C1 05                               .I.q+..
main, called close()
main, called closeInternal(true)
main, called close()
main, called closeInternal(true)
main, called close()
main, called closeInternal(true)

コード例

このセクションには次のコード例が含まれています。

セキュアでないソケットからセキュアなソケットへの変換

JSSEを使用してセキュアでないソケット接続をセキュアなソケット接続に変換する方法を示すコード例です。このコード例は、『Java SE 6ネットワーク・セキュリティ』(Marco Pistoia他著)から引用したものです。

例8-26では、セキュアでないソケットを使用してクライアントとサーバーとの間の通信を設定するために使用できるサンプル・コードを示します。次に例8-27ではこのコードを変更し、JSSEを使用してセキュアなソケット通信を設定します。

例8-26 SSLを使用しないソケットの例

次の例では、セキュアでないソケット接続を設定するサーバー側およびクライアント側のコードを示します。

サーバーとして動作し、ソケットを使用してクライアントと通信するJavaプログラムでは、次のようなコードでソケット通信を設定します。

    import java.io.*;
    import java.net.*;
    
    . . .
    
    int port = availablePortNumber;
    
    ServerSocket s;
    
    try {
        s = new ServerSocket(port);
        Socket c = s.accept();
    
        OutputStream out = c.getOutputStream();
        InputStream in = c.getInputStream();
    
        // Send messages to the client through
        // the OutputStream
        // Receive messages from the client
        // through the InputStream
    } catch (IOException e) { }

ソケットを使ってサーバーとの通信を設定するクライアント・コードの例を、次に示します。

    import java.io.*;
    import java.net.*;
    
    . . .
    
    int port = availablePortNumber;
    String host = "hostname";
    
    try {
        s = new Socket(host, port);
    
        OutputStream out = s.getOutputStream();
        InputStream in = s.getInputStream();
    
        // Send messages to the server through
        // the OutputStream
        // Receive messages from the server
        // through the InputStream
    } catch (IOException e) { }

例8-27 SSLを使用するソケットの例

次の例では、セキュアなソケット接続を設定するサーバー側およびクライアント側のコードを示します。

サーバーとして動作し、セキュアなソケットを使用してクライアントと通信するJavaプログラムでは、次のようなコードでソケット通信を設定します。セキュアでないソケットを使った通信のプログラムとこのプログラムとの違いは、太字で示されています。

    import java.io.*;
    import javax.net.ssl.*;
    
    . . .
    
    int port = availablePortNumber;
    
    SSLServerSocket s;
    
    try {
        SSLServerSocketFactory sslSrvFact =
            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
        s = (SSLServerSocket)sslSrvFact.createServerSocket(port);
    
        SSLSocket c = (SSLSocket)s.accept();
    
        OutputStream out = c.getOutputStream();
        InputStream in = c.getInputStream();
    
        // Send messages to the client through
        // the OutputStream
        // Receive messages from the client
        // through the InputStream
    }
    
    catch (IOException e) {
    }

セキュアなソケットを使ってサーバーとの通信を設定するクライアント・コードの例を、次に示します。セキュアでないソケットとの違いは、太字で示されています。

    import java.io.*;
    import javax.net.ssl.*;
    
    . . .
    
    int port = availablePortNumber;
    String host = "hostname";
    
    try {
        SSLSocketFactory sslFact =
            (SSLSocketFactory)SSLSocketFactory.getDefault();
        SSLSocket s = (SSLSocket)sslFact.createSocket(host, port);
    
        OutputStream out = s.getOutputStream();
        InputStream in = s.getInputStream();
    
        // Send messages to the server through
        // the OutputStream
        // Receive messages from the server
        // through the InputStream
    }
    
    catch (IOException e) {
    }

JSSEサンプル・コードの実行

JSSEサンプル・プログラムでは、JSSEの使用方法を示します。

サンプル・コードを使用する場合、サンプル・プログラムはJSSEの使用法を示すために設計されていることに注意してください。堅牢なアプリケーションを開発するためのものではありません。

注意:

セキュアな通信を設定すると、アルゴリズムが複雑になります。サンプル・プログラムでは、設定プロセス中のフィードバックがありません。プログラムの実行時は、少し待ってください。しばらく出力が表示されない場合があります。javax.net.debugシステム・プロパティをallに設定して、プログラムを実行すると、フィードバックが表示されます。このデバッグ情報の見方の説明は、ガイド「SSL/TLS接続のデバッグ」を参照してください。

サンプル・コードの場所

JDK 8ドキュメント内のJSSEサンプル・コードではすべてのサンプル・コード・ファイルとテキスト・ファイルをリストします。そのページには、すべてのサンプル・コード・ファイルをダウンロードできるZIPファイルへのリンクも記載されています。

次のセクションでは、サンプルについて説明します。JDK 8ドキュメント内のJSSEサンプル・コードREADME.txtを参照してください。

クライアントとサーバーのセキュアなソケット接続を表すサンプル・コード

samples/socketsディレクトリにあるサンプル・プログラムは、クライアントとサーバーとの間でセキュアなソケット接続を設定する方法を示しています。

サンプルのクライアント・プログラムを実行中に、Webサーバーなどの既存のサーバーと通信できます。または、サンプル・サーバー・プログラムClassFileServerと通信することもできます。サンプルのクライアント・プログラムとサーバー・プログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウから両方を実行することもできます。

amples/sockets/clientディレクトリのサンプルSSLSocketClient*プログラム(および「HTTPS接続を表すサンプル・コード」で説明するURLReader*プログラム)は、すべてClassFileServerサンプル・サーバー・プログラムで実行できます。これを実行する方法の例は、「ClassFileServerを使用したSSLSocketClientWithClientAuthの実行」に示しています。同様の変更をして、URLReaderSSLSocketClientまたはSSLSocketClientWithTunnelingClassFileServerで実行できます。

クライアントとサーバーとの間で通信中に認証エラーが発生する場合(WebサーバーとClassFileServerのどちらを使用しているか関係なく)、必要な鍵がトラストストア(トラスト鍵データベース)にないためである可能性があります。用語と定義を参照してください。たとえば、ClassFileServerは、SSLハンドシェーク中に必要なlocalhostの公開鍵を格納するtestkeysというキーストアを使用します。testkeysキーストアはClassFileServerソースと同じsamples/sockets/serverディレクトリにあります。参照するトラストストアで、localhostの対応する公開鍵の証明書をクライアントが見つけられない場合、認証エラーが発生します。次のセクションで説明するように、samplecacertsトラストストア(localhostの公開鍵と証明書を格納する)を使用してください。

構成要件

クライアントとサーバーとの間のセキュアなソケット接続を作成するサンプル・プログラムを実行する場合は、適切な証明書ファイル(トラストストア)を利用できるようにしておく必要があります。クライアント・プログラムとサーバー・プログラムの両方で、samplesディレクトリのsamplecacerts証明書ファイルを使用してください。この証明書ファイルを使用すると、クライアントがサーバーを認証できるようになります。このファイルには、JDK (cacertsファイルにある)に付属する一般的な証明書発行局(CA)のすべての証明書と、サンプルサーバーClassFileServerとの通信時にクライアントがlocalhostを認証するために必要なlocalhostの証明書が含まれています。ClassFileServerは、samplecacertsの公開鍵に対応するlocalhostの公開鍵を含むキーストアを使用します。

クライアントとサーバーの両方でsamplecacertsファイルを使用できるようにするには、それをjava-home/lib/security/jssecacertsファイルにコピーして名前をcacertsに変更し、java-home/lib/security/cacertsファイルと置き換えます。あるいは、クライアントとサーバーの両方に対してjavaコマンドを実行する場合は、次のオプションをコマンド行に追加します。

-Djavax.net.ssl.trustStore=path_to_samplecacerts_file

java-homeの詳細は、用語と定義を参照してください。

samplecacertsトラスト・ストアのパスワードはchangeitです。keytoolユーティリティを使用して、サンプルの独自の証明書を置き換えることができます。

Mozilla FirefoxやMicrosoft Internet Explorerなどのブラウザを使用して、ClassFileServerの例で提供されているサンプルのSSLサーバーにアクセスすると、ダイアログ・ボックスが開いて、証明書が認識されないというメッセージが表示されます。これは、サンプル・プログラムで使用する証明書は自己署名付きのもので、テスト用にすぎないためです。現在のセッションで証明書に同意できます。SSLサーバーのテストが終了したあと、ブラウザを終了し、ブラウザの名前空間からテスト用証明書を削除します。

クライアント認証の場合、適切なディレクトリの別のduke証明書を使用できます。公開鍵および証明書も、samplecacertsファイルに格納されています。

SSLSocketClientの実行

JDK 8ドキュメント内のJSSEサンプル・コードSSLSocketClient.javaプログラムは、SSLSocketを使用してHTTP要求を送信しHTTPSサーバーから応答を受け取るクライアントの作成方法を示します。このプログラムの出力は、https://www.verisign.com/index.htmlのHTMLソースです。

ファイアウォールの内側から、このプログラムを提供されたとおりに実行しないでください。ファイアウォールの内側から実行すると、JSSEはファイアウォールを経由したwww.verisign.comへのパスを検出できないので、UnknownHostExceptionを受け取ります。ファイアウォールの外側から実行できる同等のクライアントを作成するには、サンプル・プログラムSSLSocketClientWithTunnelingで示すように、プロキシ・トンネリングを設定します。

SSLSocketClientWithTunnelingの実行

JDK 8ドキュメント内のJSSEサンプル・コードSSLSocketClientWithTunneling.javaプログラムは、ファイアウォールの外側からセキュアなWebサーバーにアクセスするプロキシ・トンネリングの方法を示します。このプログラムを実行するには、次のJavaシステム・プロパティに適切な値を設定する必要があります。

java -Dhttps.proxyHost=webproxy
-Dhttps.proxyPort=ProxyPortNumber
SSLSocketClientWithTunneling

注意:

-Dオプションによるプロキシ指定はオプションです。webproxyは使用するプロキシ・ホスト名に、ProxyPortNumberは適切なポート番号に置き換えてください。

プログラムはhttps://www.verisign.com/index.htmlのHTMLソース・ファイルを返します。

SSLSocketClientWithClientAuthの実行

JDK 8ドキュメント内のJSSEサンプル・コードSSLSocketClientWithClientAuth.javaプログラムは、サーバーから要求された場合にクライアント認証を行うように、キー・マネージャを設定する方法を示します。このプログラムも、クライアントがファイアウォールの外側にはいないことを前提にしています。SSLSocketClientWithTunnelingの例に従ってプログラムを変更すれば、ファイアウォールの内側から接続することもできます。

このプログラムを実行するには、ホスト、ポート、および要求されたファイル・パスの3つのパラメータを指定する必要があります。前の例を反映させるには、ホストにwww.verisign.com、ポート番号に443、要求されたファイル・パスにhttps://www.verisign.com/を設定することで、このプログラムをクライアント認証なしで実行します。これらのパラメータを使用したときの出力が、Webサイトhttps://www.verisign.com/のHTMLソースです。

SSLSocketClientWithClientAuthを実行してクライアント認証を行うには、クライアント認証を要求するサーバーにアクセスする必要があります。このサーバーには、サンプル・プログラムClassFileServerを使用できます。これについては、次のセクションで説明します。

ClassFileServerの実行

ここでClassFileServerと呼ばれるプログラムは、JDK 8ドキュメント内のJSSEサンプル・コードClassFileServer.javaClassServer.javaという2つのファイルで構成されています。

これらを実行するには、ClassFileServer.classを実行します。その際は次のパラメータが必要です。

  • portは、利用できる未使用のポート番号です。たとえば、2001のような数字を使用できます。
  • docrootは、取得するファイルを含むサーバーのディレクトリを表します。たとえば、Solarisでは、/home/userid/ (useridは特定のUIDを表す)を使用でき、Microsoft Windowsシステムではc:\を使用できます。
  • TLSは、サーバーがSSLを使用するかTLSを使用するかを示すオプションのパラメータです。
  • trueは、クライアント認証が必要であることを示すオプションのパラメータです。このパラメータは、TLSパラメータが設定されているかどうかだけを参照します。

注意:

TLSパラメータとtrueパラメータはオプションです。それらを省略した場合は、TLSではない通常のファイルサーバーを認証なしで使用し、何も起こらないことを示します。これは、一方の側(クライアント)がTLSとネゴシエーションを行おうとしても、もう一方の側(サーバー)は行おうとしないため、通信ができないからです。

注意:

サーバーは、GET /path_to_fileの形式でのGET要求を予期しています。

ClassFileServerによるSSLSocketClientWithClientAuthの実行

JDK 8ドキュメント内のJSSEサンプル・コードのサンプル・プログラムSSLSocketClientWithClientAuth.javaおよびClassFileServerを使用して、認証済の通信を設定できます。この通信では、クライアントとサーバーが相互に認証します。サンプルのプログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウまたはコマンド・プロンプト・ウィンドウから両方を実行することもできます。クライアントとサーバーの両方を設定するには、次を実行します。

  1. ClassFileServerプログラムを1つのマシンまたはターミナル・ウィンドウから実行します。

    ClassFileServerの実行を参照してください。

  2. SSLSocketClientWithClientAuthプログラムを別のマシンやターミナル・ウィンドウで実行します。SSLSocketClientWithClientAuthには、次のパラメータが必要です。
    • hostは、ClassFileServerを実行するために使用するマシンのホスト名です。
    • portは、ClassFileServer用に指定したものと同じポートです。
    • requestedfilepathは、サーバーから取得するファイルのパスを示します。このパラメータには、/filepathと指定する必要があります。GET文の一部として使用されるので、ファイル・パスにはフォワード・スラッシュが必要です。GET文には、稼動中のオペレーティング・システムの種類にかかわらず、フォワード・スラッシュが必要です。文の構成は次のようになります。

      "GET " + requestedfilepath + " HTTP/1.0"
      

注意:

ClassFileServerが動作しているローカル・マシンに接続するように、他のSSLClient*アプリケーションのGETコマンドを変更できます。

HTTPS接続を表すサンプル・コード

JSSEを介してセキュアな通信にアクセスするためのプライマリAPIは2つあります。1つの方法は、SSLSocketClientSSLSocketClientWithTunnelingおよびSSLSocketClientWithClientAuth (ClassFileServerを使用するか使用しないで)に示すように、任意のセキュアな通信に使用できるソケット・レベルのAPIを使用することです。

2つ目はもっと簡単な方法で、標準のJava URL APIを使用します。java.net.URLクラスを使用したHTTPS URLプロトコルまたはスキームを使用して、SSL対応のWebサーバーとセキュアに通信できます。

HTTPS URLスキームのサポートは一般的なブラウザの多くに実装されており、JSSEで提供されているソケット・レベルAPIを必要とせずにセキュアな通信にアクセスできます。

URLの例はhttps://www.verisign.comです。

HTTPS URL実装のトラストおよび鍵の管理は、環境に固有です。JSSE実装は、HTTPS URL実装を提供します。別のHTTPSプロトコル実装を使用するには、java.protocol.handler.pkgsを設定します。パッケージ名に対するjava.lang.Systemプロパティの指定方法を参照してください。詳細については、java.net.URLクラスのドキュメントを参照してください。

JSSEでダウンロードできるサンプルには、HTTPS接続の作成方法を示すサンプル・プログラムが2つ含まれています。これらのサンプル・プログラム(URLReader.javaURLReaderWithOptions.java)は、どちらもsamples/urlsディレクトリにあります。

URLReaderの実行

JDK 8ドキュメント内のJSSEサンプル・コードURLReader.javaプログラムは、セキュアなサイトにアクセスするURLクラスの使用方法を示します。このプログラムの出力は、https://www.verisign.com/のHTMLソースです。デフォルトで、JSSEに付属のHTTPSプロトコル実装が使用されます。別の実装を使用するには、システム・プロパティjava.protocol.handler.pkgsの値を、実装を含むパッケージ名に設定します。

ファイアウォールの内側でサンプル・コードを実行している場合は、https.proxyHostおよびhttps.proxyPortシステム・プロパティを設定する必要があります。たとえば、ポート8080でプロキシ・ホスト「webproxy」を使用する場合は、javaコマンドで次のオプションを使用できます。

-Dhttps.proxyHost=webproxy
-Dhttps.proxyPort=8080

または、java.lang.SystemのメソッドsetProperty()で、ソース・コード内のシステム・プロパティを設定することもできます。たとえば、コマンド行オプションを使用するかわりに、使用するプログラムに次の行を含めることができます。

System.setProperty("java.protocol.handler.pkgs", "com.ABC.myhttpsprotocol");
System.setProperty("https.proxyHost", "webproxy");
System.setProperty("https.proxyPort", "8080");

URLReaderWithOptionsの実行

JDK 8ドキュメント内のJSSEサンプル・コードURLReaderWithOptions.javaプログラムは、基本的にはURLReader.javaプログラムと同じですが、実行時にプログラムの引数として次のシステム・プロパティのどれかまたはすべてをオプションで入力できる点が異なります。

  • java.protocol.handler.pkgs
  • https.proxyHost
  • https.proxyPort
  • https.cipherSuites

URLReaderWithOptionsを実行するには、次のコマンドを入力します。

java URLReaderWithOptions [-h proxyhost -p proxyport] [-k protocolhandlerpkgs] [-c ciphersarray]

注意:

複数のプロトコル・ハンドラを、縦線で区切った項目のリストでprotocolhandlerpkgs引数に含めることができます。複数のSSL暗号化方式群名を、カンマで区切った項目のリストでciphersarray引数に含めることができます。可能な暗号化方式群名はSSLSocket.getSupportedCipherSuites()メソッドで返されるものと同じです。暗号群はSSLおよびTLSプロトコルの仕様から命名されています。

protocolhandlerpkgs引数は、Oracleが提供するデフォルト以外のHTTPSプロトコル・ハンドラ実装を使用する場合にのみ必要です。

ファイアウォールの内側でサンプル・コード実行している場合は、プロキシ・ホストおよびプロキシ・ポートの引数を含める必要があります。また、使用できる暗号群のリストを含めることもできます。

次に、URLReaderWithOptionsの実行例と、ポート8080にプロキシ・ポート「webproxy」を指定する場合の例を示します。

java URLReaderWithOptions -h webproxy -p 8080

セキュアなRMI接続を表すサンプル・コード

samples/rmiディレクトリ内のサンプル・コードは、セキュアなJava Remote Method Invocation (RMI)接続の作成方法を示しています。このサンプル・コードは、基本的には、カスタムRMIソケット・ファクトリをインストールして使用するように変更されたHello Worldサンプルです。

SSLEngineの使用を表すサンプル・コード

SSLEngineは、アプリケーション開発者にI/Oおよび計算戦略を選択するときの柔軟性を提供します。SSLEngineは、SSL/TLS実装を特定のI/O抽象化(シングル・スレッドSSLSocketsなど)に結びつけるのではなく、I/Oおよび計算の制約をSSL/TLS実装から除外します。

前述したように、SSLEngineは高度なAPIであり、不用意に使用することはできません。ここでは、その使用を説明するのに役立つ入門用サンプル・コードを示します。最初のデモは、ほとんどのI/Oおよびスレッドの発行を除外し、SSLEngineメソッドの多くに重点を置きます。2番目のデモは、より現実的な例であり、SSLEngineがどのようにJava NIOと結合して基本的なHTTP/HTTPSサーバーを作成するかを示します。

SSLEngineSimpleDemoの実行

JDK 8ドキュメント内のJSSEサンプル・コードSSLEngineSimpleDemo.javaプログラムは、入出力とスレッドの問題が簡素化されている、SSLEngineの操作に重点を置いた非常に単純なアプリケーションです。このアプリケーションは、一般的なByteBufferオブジェクトによってSSL/TLSメッセージを交換する2つのSSLEngineオブジェクトを作成します。1つのループがすべてのエンジン操作を順番に実行して、セキュアな接続の確立(ハンドシェーク)、アプリケーション・データの転送、およびエンジンのクローズを示します。

SSLEngineResultは、SSLEngineの現在の状態に関して多くの情報を提供します。この例では、すべての状態を調べているわけではありません。I/Oおよびスレッドの発行を適度に単純化しているため本番稼動環境に適した例ではありませんが、SSLEngineの全体的な機能の説明に有用です。

NIOベースのサーバーの実行

SSLEngineによって提供される柔軟性を十分に利用するには、最初にI/Oやスレッド・モデルなどの相補的なAPIを理解する必要があります。

大規模なアプリケーションの開発者が有用と考えるI/Oモデルは、NIO SocketChannelです。NIOは、java.net.Socket APIに内在するスケーリングの問題のいくつかを解決するために部分的に導入されました。SocketChannelには、次のような様々な操作モードがあります。

  • ブロック
  • 非ブロック
  • セレクタによる非ブロック

新しい多くのNIO APIを示すだけでなく、セキュアなHTTPSサーバーを作成するためにSSLEngineを採用する方法も示す、基本的なHTTPサーバーのサンプル・コードが提供されています。サーバーは本番稼動の品質ではありませんが、これらの多くの新しいAPIの動作を示しています。

サンプル・ディレクトリには、サーバーを紹介するREADME.txtファイルがあり、これには、サーバーの構築および構成方法の説明、コード・レイアウトの簡潔な概要が含まれています。SSLEngineのユーザーにとってもっとも重要なファイルは、ChannelIO.javaおよびChannelIOSecure.javaです。

注意:

この項で説明するサーバー例は、JDKに含まれています。コードは、jdk-home/samples/nio/serverディレクトリにバンドルされています。

JSSEで使用するキーストアの作成

keytoolユーティリティを使用してJSSEでの使用に適した単純なPKCS12キーストアを作成する方法の手順を示します。

まずキーストア内に(公開鍵および秘密鍵を持つ) keyEntryを作成し、トラストストア内に対応するtrustedCertEntry (公開鍵のみ)を作成します。クライアント認証の場合、クライアントの証明書に対して同様の処理に従う必要があります。

注意:

PKCS12での信頼できるアンカーおよび秘密鍵の格納は、JDK 8以降でサポートされています。

注意:

ここでは、各ステップに関する詳しい解説は省略します。keytoolを参照してください。

ユーザー入力は太字で表示されます。

  1. 対応する公開鍵および秘密鍵によって、新しいキーストアと自己署名付き証明書を作成します。

        % keytool -genkeypair -alias duke -keyalg RSA -validity 7 -keystore keystore 
        
        Enter keystore password:  <password>
        What is your first and last name?
        [Unknown]:  Duke
        What is the name of your organizational unit?
        [Unknown]:  Java Software
        What is the name of your organization?
        [Unknown]:  Oracle, Inc.
        What is the name of your City or Locality?
        [Unknown]:  Palo Alto
        What is the name of your State or Province?
        [Unknown]:  CA
        What is the two-letter country code for this unit?
        [Unknown]:  US
        Is CN=Duke, OU=Java Software, O="Oracle, Inc.",
        L=Palo Alto, ST=CA, C=US correct?
        [no]:  yes
    
  2. キーストアを調べます。エントリの型はPrivatekeyEntryで、これは、このエントリに秘密鍵が関連付けられていることを示します。

        % keytool -list -v -keystore keystore
        
        Enter keystore password:  <password>
        
        Keystore type: PKCS12
        Keystore provider: SUN
    
        Your keystore contains 1 entry
    
        Alias name: duke
        Creation date: Jul 25, 2016
        Entry type: PrivateKeyEntry
        Certificate chain length: 1
        Certificate[1]:
        Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Serial number: 210cccfc
        Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016
        Certificate fingerprints:
             SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F
             SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2:
        4B:9D:80:31:67:8A:D4:B4:7A:B5:12
        Signature algorithm name: SHA256withRSA
        Subject Public Key Algorithm: RSA (2048)
        Version: 3
    
        Extensions:
    
       #1: ObjectId: 2.5.29.14 Criticality=false
       SubjectKeyIdentifier [
       KeyIdentifier [
       0000: 7F C9 95 48 42 8D 68 91   BA 1E E6 5C 2C 6B FF 75  ...HB.h....\,k.u
       0010: 5F 19 78 43                                        _.xC
       ]
       ]
  3. 自己署名付き証明書をエクスポートし、内容を調べます。

        % keytool -export -alias duke -keystore keystore -rfc -file duke.cer
        Enter keystore password:  <password>
        Certificate stored in file <duke.cer>
        % cat duke.cer
        -----BEGIN CERTIFICATE-----
        MIIDdzCCAl+gAwIBAgIEIQzM/DANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJV
        UzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEVMBMGA1UEChMMT3Jh
        Y2xlLCBJbmMuMRYwFAYDVQQLEw1KYXZhIFNvZnR3YXJlMQ0wCwYDVQQDEwREdWtl
        MB4XDTE2MDcyNTA1MDMyN1oXDTE2MDgwMTA1MDMyN1owbDELMAkGA1UEBhMCVVMx
        CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8xFTATBgNVBAoTDE9yYWNs
        ZSwgSW5jLjEWMBQGA1UECxMNSmF2YSBTb2Z0d2FyZTENMAsGA1UEAxMERHVrZTCC
        ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ7+Yeu6HDZgWwkGlG4iKH9w
        vGKrxXVR57FaFyheMevrgj1ovVnQVFhfdMvjPkjWmpqLg6rfTqU4bKbtoMWV6+Rn
        uQrCw2w9xNC93hX9PxRa20UKrSRDKnUSvi1wjlaxfj0KUKuMwbbY9S8x/naYGeTL
        lwbHiiMvkoFkP2kzhVgeqHjIwSz4HRN8vWHCwgIDFWX/ZlS+LbvB4TSZkS0ZcQUV
        vJWTocOd8RB90W3bkibWkWq166XYGE1Nq1L4WIhrVJwbav6ual69yJsEpVcshVkx
        E1WKzJg7dGb03to4agbReb6+aoCUwb2vNUudNWasSrxoEFArVFGD/ZkPT0esfqEC
        AwEAAaMhMB8wHQYDVR0OBBYEFH/JlUhCjWiRuh7mXCxr/3VfGXhDMA0GCSqGSIb3
        DQEBCwUAA4IBAQAmcTm2ahsIJLayajsvm8yPzQsHA7kIwWfPPHCoHmNbynG67oHB
        fleaNvrgm/raTT3TrqQkg0525qI6Cqaoyy8JA2fAp3i+hmyoGHaIlo14bKazaiPS
        RCCqk0J8vwY3CY9nVal1XlHJMEcYV7X1sxKbuAKFoAJ29E/p6ie0JdHtQe31M7X9
        FNLYzt8EpJYUtWo13B9Oufz/Guuex9PQ7aC93rbO32MxtnnCGMxQHlaHLLPygc/x
        cffGz5Xe5s+NEm78CY7thgN+drI7icBYmv4navsnr2OQaD3AfnJ4WYSQyyUUCPxN
        zuk+B0fbLn7PCCcQspmqfgzIpgbEM9M1/yav
        -----END CERTIFICATE-----    
    

    また、-certreqによって証明書署名要求(CSR)を生成し、証明書発行局(CA)に送付して署名を求めることもできますが、それはこの例の範囲を超えています。

  4. 証明書を新しいトラスト・ストアにインポートします。

        % keytool -import -alias dukecert -file duke.cer -keystore truststore
        Enter keystore password:  <password>
        Re-enter new password:
        Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Serial number: 210cccfc
        Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016
        Certificate fingerprints:
             SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F
             SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2:
        4B:9D:80:31:67:8A:D4:B4:7A:B5:12
        Signature algorithm name: SHA256withRSA
        Subject Public Key Algorithm: RSA (2048)
        Version: 3
    
        Extensions:
    
        #1: ObjectId: 2.5.29.14 Criticality=false
        SubjectKeyIdentifier [
        KeyIdentifier [
        0000: 7F C9 95 48 42 8D 68 91   BA 1E E6 5C 2C 6B FF 75  ...HB.h....\,k.u
        0010: 5F 19 78 43                                        _.xC
        ]
        ]
    
        Trust this certificate? [no]:  yes
        Certificate was added to keystore
    
        
    
  5. トラストストアを調べます。エントリの型はtrustedCertEntryで、これは、秘密鍵をこのエントリで使用できないことを示します。これは、このファイルがKeyManagerのキーストアとして適切でないことも意味します。

        % keytool -list -v -keystore truststore
        Enter keystore password:  <password>
        
        Keystore type: PKCS12
        Keystore provider: SUN
        
        Your keystore contains 1 entry
    
        Alias name: dukecert
        Creation date: Jul 25, 2016
        Entry type: trustedCertEntry
    
        Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US
        Serial number: 210cccfc
        Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016
        Certificate fingerprints:
             SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F
             SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2:
        4B:9D:80:31:67:8A:D4:B4:7A:B5:12
        Signature algorithm name: SHA256withRSA
        Subject Public Key Algorithm: RSA (2048)
        Version: 3
    
        Extensions:
    
        #1: ObjectId: 2.5.29.14 Criticality=false
        SubjectKeyIdentifier [
        KeyIdentifier [
        0000: 7F C9 95 48 42 8D 68 91   BA 1E E6 5C 2C 6B FF 75  ...HB.h....\,k.u
        0010: 5F 19 78 43                                        _.xC
        ]
        ]
    
    
    
        *******************************************
        *******************************************
    
  6. ここで、適切なキーストアを使用してアプリケーションを実行します。この例では、デフォルトのX509KeyManagerおよびX509TrustManagerを使用することを前提とするため、「JSSEのカスタマイズ」で説明したシステム・プロパティを使用してキーストアを選択します。

        % java -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password Server
        
        % java -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword Client
        
    

注意:

この例で認証されるのは、サーバーのみです。クライアントの認証の場合、クライアントの鍵に対して同様のキーストアを用意し、サーバーに対して適切なトラストストアを提供する必要があります。

Server Name Indication (SNI)拡張の使用

これらの例では、クライアント側アプリケーションとサーバー側アプリケーションでServer Name Indication (SNI)拡張を使用する方法およびそれを仮想インフラストラクチャに適用する方法を示します。

このセクションのすべての例で、パラメータの設定後にそれらを適用するには、対応するSSLSocketSSLEngineまたはSSLServerSocketオブジェクトで、setSSLParameters(SSLParameters)メソッドを呼び出します。

一般的なクライアント側使用例

次は、クライアント・アプリケーションを開発するためにSNI拡張の理解を必要とするユース・ケースのリストです。

  • ケース1.クライアントはwww.example.comにアクセスする必要があります。

    ホスト名を明示的に設定します。

        SNIHostName serverName = new SNIHostName("www.example.com");
        sslParameters.setServerNames(Collections.singletonList(serverName)); 

    クライアントは常にホスト名を明示的に指定してください。

  • ケース2.サーバーでサポートしていないため、クライアントはSNIを使用する必要はありません。

    空のサーバー名リストでSNIを無効にします。

        sslParameters.setServerNames(Collections.emptyList());        
    
  • ケース3.クライアントはURL https://www.example.comにアクセスする必要があります。

    OracleプロバイダはデフォルトでSNI拡張にホスト名を設定しますが、サード・パーティ・プロバイダがデフォルトのサーバー名表示をサポートしていないことがあります。アプリケーションでプロバイダに依存しないようにするには、常にホスト名を明示的に設定します。

  • ケース4.クライアントはソケットをサーバー・モードからクライアント・モードに切り替える必要があります。

    まず、メソッドsslSocket.setUseClientMode(true)でモードを切り替えます。次に、ソケットでサーバー名表示パラメータをリセットします。

一般的なサーバー側使用例

次は、サーバー・アプリケーションを開発するためにSNI拡張の理解を必要とするユース・ケースのリストです。

  • ケース1.サーバーはすべてのサーバー名表示タイプを受け付ける必要があります。

    SNI拡張を処理するコードがない場合、サーバーはすべてのサーバー名表示型を無視します。

  • ケース2.サーバーは型 host_nameのすべてのサーバー名表示型を拒否する必要があります。

    host_nameに無効なサーバー名パターンを設定します。

        SNIMatcher matcher = SNIHostName.createSNIMatcher("");
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);        
    

    他の方法は、matches()メソッドで、常にfalseを返すSNIMatcherサブクラスを作成することです。

        class DenialSNIMatcher extends SNIMatcher {
            DenialSNIMatcher() {
                super(StandardConstants.SNI_HOST_NAME);
            }
        
            @Override
            public boolean matches(SNIServerName serverName) {
                return false;
            }
        }
        
        SNIMatcher matcher = new DenialSNIMatcher();
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);        
    
  • ケース3.サーバーはexample.comドメイン内のすべてのホスト名への接続を受け付ける必要があります。

    すべての*.example.comアドレスを含むパターンとして、host_nameの認識可能なサーバー名を設定します。

        SNIMatcher matcher = SNIHostName.createSNIMatcher("(.*\\.)*example\\.com");
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);
    
  • ケース4.サーバーはソケットをクライアント・モードからサーバー・モードに切り替える必要があります。

    まず、メソッドsslSocket.setUseClientMode(false)でモードを切り替えます。次に、ソケットでサーバー名表示パラメータをリセットします。

仮想インフラストラクチャの操作

このセクションでは、仮想インフラストラクチャ内からServer Name Indication (SNI)拡張を使用する方法について説明します。ここでは、ソケットからのClientHelloメッセージのパーサーの作成方法を示し、SSLSocketおよびSSLEngineを使用した仮想サーバー・ディスパッチャの例を示し、SNI拡張を使用できない場合に何が発生するかを説明して、フェールオーバーSSLContextを作成する方法を示します。

ClientHelloパーサーの準備

アプリケーションはソケットからのClientHelloメッセージを解析するAPIを実装する必要があります。次の例に、これらの機能を実行できるSSLCapabilitiesクラスとSSLExplorerクラスを示します。

SSLSocketClient.javaはハンドシェーク中にSSL/TLS/DTLSセキュリティ機能をカプセル化します(つまり、SSL/TLS/DTLSハンドシェークで受け付けられる暗号化方式群のリスト、レコード・バージョン、helloバージョンおよびサーバー名表示)。それは、SSLExplorer.explore()メソッドで、SSL/TLS/DTLS接続のネットワーク・データを調べることによって取得できます。

SSLExplorer.javaはTLSクライアントからの初期ClientHelloメッセージを調査しますが、ハンドシェークを開始したり、ネットワーク・データを消費したりしません。SSLExplorer.explore()メソッドはClientHelloメッセージを解析し、SSLCapabilitiesにセキュリティ・パラメータを取得します。このメソッドは、TLS接続でハンドシェークが行われる前に呼び出す必要があります。

SSLSocketに基づいた仮想サーバー・ディスパッチャ

このセクションでは、SSLSocketに基づいて、仮想サーバー・ディスパッチャを使用する手順を説明します。

  1. サーバー名ハンドラを登録します。

    このステップで、アプリケーションは様々なサーバー名表示の様々なSSLContextオブジェクトを作成したり、特定のサーバー名表示を指定した仮想マシンまたは分散システムにリンクしたりできます。

    たとえば、サーバー名がwww.example.orgの場合、登録されたサーバー名ハンドラはローカル仮想ホスティングWebサービス用などになります。ローカル仮想ホスティングWebサービスは指定したSSLContextを使用します。サーバー名がwww.example.comの場合、登録されたサーバー名ハンドラは10.0.0.36でホストしている仮想マシン用などになります。ハンドラはこの接続を仮想マシンにマッピングできます。

  2. ServerSocketを作成し、新しい接続を受け付けます。

    ServerSocket serverSocket = new ServerSocket(serverPort);
    Socket socket = serverSocket.accept();
    
  3. ソケット入力ストリームからバイトを読み取り、バッファして、バッファ済のバイトを調査します。

    InputStream ins = socket.getInputStream();
    byte[] buffer = new byte[0xFF];
    int position = 0;
    SSLCapabilities capabilities = null;
        
    // Read the header of TLS record
    while (position < SSLExplorer.RECORD_HEADER_SIZE) {
        int count = SSLExplorer.RECORD_HEADER_SIZE - position;
        int n = ins.read(buffer, position, count);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        }
        position += n;
    }
        
    // Get the required size to explore the SSL capabilities
    int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);
    if (buffer.length < recordLength) {
        buffer = Arrays.copyOf(buffer, recordLength);
    }
        
    while (position < recordLength) {
        int count = recordLength - position;
        int n = ins.read(buffer, position, count);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        }
        position += n;
    }
        
    // Explore
    capabilities = SSLExplorer.explore(buffer, 0, recordLength);
    if (capabilities != null) {
        System.out.println("Record version: " + capabilities.getRecordVersion());
        System.out.println("Hello version: " + capabilities.getHelloVersion());
    }
  4. 調査済の機能から要求されたサーバー名を取得します。

    List<SNIServerName> serverNames = capabilities.getServerNames();
    
  5. このサーバー名表示の登録済のサーバー名ハンドラを検索します。

    ホスト名のサービスが仮想マシンまたは他の分散システムに存在する場合、アプリケーションは接続を転送先に転送する必要があります。アプリケーションは、ソケット・ストリームからのSSLアプリケーションよりも、rawインターネット・データを読取りおよび書込みする必要があります。

    Socket destinationSocket = new Socket(serverName, 443);
    // Forward buffered bytes and network data from the current socket to the destinationSocket.
    

    ホスト名のサービスが同じプロセスに存在し、ホスト名サービスでSSLSocketを直接使用できる場合、アプリケーションはSSLSocketインスタンスをサーバーに設定する必要があります。

    // Get service context from registered handler
    // or create the context
    SSLContext serviceContext = ...
    
    SSLSocketFactory serviceSocketFac = serviceContext.getSSLSocketFactory();
    
    // wrap the buffered bytes
    ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, position);
    SSLSocket serviceSocket = (SSLSocket)serviceSocketFac.createSocket(socket, bais, true);
    
    // Now the service can use serviceSocket as usual.
    

SSLEngineに基づいた仮想サーバー・ディスパッチャ

このセクションでは、SSLEngineに基づいて、仮想サーバー・ディスパッチャを使用する手順を説明します。

  1. サーバー名ハンドラを登録します。

    このステップで、アプリケーションは様々なサーバー名表示の様々なSSLContextオブジェクトを作成したり、特定のサーバー名表示を指定した仮想マシンまたは分散システムにリンクしたりできます。

    たとえば、サーバー名がwww.example.orgの場合、登録されたサーバー名ハンドラはローカル仮想ホスティングWebサービス用などになります。ローカル仮想ホスティングWebサービスは指定したSSLContextを使用します。サーバー名がwww.example.comの場合、登録されたサーバー名ハンドラは10.0.0.36でホストしている仮想マシン用などになります。ハンドラはこの接続を仮想マシンにマッピングできます。

  2. ServerSocketまたはServerSocketChannelを作成し、新しい接続を受け付けます。

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(...);
    ...
    SocketChannel socketChannel = serverSocketChannel.accept();
    
  3. ソケット入力ストリームからバイトを読み取り、バッファして、バッファ済のバイトを調査します。

    ByteBuffer buffer = ByteBuffer.allocate(0xFF);
    SSLCapabilities capabilities = null;
    while (true) {
        // ensure the capacity
        if (buffer.remaining() == 0) {
            ByteBuffer oldBuffer = buffer;
            buffer = ByteBuffer.allocate(buffer.capacity() + 0xFF);
            buffer.put(oldBuffer);
        }
    
        int n = sc.read(buffer);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        }
    
        int position = buffer.position();
        buffer.flip();
        capabilities = explorer.explore(buffer);
        buffer.rewind();
        buffer.position(position);
        buffer.limit(buffer.capacity());
        if (capabilities != null) {
            System.out.println("Record version: " +
                capabilities.getRecordVersion());
            System.out.println("Hello version: " +
                capabilities.getHelloVersion());
            break;
        }
    }
    
    buffer.flip();  // reset the buffer position and limitation 
  4. 調査済の機能から要求されたサーバー名を取得します。

    List<SNIServerName> serverNames = capabilities.getServerNames();
    
  5. このサーバー名表示の登録済のサーバー名ハンドラを検索します。

    ホスト名のサービスが仮想マシンまたは他の分散システムに存在する場合、アプリケーションは接続を転送先に転送する必要があります。アプリケーションは、ソケット・ストリームからのSSLアプリケーションよりも、rawインターネット・データを読取りおよび書込みする必要があります。

    Socket destinationSocket = new Socket(serverName, 443);
    // Forward buffered bytes and network data from the current socket to the destinationSocket.
    

    ホスト名のサービスが同じプロセスに存在し、ホスト名サービスでSSLEngineを直接使用できる場合、アプリケーションは単にネット・データをSSLEngineインスタンスに提供します。

    // Get service context from registered handler
    // or create the context
    SSLContext serviceContext = ...
        
    SSLEngine serviceEngine = serviceContext.createSSLEngine();
    // Now the service can use the buffered bytes and other byte buffer as usual.
    

使用可能なSNI拡張がない

ClientHelloメッセージにサーバー名表示がない場合、SNIに従って正しいサービスを選択する方法がありません。そのような場合、アプリケーションは、サーバー名表示がない場合に、接続をそれに委譲できるように、デフォルトのサービスを指定する必要がある場合があります。

フェイルオーバーSSLContext

SSLExplorer.explore()メソッドはSSL/TLS/DTLSの内容の妥当性をチェックしません。レコード形式がSSL/TLS/DTLS仕様に準拠していない場合、またはハンドシェークの起動後に、explore()メソッドが呼び出された場合、メソッドはIOExceptionをスローすることがあり、ネットワーク・データを生成できません。そのような場合、SSL/TLS/DTLS接続のネゴシエーションに使用されないが適切な警告メッセージで接続を閉じるフェイルオーバーSSLContextを使用することで、SSLExplorer.explore()によってスローされた例外を処理します。次の例はフェールオーバーSSLContextを示しています。「一般的なサーバー側使用例」の「ケース2」で、DenialSNIMatcherクラスの例を参照できます。

byte[] buffer = ...       // buffered network data
boolean failed = true;    // SSLExplorer.explore() throws an exception

SSLContext context = SSLContext.getInstance("TLS");
// the failover SSLContext
    
context.init(null, null, null);
SSLSocketFactory sslsf = context.getSocketFactory();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, position);
SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);

SNIMatcher matcher = new DenialSNIMatcher();
Collection<SNIMatcher> matchers = new ArrayList<>(1);
matchers.add(matcher);
SSLParameters params = sslSocket.getSSLParameters();
params.setSNIMatchers(matchers);    // no recognizable server name
sslSocket.setSSLParameters(params);

try {
    InputStream sslIS = sslSocket.getInputStream();
    sslIS.read();
} catch (Exception e) {
    System.out.println("Server exception " + e);
} finally {
    sslSocket.close();
}

標準名

JDK Security APIは、アルゴリズム、証明書およびキーストアのタイプの一連の標準名を必要とし、これらを使用します。Javaセキュリティ標準アルゴリズム名を参照してください。特定のプロバイダ情報は、JDKプロバイダ・ドキュメントで参照できます。

プロバイダのプラグイン可能性

JSSEは完全にプラガブルであり、サード・パーティのJSSEプロバイダの使用には何の制限もありません。

JSSE暗号化方式群のパラメータ

表8-14には、JSSE暗号化方式群名に関連するその他のパラメータのリストが示されています。Javaセキュリティ標準アルゴリズム名を参照してください。

表8-14 JSSE暗号化方式群のパラメータ

標準名(異なる場合は、IANA名) 鍵交換アルゴリズム バルクCipherアルゴリズム メッセージ認証コード・アルゴリズム

SSL_NULL_WITH_NULL_NULL

IANA: TLS_NULL_WITH_NULL_NULL

K_NULL

B_NULL

M_NULL

SSL_RSA_WITH_NULL_MD5

IANA: TLS_RSA_WITH_NULL_MD5

RSA

B_NULL

MD5

SSL_RSA_WITH_NULL_SHA

IANA: TLS_RSA_WITH_NULL_SHA

RSA

B_NULL

SHA-1

SSL_RSA_EXPORT_WITH_RC4_40_MD5

IANA: TLS_RSA_EXPORT_WITH_RC4_40_MD5

RSA_EXPORT

RC4_40

MD5

SSL_RSA_WITH_RC4_128_MD5

IANA: TLS_RSA_WITH_RC4_128_MD5

RSA

RC4

MD5

SSL_RSA_WITH_RC4_128_SHA

IANA: TLS_RSA_WITH_RC4_128_SHA

RSA

RC4

SHA-1

SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5

IANA: TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5

RSA_EXPORT

RC2_CBC_40

MD5

SSL_RSA_WITH_IDEA_CBC_SHA

IANA: TLS_RSA_WITH_IDEA_CBC_SHA

RSA

IDEA_CBC

SHA-1

SSL_RSA_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_RSA_EXPORT_WITH_DES40_CBC_SHA

RSA_EXPORT

DES40_CBC

SHA-1

SSL_RSA_WITH_DES_CBC_SHA

IANA: TLS_RSA_WITH_DES_CBC_SHA

RSA

DES_CBC

SHA-1

SSL_RSA_WITH_3DES_EDE_CBC_SHA

IANA: TLS_RSA_WITH_3DES_EDE_CBC_SHA

RSA

3DES_EDE_CBC

SHA-1

SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA

DH_DSS

DES40_CBC

SHA-1

SSL_DH_DSS_WITH_DES_CBC_SHA

IANA: TLS_DH_DSS_WITH_DES_CBC_SHA

DH_DSS

DES_CBC

SHA-1

SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA

IANA: TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA

DH_DSS

3DES_EDE_CBC

SHA-1

SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA

DH_RSA_EXPORT

DES40_CBC

SHA-1

SSL_DH_RSA_WITH_DES_CBC_SHA

IANA: TLS_DH_RSA_WITH_DES_CBC_SHA

DH_RSA

DES_CBC

SHA-1

SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA

IANA: TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA

DH_RSA

3DES_EDE_CBC

SHA-1

SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

DHE_DSS_EXPORT

DES40_CBC

SHA-1

SSL_DHE_DSS_WITH_DES_CBC_SHA

IANA: TLS_DHE_DSS_WITH_DES_CBC_SHA

DHE_DSS

DES_CBC

SHA-1

SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA

IANA: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA

DHE_DSS

3DES_EDE_CBC

SHA-1

SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA

DHE_RSA_EXPORT

DES40_CBC

SHA-1

SSL_DHE_RSA_WITH_DES_CBC_SHA

IANA: TLS_DHE_RSA_WITH_DES_CBC_SHA

DHE_RSA

DES_CBC

SHA-1

SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA

IANA: TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA

DHE_RSA

3DES_EDE_CBC

SHA-1

SSL_DH_anon_EXPORT_WITH_RC4_40_MD5

IANA: TLS_DH_anon_EXPORT_WITH_RC4_40_MD5

DH_anon_EXPORT

RC4_40

MD5

SSL_DH_anon_WITH_RC4_128_MD5

IANA: TLS_DH_anon_WITH_RC4_128_MD5

DH_anon

RC4

MD5

SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA

IANA: TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA

DH_anon

DES40_CBC

SHA-1

SSL_DH_anon_WITH_DES_CBC_SHA

IANA: TLS_DH_anon_WITH_DES_CBC_SHA

DH_anon

DES_CBC

SHA-1

SSL_DH_anon_WITH_3DES_EDE_CBC_SHA

IANA: TLS_DH_anon_WITH_3DES_EDE_CBC_SHA

DH_anon

3DES_EDE_CBC

SHA-1

TLS_KRB5_WITH_DES_CBC_SHA

KRB5

DES_CBC

SHA-1

TLS_KRB5_WITH_3DES_EDE_CBC_SHA

KRB5

3DES_EDE_CBC

SHA-1

TLS_KRB5_WITH_RC4_128_SHA

KRB5

RC4

SHA-1

TLS_KRB5_WITH_IDEA_CBC_SHA

KRB5

IDEA_CBC

SHA-1

TLS_KRB5_WITH_DES_CBC_MD5

KRB5

DES_CBC

MD5

TLS_KRB5_WITH_3DES_EDE_CBC_MD5

KRB5

3DES_EDE_CBC

MD5

TLS_KRB5_WITH_RC4_128_MD5

KRB5

RC4

MD5

TLS_KRB5_WITH_IDEA_CBC_MD5

KRB5

IDEA_CBC

MD5

TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA

KRB5_EXPORT

DES_CBC

SHA-1

TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA

KRB5_EXPORT

RC2_CBC_40

SHA-1

TLS_KRB5_EXPORT_WITH_RC4_40_SHA

KRB5_EXPORT

RC4_40

SHA-1

TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5

KRB5_EXPORT

DES_CBC

MD5

TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5

KRB5_EXPORT

RC2_CBC_40

MD5

TLS_KRB5_EXPORT_WITH_RC4_40_MD5

KRB5_EXPORT

RC4_40

MD5

TLS_PSK_WITH_NULL_SHA

PSK

B_NULL

SHA-1

TLS_DHE_PSK_WITH_NULL_SHA

DHE_PSK

B_NULL

SHA-1

TLS_RSA_PSK_WITH_NULL_SHA

RSA_PSK

B_NULL

SHA-1

TLS_RSA_WITH_AES_128_CBC_SHA

RSA

AES_128_CBC

SHA-1

TLS_DH_DSS_WITH_AES_128_CBC_SHA

DH_DSS

AES_128_CBC

SHA-1

TLS_DH_RSA_WITH_AES_128_CBC_SHA

DH_RSA

AES_128_CBC

SHA-1

TLS_DHE_DSS_WITH_AES_128_CBC_SHA

DHE_DSS

AES_128_CBC

SHA-1

TLS_DHE_RSA_WITH_AES_128_CBC_SHA

DHE_RSA

AES_128_CBC

SHA-1

TLS_DH_anon_WITH_AES_128_CBC_SHA

DH_anon

AES_128_CBC

SHA-1

TLS_RSA_WITH_AES_256_CBC_SHA

RSA

AES_256_CBC

SHA-1

TLS_DH_DSS_WITH_AES_256_CBC_SHA

DH_DSS

AES_256_CBC

SHA-1

TLS_DH_RSA_WITH_AES_256_CBC_SHA

DH_RSA

AES_256_CBC

SHA-1

TLS_DHE_DSS_WITH_AES_256_CBC_SHA

DHE_DSS

AES_256_CBC

SHA-1

TLS_DHE_RSA_WITH_AES_256_CBC_SHA

DHE_RSA

AES_256_CBC

SHA-1

TLS_DH_anon_WITH_AES_256_CBC_SHA

DH_anon

AES_256_CBC

SHA-1

TLS_RSA_WITH_NULL_SHA256

RSA

B_NULL

SHA-1

TLS_RSA_WITH_AES_128_CBC_SHA256

RSA

AES_128_CBC

SHA-256

TLS_RSA_WITH_AES_256_CBC_SHA256

RSA

AES_256_CBC

SHA-256

TLS_DH_DSS_WITH_AES_128_CBC_SHA256

DH_DSS

AES_128_CBC

SHA-256

TLS_DH_RSA_WITH_AES_128_CBC_SHA256

DH_RSA

AES_128_CBC

SHA-256

TLS_DHE_DSS_WITH_AES_128_CBC_SHA256

DHE_DSS

AES_128_CBC

SHA-256

TLS_RSA_WITH_CAMELLIA_128_CBC_SHA

RSA

CAMELLIA_128_CBC

SHA-1

TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA

DH_DSS

CAMELLIA_128_CBC

SHA-1

TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA

DH_RSA

CAMELLIA_128_CBC

SHA-1

TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA

DHE_DSS

CAMELLIA_128_CBC

SHA-1

TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA

DHE_RSA

CAMELLIA_128_CBC

SHA-1

TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA

DH_anon

CAMELLIA_128_CBC

SHA-1

TLS_DHE_RSA_WITH_AES_128_CBC_SHA256

DHE_RSA

AES_128_CBC

SHA-256

TLS_DH_DSS_WITH_AES_256_CBC_SHA256

DH_DSS

AES_256_CBC

SHA-256

TLS_DH_RSA_WITH_AES_256_CBC_SHA256

DH_RSA

AES_256_CBC

SHA-256

TLS_DHE_DSS_WITH_AES_256_CBC_SHA256

DHE_DSS

AES_256_CBC

SHA-256

TLS_DHE_RSA_WITH_AES_256_CBC_SHA256

DHE_RSA

AES_256_CBC

SHA-256

TLS_DH_anon_WITH_AES_128_CBC_SHA256

DH_anon

AES_128_CBC

SHA-256

TLS_DH_anon_WITH_AES_256_CBC_SHA256

DH_anon

AES_256_CBC

SHA-256

TLS_RSA_WITH_CAMELLIA_256_CBC_SHA

RSA

CAMELLIA_256_CBC

SHA-1

TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA

DH_DSS

CAMELLIA_256_CBC

SHA-1

TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA

DH_RSA

CAMELLIA_256_CBC

SHA-1

TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA

DHE_DSS

CAMELLIA_256_CBC

SHA-1

TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA

DHE_RSA

CAMELLIA_256_CBC

SHA-1

TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA

DH_anon

CAMELLIA_256_CBC

SHA-1

TLS_PSK_WITH_RC4_128_SHA

PSK

RC4

SHA-1

TLS_PSK_WITH_3DES_EDE_CBC_SHA

PSK

3DES_EDE_CBC

SHA-1

TLS_PSK_WITH_AES_128_CBC_SHA

PSK

AES_128_CBC

SHA-1

TLS_PSK_WITH_AES_256_CBC_SHA

PSK

AES_256_CBC

SHA-1

TLS_DHE_PSK_WITH_RC4_128_SHA

DHE_PSK

RC4

SHA-1

TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA

DHE_PSK

3DES_EDE_CBC

SHA-1

TLS_DHE_PSK_WITH_AES_128_CBC_SHA

DHE_PSK

AES_128_CBC

SHA-1

TLS_DHE_PSK_WITH_AES_256_CBC_SHA

DHE_PSK

AES_256_CBC

SHA-1

TLS_RSA_PSK_WITH_RC4_128_SHA

RSA_PSK

RC4

SHA-1

TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA

RSA_PSK

3DES_EDE_CBC

SHA-1

TLS_RSA_PSK_WITH_AES_128_CBC_SHA

RSA_PSK

AES_128_CBC

SHA-1

TLS_RSA_PSK_WITH_AES_256_CBC_SHA

RSA_PSK

AES_256_CBC

SHA-1

TLS_RSA_WITH_SEED_CBC_SHA

RSA

SEED_CBC

SHA-1

TLS_DH_DSS_WITH_SEED_CBC_SHA

DH_DSS

SEED_CBC

SHA-1

TLS_DH_RSA_WITH_SEED_CBC_SHA

DH_RSA

SEED_CBC

SHA-1

TLS_DHE_DSS_WITH_SEED_CBC_SHA

DHE_DSS

SEED_CBC

SHA-1

TLS_DHE_RSA_WITH_SEED_CBC_SHA

DHE_RSA

SEED_CBC

SHA-1

TLS_DH_anon_WITH_SEED_CBC_SHA

DH_anon

SEED_CBC

SHA-1

TLS_RSA_WITH_AES_128_GCM_SHA256

RSA

AES_128_GCM

SHA-256

TLS_RSA_WITH_AES_256_GCM_SHA384

RSA

AES_256_GCM

SHA-384

TLS_DHE_RSA_WITH_AES_128_GCM_SHA256

DHE_RSA

AES_128_GCM

SHA-256

TLS_DHE_RSA_WITH_AES_256_GCM_SHA384

DHE_RSA

AES_256_GCM

SHA-384

TLS_DH_RSA_WITH_AES_128_GCM_SHA256

DH_RSA

AES_128_GCM

SHA-256

TLS_DH_RSA_WITH_AES_256_GCM_SHA384

DH_RSA

AES_256_GCM

SHA-384

TLS_DHE_DSS_WITH_AES_128_GCM_SHA256

DHE_DSS

AES_128_GCM

SHA-256

TLS_DHE_DSS_WITH_AES_256_GCM_SHA384

DHE_DSS

AES_256_GCM

SHA-384

TLS_DH_DSS_WITH_AES_128_GCM_SHA256

DH_DSS

AES_128_GCM

SHA-256

TLS_DH_DSS_WITH_AES_256_GCM_SHA384

DH_DSS

AES_256_GCM

SHA-384

TLS_DH_anon_WITH_AES_128_GCM_SHA256

DH_anon

AES_128_GCM

SHA-256

TLS_DH_anon_WITH_AES_256_GCM_SHA384

DH_anon

AES_256_GCM

SHA-384

TLS_PSK_WITH_AES_128_GCM_SHA256

PSK

AES_128_GCM

SHA-256

TLS_PSK_WITH_AES_256_GCM_SHA384

PSK

AES_256_GCM

SHA-384

TLS_DHE_PSK_WITH_AES_128_GCM_SHA256

DHE_PSK

AES_128_GCM

SHA-256

TLS_DHE_PSK_WITH_AES_256_GCM_SHA384

DHE_PSK

AES_256_GCM

SHA-384

TLS_RSA_PSK_WITH_AES_128_GCM_SHA256

RSA_PSK

AES_128_GCM

SHA-256

TLS_RSA_PSK_WITH_AES_256_GCM_SHA384

RSA_PSK

AES_256_GCM

SHA-384

TLS_PSK_WITH_AES_128_CBC_SHA256

PSK

AES_128_CBC

SHA-256

TLS_PSK_WITH_AES_256_CBC_SHA384

PSK

AES_256_CBC

SHA-384

TLS_PSK_WITH_NULL_SHA256

PSK

B_NULL

SHA-256

TLS_PSK_WITH_NULL_SHA384

PSK

B_NULL

SHA-384

TLS_DHE_PSK_WITH_AES_128_CBC_SHA256

DHE_PSK

AES_128_CBC

SHA-256

TLS_DHE_PSK_WITH_AES_256_CBC_SHA384

DHE_PSK

AES_256_CBC

SHA-384

TLS_DHE_PSK_WITH_NULL_SHA256

DHE_PSK

B_NULL

SHA-256

TLS_DHE_PSK_WITH_NULL_SHA384

DHE_PSK

B_NULL

SHA-384

TLS_RSA_PSK_WITH_AES_128_CBC_SHA256

RSA_PSK

AES_128_CBC

SHA-256

TLS_RSA_PSK_WITH_AES_256_CBC_SHA384

RSA_PSK

AES_256_CBC

SHA-384

TLS_RSA_PSK_WITH_NULL_SHA256

RSA_PSK

B_NULL

SHA-256

TLS_RSA_PSK_WITH_NULL_SHA384

RSA_PSK

B_NULL

SHA-384

TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256

RSA

CAMELLIA_128_CBC

SHA-256

TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256

DH_DSS

CAMELLIA_128_CBC

SHA-256

TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256

DH_RSA

CAMELLIA_128_CBC

SHA-256

TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256

DHE_DSS

CAMELLIA_128_CBC

SHA-256

TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256

DHE_RSA

CAMELLIA_128_CBC

SHA-256

TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256

DH_anon

CAMELLIA_128_CBC

SHA-256

TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256

RSA

CAMELLIA_256_CBC

SHA-256

TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256

DH_DSS

CAMELLIA_256_CBC

SHA-256

TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256

DH_RSA

CAMELLIA_256_CBC

SHA-256

TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256

DHE_DSS

CAMELLIA_256_CBC

SHA-256

TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256

DHE_RSA

CAMELLIA_256_CBC

SHA-256

TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256

DH_anon

CAMELLIA_256_CBC

SHA-256

TLS_EMPTY_RENEGOTIATION_INFO_SCSV

該当なし

該当なし

該当なし

TLS_FALLBACK_SCSV

該当なし

該当なし

該当なし

TLS_ECDH_ECDSA_WITH_NULL_SHA

ECDH_ECDSA

B_NULL

SHA-1

TLS_ECDH_ECDSA_WITH_RC4_128_SHA

ECDH_ECDSA

RC4

SHA-1

TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA

ECDH_ECDSA

3DES_EDE_CBC

SHA-1

TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA

ECDH_ECDSA

AES_128_CBC

SHA-1

TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA

ECDH_ECDSA

AES_256_CBC

SHA-1

TLS_ECDHE_ECDSA_WITH_NULL_SHA

ECDHE_ECDSA

B_NULL

SHA-1

TLS_ECDHE_ECDSA_WITH_RC4_128_SHA

ECDHE_ECDSA

RC4

SHA-1

TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA

ECDHE_ECDSA

3DES_EDE_CBC

SHA-1

TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA

ECDHE_ECDSA

AES_128_CBC

SHA-1

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA

ECDHE_ECDSA

AES_256_CBC

SHA-1

TLS_ECDH_RSA_WITH_NULL_SHA

ECDH_RSA

B_NULL

SHA-1

TLS_ECDH_RSA_WITH_RC4_128_SHA

ECDH_RSA

RC4

SHA-1

TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA

ECDH_RSA

3DES_EDE_CBC

SHA-1

TLS_ECDH_RSA_WITH_AES_128_CBC_SHA

ECDH_RSA

AES_128_CBC

SHA-1

TLS_ECDH_RSA_WITH_AES_256_CBC_SHA

ECDH_RSA

AES_256_CBC

SHA-1

TLS_ECDHE_RSA_WITH_NULL_SHA

ECDHE_RSA

B_NULL

SHA-1

TLS_ECDHE_RSA_WITH_RC4_128_SHA

ECDHE_RSA

RC4

SHA-1

TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

ECDHE_RSA

3DES_EDE_CBC

SHA-1

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

ECDHE_RSA

AES_128_CBC

SHA-1

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

ECDHE_RSA

AES_256_CBC

SHA-1

TLS_ECDH_anon_WITH_NULL_SHA

ECDH_anon

B_NULL

SHA-1

TLS_ECDH_anon_WITH_RC4_128_SHA

ECDH_anon

RC4

SHA-1

TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA

ECDH_anon

3DES_EDE_CBC

SHA-1

TLS_ECDH_anon_WITH_AES_128_CBC_SHA

ECDH_anon

AES_128_CBC

SHA-1

TLS_ECDH_anon_WITH_AES_256_CBC_SHA

ECDH_anon

AES_256_CBC

SHA-1

TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA

SRP_SHA

3DES_EDE_CBC

SHA-1

TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA

SRP_SHA

3DES_EDE_CBC

SHA-1

TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA

SRP_SHA

3DES_EDE_CBC

SHA-1

TLS_SRP_SHA_WITH_AES_128_CBC_SHA

SRP_SHA

AES_128_CBC

SHA-1

TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA

SRP_SHA

AES_128_CBC

SHA-1

TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA

SRP_SHA

AES_128_CBC

SHA-1

TLS_SRP_SHA_WITH_AES_256_CBC_SHA

SRP_SHA

AES_256_CBC

SHA-1

TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA

SRP_SHA

AES_256_CBC

SHA-1

TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA

SRP_SHA

AES_256_CBC

SHA-1

TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256

ECDHE_ECDSA

AES_128_CBC

SHA-256

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384

ECDHE_ECDSA

AES_256_CBC

SHA-384

TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256

ECDH_ECDSA

AES_128_CBC

SHA-256

TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384

ECDH_ECDSA

AES_256_CBC

SHA-384

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

ECDHE_RSA

AES_128_CBC

SHA-256

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

ECDHE_RSA

AES_256_CBC

SHA-384

TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256

ECDH_RSA

AES_128_CBC

SHA-256

TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384

ECDH_RSA

AES_256_CBC

SHA-384

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

ECDHE_ECDSA

AES_128_GCM

SHA-256

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

ECDHE_ECDSA

AES_256_GCM

SHA-384

TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256

ECDH_ECDSA

AES_128_GCM

SHA-256

TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384

ECDH_ECDSA

AES_256_GCM

SHA-384

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

ECDHE_RSA

AES_128_GCM

SHA-256

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

ECDHE_RSA

AES_256_GCM

SHA-384

TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256

ECDH_RSA

AES_128_GCM

SHA-256

TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384

ECDH_RSA

AES_256_GCM

SHA-384

TLS_ECDHE_PSK_WITH_RC4_128_SHA

ECDHE_PSK

RC4

SHA-1

TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA

ECDHE_PSK

3DES_EDE_CBC

SHA-1

TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA

ECDHE_PSK

AES_128_CBC

SHA-1

TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA

ECDHE_PSK

AES_256_CBC

SHA-1

TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256

ECDHE_PSK

AES_128_CBC

SHA-256

TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384

ECDHE_PSK

AES_256_CBC

SHA-384

TLS_ECDHE_PSK_WITH_NULL_SHA

ECDHE_PSK

B_NULL

SHA-1

TLS_ECDHE_PSK_WITH_NULL_SHA256

ECDHE_PSK

B_NULL

SHA-256

TLS_ECDHE_PSK_WITH_NULL_SHA384

ECDHE_PSK

B_NULL

SHA-384

TLS_RSA_WITH_ARIA_128_CBC_SHA256

RSA

ARIA_128_CBC

SHA-256

TLS_RSA_WITH_ARIA_256_CBC_SHA384

RSA

ARIA_256_CBC

SHA-384

TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256

DH_DSS

ARIA_128_CBC

SHA-256

TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384

DH_DSS

ARIA_256_CBC

SHA-384

TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256

DH_RSA

ARIA_128_CBC

SHA-256

TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384

DH_RSA

ARIA_256_CBC

SHA-384

TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256

DHE_DSS

ARIA_128_CBC

SHA-256

TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384

DHE_DSS

ARIA_256_CBC

SHA-384

TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256

DHE_RSA

ARIA_128_CBC

SHA-256

TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384

DHE_RSA

ARIA_256_CBC

SHA-384

TLS_DH_anon_WITH_ARIA_128_CBC_SHA256

DH_anon

ARIA_128_CBC

SHA-256

TLS_DH_anon_WITH_ARIA_256_CBC_SHA384

DH_anon

ARIA_256_CBC

SHA-384

TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256

ECDHE_ECDSA

ARIA_128_CBC

SHA-256

TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384

ECDHE_ECDSA

ARIA_256_CBC

SHA-384

TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256

ECDH_ECDSA

ARIA_128_CBC

SHA-256

TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384

ECDH_ECDSA

ARIA_256_CBC

SHA-384

TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256

ECDHE_RSA

ARIA_128_CBC

SHA-256

TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384

ECDHE_RSA

ARIA_256_CBC

SHA-384

TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256

ECDH_RSA

ARIA_128_CBC

SHA-256

TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384

ECDH_RSA

ARIA_256_CBC

SHA-384

TLS_RSA_WITH_ARIA_128_GCM_SHA256

RSA

ARIA_128_GCM

SHA-256

TLS_RSA_WITH_ARIA_256_GCM_SHA384

RSA

ARIA_256_GCM

SHA-384

TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256

DHE_RSA

ARIA_128_GCM

SHA-256

TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384

DHE_RSA

ARIA_256_GCM

SHA-384

TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256

DH_RSA

ARIA_128_GCM

SHA-256

TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384

DH_RSA

ARIA_256_GCM

SHA-384

TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256

DHE_DSS

ARIA_128_GCM

SHA-256

TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384

DHE_DSS

ARIA_256_GCM

SHA-384

TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256

DH_DSS

ARIA_128_GCM

SHA-256

TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384

DH_DSS

ARIA_256_GCM

SHA-384

TLS_DH_anon_WITH_ARIA_128_GCM_SHA256

DH_anon

ARIA_128_GCM

SHA-256

TLS_DH_anon_WITH_ARIA_256_GCM_SHA384

DH_anon

ARIA_256_GCM

SHA-384

TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256

ECDHE_ECDSA

ARIA_128_GCM

SHA-256

TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384

ECDHE_ECDSA

ARIA_256_GCM

SHA-384

TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256

ECDH_ECDSA

ARIA_128_GCM

SHA-256

TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384

ECDH_ECDSA

ARIA_256_GCM

SHA-384

TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256

ECDHE_RSA

ARIA_128_GCM

SHA-256

TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384

ECDHE_RSA

ARIA_256_GCM

SHA-384

TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256

ECDH_RSA

ARIA_128_GCM

SHA-256

TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384

ECDH_RSA

ARIA_256_GCM

SHA-384

TLS_PSK_WITH_ARIA_128_CBC_SHA256

PSK

ARIA_128_CBC

SHA-256

TLS_PSK_WITH_ARIA_256_CBC_SHA384

PSK

ARIA_256_CBC

SHA-384

TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256

DHE_PSK

ARIA_128_CBC

SHA-256

TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384

DHE_PSK

ARIA_256_CBC

SHA-384

TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256

RSA_PSK

ARIA_128_CBC

SHA-256

TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384

RSA_PSK

ARIA_256_CBC

SHA-384

TLS_PSK_WITH_ARIA_128_GCM_SHA256

PSK

ARIA_128_GCM

SHA-256

TLS_PSK_WITH_ARIA_256_GCM_SHA384

PSK

ARIA_256_GCM

SHA-384

TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256

DHE_PSK

ARIA_128_GCM

SHA-256

TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384

DHE_PSK

ARIA_256_GCM

SHA-384

TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256

RSA_PSK

ARIA_128_GCM

SHA-256

TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384

RSA_PSK

ARIA_256_GCM

SHA-384

TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256

ECDHE_PSK

ARIA_128_CBC

SHA-256

TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384

ECDHE_PSK

ARIA_256_CBC

SHA-384

TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256

ECDHE_ECDSA

CAMELLIA_128_CBC

SHA-256

TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384

ECDHE_ECDSA

CAMELLIA_256_CBC

SHA-384

TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256

ECDH_ECDSA

CAMELLIA_128_CBC

SHA-256

TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384

ECDH_ECDSA

CAMELLIA_256_CBC

SHA-384

TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256

ECDHE_RSA

CAMELLIA_128_CBC

SHA-256

TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384

ECDHE_RSA

CAMELLIA_256_CBC

SHA-384

TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256

ECDH_RSA

CAMELLIA_128_CBC

SHA-256

TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384

ECDH_RSA

CAMELLIA_256_CBC

SHA-384

TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256

RSA

CAMELLIA_128_GCM

SHA-256

TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384

RSA

CAMELLIA_256_GCM

SHA-384

TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256

DHE_RSA

CAMELLIA_128_GCM

SHA-256

TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384

DHE_RSA

CAMELLIA_256_GCM

SHA-384

TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256

DH_RSA

CAMELLIA_128_GCM

SHA-256

TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384

DH_RSA

CAMELLIA_256_GCM

SHA-384

TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256

DHE_DSS

CAMELLIA_128_GCM

SHA-256

TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384

DHE_DSS

CAMELLIA_256_GCM

SHA-384

TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256

DH_DSS

CAMELLIA_128_GCM

SHA-256

TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384

DH_DSS

CAMELLIA_256_GCM

SHA-384

TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256

DH_anon

CAMELLIA_128_GCM

SHA-256

TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384

DH_anon

CAMELLIA_256_GCM

SHA-384

TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256

ECDHE_ECDSA

CAMELLIA_128_GCM

SHA-256

TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384

ECDHE_ECDSA

CAMELLIA_256_GCM

SHA-384

TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256

ECDH_ECDSA

CAMELLIA_128_GCM

SHA-256

TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384

ECDH_ECDSA

CAMELLIA_256_GCM

SHA-384

TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256

ECDHE_RSA

CAMELLIA_128_GCM

SHA-256

TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384

ECDHE_RSA

CAMELLIA_256_GCM

SHA-384

TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256

ECDH_RSA

CAMELLIA_128_GCM

SHA-256

TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384

ECDH_RSA

CAMELLIA_256_GCM

SHA-384

TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256

PSK

CAMELLIA_128_GCM

SHA-256

TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384

PSK

CAMELLIA_256_GCM

SHA-384

TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256

DHE_PSK

CAMELLIA_128_GCM

SHA-256

TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384

DHE_PSK

CAMELLIA_256_GCM

SHA-384

TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256

RSA_PSK

CAMELLIA_128_GCM

SHA-256

TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384

RSA_PSK

CAMELLIA_256_GCM

SHA-384

TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256

PSK

CAMELLIA_128_CBC

SHA-256

TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384

PSK

CAMELLIA_256_CBC

SHA-384

TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256

DHE_PSK

CAMELLIA_128_CBC

SHA-256

TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384

DHE_PSK

CAMELLIA_256_CBC

SHA-384

TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256

RSA_PSK

CAMELLIA_128_CBC

SHA-256

TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384

RSA_PSK

CAMELLIA_256_CBC

SHA-384

TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256

ECDHE_PSK

CAMELLIA_128_CBC

SHA-256

TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384

ECDHE_PSK

CAMELLIA_256_CBC

SHA-384

TLS_RSA_WITH_AES_128_CCM

RSA

AES_128_CCM

CCM

TLS_RSA_WITH_AES_256_CCM

RSA

AES_256_CCM

CCM

TLS_DHE_RSA_WITH_AES_128_CCM

DHE_RSA

AES_128_CCM

CCM

TLS_DHE_RSA_WITH_AES_256_CCM

DHE_RSA

AES_256_CCM

CCM

TLS_RSA_WITH_AES_128_CCM_8

RSA

AES_128_CCM

CCM_8

TLS_RSA_WITH_AES_256_CCM_8

RSA

AES_256_CCM

CCM_8

TLS_DHE_RSA_WITH_AES_128_CCM_8

DHE_RSA

AES_128_CCM

CCM_8

TLS_DHE_RSA_WITH_AES_256_CCM_8

DHE_RSA

AES_256_CCM

CCM_8

TLS_PSK_WITH_AES_128_CCM

PSK

AES_128_CCM

CCM

TLS_PSK_WITH_AES_256_CCM

PSK

AES_256_CCM

CCM

TLS_DHE_PSK_WITH_AES_128_CCM

DHE_PSK

AES_128_CCM

CCM

TLS_DHE_PSK_WITH_AES_256_CCM

DHE_PSK

AES_256_CCM

CCM

TLS_PSK_WITH_AES_128_CCM_8

PSK

AES_128_CCM

CCM_8

TLS_PSK_WITH_AES_256_CCM_8

PSK

AES_256_CCM

CCM_8

TLS_DHE_PSK_WITH_AES_128_CCM_8

DHE_PSK

AES_128_CCM

CCM_8

TLS_DHE_PSK_WITH_AES_256_CCM_8

DHE_PSK

AES_256_CCM

CCM_8

TLS_ECDHE_ECDSA_WITH_AES_128_CCM

ECDHE_ECDSA

AES_128_CCM

CCM

TLS_ECDHE_ECDSA_WITH_AES_256_CCM

ECDHE_ECDSA

AES_256_CCM

CCM

TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8

ECDHE_ECDSA

AES_128_CCM

CCM_8

TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8

ECDHE_ECDSA

AES_256_CCM

CCM_8

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

ECDHE_RSA

AEAD_CHACHA20_POLY1305

SHA-256

TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

ECDHE_ECDSA

AEAD_CHACHA20_POLY1305

SHA-256

TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256

DHE_RSA

AEAD_CHACHA20_POLY1305

SHA-256

TLS_PSK_WITH_CHACHA20_POLY1305_SHA256

PSK

AEAD_CHACHA20_POLY1305

SHA-256

TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256

ECDHE_PSK

AEAD_CHACHA20_POLY1305

SHA-256

TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256

DHE_PSK

AEAD_CHACHA20_POLY1305

SHA-256

TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256

RSA_PSK

AEAD_CHACHA20_POLY1305

SHA-256



脚注の凡例

脚注4: これらのセキュリティ・プロパティで指定されている制限付きアルゴリズムのリストは、変更される可能性があります。最新の値については、JDKインストールのjava.securityファイルを参照してください。