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


Introduction

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

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

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

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

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

これらのセキュリティ・プロトコルは、通常の双方向のストリーム・ソケットをカプセル化し、JSSE APIは認証、暗号化および整合性保護の透過的なサポートを追加します。

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

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

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

特長と利点

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

JSSE標準API

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

SunJSSEプロバイダ

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

このプロバイダの詳細は、Oracleプロバイダ・ドキュメントの「SunJSSE」セクションで説明されています。

関連項目

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

用語と定義

このドキュメントでは、暗号化に関するいくつかの用語が使用されています。 このセクションでは、こうした用語を定義します。

認証

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

暗号化方式群

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

証明書

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

暗号化ハッシュ関数

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

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

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

復号化

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

デジタル署名

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

encryption/decryption

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

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

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

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

キー合意

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

キー交換

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

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

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

keystore/truststore

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

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

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

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

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

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

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

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

公開キー暗号化

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

レコード・プロトコル

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

秘密キー暗号化

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

セッション

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

トラスト・マネージャ

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

トラストストア

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

トランスポート・レイヤー・セキュリティ(TLS)プロトコルの概要

トランスポート・レイヤー・セキュリティ(TLS)は、Webで暗号化を実装する場合に最もよく使用されるプロトコルです。 TLSは、ネットワークでセキュアな通信を行うために暗号化プロセスを組み合わせて使用します。 「Transport Layer Security (TLS)プロトコルの概要」ページでは、TLSおよびそれが使用する暗号化プロセスの概要を示します。

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

セキュアな通信を行うには、接続の両側がSSL対応であることが必要です。 JSSE APIの接続のエンドポイント・クラスは、SSLSocketおよびSSLEngineです。 「SSLSocketおよびSSLEngineの作成に使用するJSSEクラス」では、SSLSocketおよびSSLEngineの作成に使用されるメジャー・クラスが論理的な順序で配置されています。 図の後のテキストで、図の内容を説明しています。

この図は、SSLEngineおよびSSLSocketクラスの作成に必要なJSSEクラスを示しています。 この図は、JSSEクラスおよびインタフェースとその関係についても説明しています。 このイメージの後の項では、これらのクラスおよびインタフェースについて説明します。

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


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


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

コアJSSEクラスは、javax.netおよびjavax.net.sslパッケージの一部です。

SocketFactoryおよびServerSocketFactoryクラス

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

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

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

SSLSocketFactoryおよびSSLServerSocketFactoryクラス

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

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

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

SSLSocketFactoryの取得

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

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

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

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

SSLSocketおよびSSLServerSocketクラス

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

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

ピア・スプーフィングを防ぐには、SSLSocketに提示された資格証明を常に確認する必要があります。 「暗号スイートの選択とリモート・エンティティの検証」を参照してください。


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


SSLSocketの取得

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

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

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ホスト名ルールをオーバーライドできます。

SSLEngineクラス

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

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

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

コア・クラスは、 javax.net.ssl.SSLEngineです。 TLS状態マシンをカプセル化し、SSLEngineクラスのユーザーが提供するインバウンドおよびアウトバウンドのバイト・バッファを操作します。 「SSLEngineを介したデータのフロー」は、アプリケーションからSSLEngine、トランスポート・メカニズムへのデータのフロー、およびトランスポート・メカニズムへのデータのフローを示しています。

次の文は、この図について説明しています。

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

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

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

エンジンのステータスおよびアプリケーションが実行するアクションを示すために、「非ブロッキングSocketChannelの使用」の例に示すように、SSLEngine.wrap()およびSSLEngine.unwrap()メソッドはSSLEngineResultインスタンスを返します。 このSSLEngineResultオブジェクトには、エンジンの全体的なステータスとハンドシェークのステータスの2つのステータス情報が格納されます。

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

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

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
...
}

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

結果ごとに2つのステータスを持つと、SSLEngineはアプリケーションが2つのアクションを実行する必要があることを示すことができます: ハンドシェークに対応したものと、wrap()およびunwrap()メソッドの全体的なステータスを表すもの。 たとえば、エンジンは、単一のSSLEngine.unwrap()コールの結果として、入力データが正常に処理されたことを示すSSLEngineResult.Status.OKを返し、アプリケーションがピアからさらにTLSエンコードされたデータを取得し、ハンドシェイクを続行できるように再度SSLEngine.unwrap()に指定する必要があることを示すSSLEngineResult.HandshakeStatus.NEED_UNWRAPを返すことができます。 お気付きのとおり、先の例はかなり単純化されていますが、これらすべてのステータスを適正に処理するにはコードをかなり拡張する必要があります。

「ハンドシェイク・ステータスおよび全体ステータスのチェックと処理」の例は、ハンドシェイク・ステータス、および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
...
}

TLSプロトコル用のSSLEngine

この項では、SSLEngineオブジェクトを作成し、それを使用してTLSデータを生成および処理する方法を示します。

SSLEngineオブジェクトの作成

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

「JKSをキーストアとするTLS用のSSLEngineクライアントの作成」の例は、JKSをキーストアとして使用するTLS用のSSLEngineクライアントを作成する方法を示しています。


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


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 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);
TLSデータの生成と処理

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

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

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

「TLSハンドシェイク中の状態マシン」は、典型的なTLSハンドシェイク中の状態マシンと、対応するメッセージおよびステータスを示しています:

次の文は、この図について説明しています。

ハンドシェイクのステータスが決定される前に、次のステップが実行されます:

この図は、可能なハンドシェイク・ステータスの一部を示しています。 セクション「SSLEngine操作ステータスの理解」では、これらのステータスについて詳細に説明します:

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

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

「非ブロッキングSocketChannelの使用」の例は、非ブロッキングSocketChannelを使用してピアと通信するSSLアプリケーションを示しています。


ノート: この例は、非ブロックSocketChannelを組み込んだSelectorを使用することにより、堅牢性と拡張性を高めることができます。


「非ブロッキングSocketChannelの使用」では、文字列helloは、例「JKSをキーストアとするTLS用のSSLEngineクライアントの作成」で作成したSSLEngineを使用してエンコードすることによってピアに送信されます。 これは、バイト・バッファの大きさを決定するために、SSLSessionからの情報を使用しています。

// 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 to use 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 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 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
...
}

「非ブロックSocketChannelからのデータの読取り」の例は、同じ非ブロッキングSocketChannelからデータを読み取って、「JKSをキーストアとするTLS用のSSLEngineクライアントの作成」の例で作成したSSLEngineを使用してプレーン・テキスト・データを抽出する方法を示しています。 このコードが反復されるごとに、ハンドシェーク処理が進行しているかどうかに応じて、プレーン・テキストが生成されたり、生成されなかったりします。

// Read SSL/TLS 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
...
}

ブロック・タスクの処理

ハンドシェーク時に、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接続を正しい順序でシャットダウンするため、SSL/TLSプロトコルではクローズ・メッセージを送信する必要があります。 したがって、アプリケーションがSSL/TLS接続を終了する場合は、最初にSSLEngineからクローズ・メッセージを取得し、トランスポート・メカニズムを使用してそれらのメッセージをピアに送信して、最後にトランスポート・メカニズムをシャットダウンします。 例6にこれを示します。

// 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();

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

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

SSLSessionおよびExtendedSSLSession

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

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

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

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

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


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


HttpsURLConnectionクラス

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

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つのクラス(SSLContextKeyManagerFactoryおよびTrustManagerFactory)はエンジン・クラスです。 エンジン・クラスとは、特定のアルゴリズムのAPIクラス(SSLContextの場合はプロトコル)です。その実装では1つまたは複数の暗号化サービス・プロバイダ(プロバイダ)パッケージで提供されることがあります。 プロバイダとエンジン・クラスの詳細は、「Java暗号化アーキテクチャ・リファレンス・ガイド」の「設計方針」と「概念」のセクションを参照してください。

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

SunJSEEによって提供される実装
実装されるエンジン・クラス アルゴリズムまたはプロトコル
KeyStore PKCS12
KeyManagerFactory PKIX、SunX509
TrustManagerFactory PKIX (X509またはSunPKIX)、SunX509
SSLContext SSLv3(1), TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 (JDK 8u261以降)

SSLContextクラス

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

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

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

SSLContextクラスの取得と初期化

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

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

SSLContextオブジェクトの作成

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


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

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

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

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

プロトコルは、希望するセキュアなソケット・プロトコルを記述する文字列(TLSなど)です。 SSLContextオブジェクトの一般的なプロトコル名は、付録Aで定義されています。

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

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

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

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

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

内部のデフォルト・コンテキストが使用される場合(SSLContextSSLSocketFactory.getDefault()またはSSLServerSocketFactory.getDefault()によって作成されるなど)、デフォルトのKeyManagerTrustManagerが作成されます。 また、デフォルトの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()メソッドを呼び出します。 不明な場合は、プロバイダのベンダーに問い合わせてください。

SunJSSEプロバイダのSunX509 TrustManagerFactoryなど、多くのファクトリでは、KeyStoreTrustManagerFactoryの初期化に必要な唯一の情報であるため、最初の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実装を使用します。 トラスト・マネージャ・ファクトリを初期化するには、通常のinit(KeyStore ks)メソッドを使用するか、javax.net.ssl.CertPathTrustManagerParametersクラスを使用して、CertPathパラメータをPKIXトラスト・マネージャに渡します。

次の例に、トラスト・マネージャを取得して特定の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("PKCS12");
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);

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

PKIXおよびCertPath APIの詳細は、「Java PKIプログラマーズ・ガイド」を参照してください。

X509TrustManagerインタフェース

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

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

X509TrustManagerの作成

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


ノート: 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暗号化方式群が匿名であり、認証を行わないので、トラストストアは必要ありません。

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

独自のX509TrustManagerの作成

指定したX509TrustManagerの動作が状況に適していない場合は、独自のTrustManagerFactoryを作成して登録するか、X509TrustManagerインタフェースを直接実装して、独自の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("PKCS12");
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();
}
}

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

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

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を作成する方法を示します。

次の例では、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");

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

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

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

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

SunJSSEプロバイダからのデフォルトのSunX509 KeyManagerFactoryなど、多くのファクトリでは、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の作成

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

独自のX509KeyManagerの作成

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

X509ExtendedKeyManagerクラス

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

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

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

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

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

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

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

TrustManagerとKeyManagerの関係

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

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

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

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

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

SSLParametersクラス

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

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

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

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

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);

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

暗号化方式群の優先順位

TLSハンドシェーク時に、クライアントは、それがサポートする暗号化オプションのリストの、最優先順位から暗号化方式群をネゴシエーションすることを要求します。 次に、サーバーはクライアントによって要求された暗号化方式群のリストから、単一の暗号化方式群を選択します。 この選択では、デフォルトで、最もセキュアな設定であるサーバーの優先順位に従います。 ただし、サーバーは、SSLParameters.setUseCipherSuitesOrder(false)メソッドを呼び出すことで、クライアントのプリファレンスではなく、クライアントのプリファレンスを尊重することを選択できます。

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からバインドまたはアンバインドされるときに、SSLSessionBindingListenerに伝えられるイベントを定義します。

HandShakeCompletedListenerインタフェース

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

HandShakeCompletedEventクラス

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

HostnameVerifierインタフェース

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

たとえば、

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());

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

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クラス

抽象SNIServerNameクラスのインスタンスは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ホスト名(クライアントから理解できる)を指定します。 この引数は、次の場合に不正です。

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


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


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

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

JSSEのカスタマイズ

JSSEには、様々な実装をプラグインしたり、デフォルトのキーストアを指定したりして、カスタマイズ可能な標準実装が含まれます。 次の表では、カスタマイズ可能な側面、デフォルトの概要、およびカスタマイズに使用するメカニズムについて説明します。

一部のカスタマイズは、セキュリティ・プロパティ値またはシステム・プロパティ値を設定することによって行われます。 表に続くセクションでは、プロパティ値の設定方法について説明します。

次の表に、java.security.Securityプロパティを設定してカスタマイズされる項目を示します:

セキュリティ・プロパティ カスタマイズされたアイテム デフォルト値 ノート
cert.provider.x509v1 X509証明書実装のカスタマイズ OracleからのX509Certificate実装 なし
SunJSSEプロバイダで使用されるJCE暗号化アルゴリズム SunJCEプロバイダよりも優先度の高い代替JCEアルゴリズム・プロバイダを指定します。「暗号化アルゴリズム・プロバイダのカスタマイズ」を参照してください。 SunJCE実装 なし
jdk.certpath.disabledAlgorithms1 無効化された証明書検証暗号化アルゴリズム(無効化された制限付き暗号化アルゴリズムを参照) MD2、MD5、SHA1 jdkCA &使用方法TLSServer、RSA keySize < 1024、DSA keySize < 1024、EC keySize < 224、jdk.disabled.namedCurves、SHA1使用方法SignedJAR & denyAfter 2019-01-01 2 なし
jdk.tls.disabledAlgorithms1 無効化された制限付き暗号化アルゴリズム SSLv3、TLSv1、TLSv1.1、RC4、DES、MD5withRSA、DH keySize < 1024、EC keySize < 224、3DES_EDE_CBC、anon、NULL、ECDHにはjdk.disabled.namedCurves 2が含まれます アプリケーションで明示的に有効化されている場合でも、TLS接続に対してネゴシエートされない特定のアルゴリズム(プロトコルのバージョン、暗号スイート、キー交換メカニズムなど)を無効にします
jdk.tls.keyLimits 1 (JDK 8u261以降) アルゴリズムでキー・セットを使用して暗号化可能なデータ量の制限 AES/GCM/NoPadding KeyUpdate 2^37 アルゴリズムで特定のキー・セットを使用して暗号化可能なデータ量を制限します。この制限に達すると、KeyUpdateポストハンドシェーク・メッセージが送信され、現在のキー・セットを更新するように要求します。
jdk.tls.legacyAlgorithms1 レガシーの暗号化アルゴリズム K_NULL、C_NULL、M_NULL、DH_anon、ECDH_anon、RC4_128、RC4_40、DES_CBC、DES40_CBC、3DES_EDE_CBC2 レガシー・アルゴリズムとみなされるアルゴリズムを指定します。これは、他の候補がないかぎり、TLSセキュリティ・パラメータのネゴシエーション中にネゴシエーションされません。
jdk.tls.maxCertificateChainLength1 証明書チェーンの処理 10 TLSハンドシェークでの証明書チェーンの最大許容長を指定します。
jdk.tls.maxHandshakeMessageSize1 証明書チェーンの処理 32768 (32KB) TLSハンドシェイクでのハンドシェイク・メッセージの最大許容サイズをバイト単位で指定します。
jdk.tls.server.defaultDHEParameters1 Diffie-Hellmanグループ JDK TLS実装における安全なプライムDiffie-Hellmanグループ Transport Layer Security (TLS)処理のデフォルトの有限フィールドDiffie-Hellmanエフェメラル(DHE)パラメータを定義
ocsp.enable1 クライアント駆動OCSPおよびOCSPプル false クライアント主導型オンライン証明書ステータス・プロトコル(OCSP)を有効にします。 失効チェックも有効にする必要があります(「クライアント主導型OCSPを使用するためのJavaクライアントの設定」を参照)。
security.provider.n 暗号化サービス・プロバイダ。プロバイダ実装のカスタマイズ暗号化アルゴリズム・プロバイダのカスタマイズを参照してください。 プラットフォームごとに異なります。java.securityセキュリティ・プロパティ・ファイルを確認してください。 セキュリティ・プロパティ・ファイルのsecurity.provider.n=行にプロバイダを指定します。nは、値が1以上の整数です。
ssl.KeyManagerFactory.algorithm デフォルトのキー・マネージャ・ファクトリ・アルゴリズム名(デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズを参照) SunX509 なし
ssl.ServerSocketFactory.provider1 デフォルトのSSLServerSocketFactory実装 OracleからのSSLServerSocketFactory実装 なし
ssl.SocketFactory.provider1 デフォルトのSSLSocketFactory実装 OracleからのSSLSocketFactory実装 なし
ssl.TrustManagerFactory.algorithm デフォルトのトラスト・マネージャ・ファクトリ・アルゴリズム名(デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズを参照) PKIX なし

1このセキュリティ・プロパティは、現在JSSE実装で使用されていますが、他の実装で検査および使用される保証はありません。 他の実装で調査する場合は、その実装で、JSSE実装と同じ方法でそれを処理すべきです。 今後のリリースでは、このプロパティが引き続き存在するか、同じタイプ(システムまたはセキュリティ)になる保証はありません。

2これらのセキュリティ・プロパティで指定された制限付き、無効およびレガシー・アルゴリズムのリストが変更される場合があります。最新の値については、JDKインストールのjava.securityファイルを参照してください。

次の表に、java.lang.Systemプロパティを設定してカスタマイズされる項目を示します。

システム・プロパティ カスタマイズされたアイテム デフォルト ノート
com.sun.net.ssl.checkRevocation1 失効チェック false クライアント主導型OCSPを有効化するには、失効チェックを有効にする必要があります(「クライアント主導型OCSPとOCSPステープリング」を参照)。
HTTPS URLのポート・フィールドを使用してカスタマイズ* デフォルトのHTTPSポート 443 なし
https.cipherSuites1 HTTPS接続用のデフォルトの暗号化方式群1 ソケット・ファクトリによって決定 HttpsURLConnectionで使用できる暗号群を指定する暗号群名リスト(カンマ区切り形式)を含む。 SSLSocket.setEnabledCipherSuites(String[])メソッドを参照してください。 このメソッドは、渡されたString配列から直接、ClientHello暗号スイートの優先順位を設定します。
https.protocols1 HTTPS接続用のデフォルトのハンドシェーク・プロトコル ソケット・ファクトリによって決定 HttpsURLConnectionで有効にするプロトコルを指定するプロトコル名リスト(カンマ区切り形式)を含む。 SSLSocket.setEnabledProtocols(String[])を参照してください。
https.proxyHost1 デフォルトのプロキシ・ホスト なし なし
https.proxyPort1 デフォルトのプロキシ・ポート 80 なし
java.protocol.handler.pkgs HTTPSプロトコルの代替実装の指定 Oracleからの実装 なし
javax.net.ssl.keyStore1 デフォルトのキーストア(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) NONE NONEを指定できます。 この設定は、ハードウェア・トークンに存在する場合など、キーストアがファイルベースでない場合に適切。
javax.net.ssl.keyStorePassword1 デフォルトのキーストア・パスワード(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) なし 他のユーザーによる検出に公開する方法でパスワードを指定することはお勧めできません。 たとえば、コマンドラインでパスワードを指定します。 パスワードのセキュリティを維持するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します。
javax.net.ssl.keyStoreProvider1 デフォルトのキーストア・プロバイダ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照) なし なし
javax.net.ssl.keyStoreType1 デフォルトのキーストア・タイプ(デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズを参照) KeyStore.getDefaultType() なし
javax.net.ssl.sessionCacheSize (JDK 8u261以降) SSLセッション・キャッシュ内の最大エントリ数のデフォルト値 20480 セッション・キャッシュ・サイズは、SSLSessionContext.setSessionCacheSizeメソッドをコールするか、javax.net.ssl.sessionCachSizeシステム・プロパティを設定することで設定できます。 キャッシュ・サイズが未設定の場合はデフォルト値が使用されます。
javax.net.ssl.trustStore1 デフォルトのトラストストア(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) jssecacerts(存在する場合)、それ以外の場合はcacerts NONEを指定できます。 この設定は、ハードウェア・トークンに存在する場合など、トラストストアがファイルベースでない場合に適切。
javax.net.ssl.trustStorePassword1 デフォルトのトラストストア・パスワード(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) なし 他のユーザーによる検出に公開する方法でパスワードを指定することはお勧めできません。 たとえば、コマンドラインでパスワードを指定します。 パスワードのセキュリティを維持するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します。
javax.net.ssl.trustStoreProvider1 デフォルトのトラストストア・プロバイダ(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) なし なし
javax.net.ssl.trustStoreType1 デフォルトのトラストストア・タイプ(「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」を参照) KeyStore.getDefaultType() なし
jdk.tls.acknowledgeCloseNotify 1 (JDK 8u261以降) close_notifyアラートの受信時の送信の指定 false システム・プロパティがtrueに設定されている場合、クライアントまたはサーバーがclose_notifyアラートを受信すると、対応するclose_notifyアラートが送信され、接続は二重クローズされます。
jdk.tls.client.cipherSuites1 クライアント側の、デフォルトで有効な暗号化方式群。デフォルトで有効な暗号化方式群の指定を参照してください このJDKリリースに対して現在実装されているSunJSSE暗号スイートのリストを、優先順位でソートして表示するには、「SunJSSE暗号スイート」を参照してください。 注意: これらのシステム・プロパティを使用して弱い暗号スイートを構成したり、構成済の暗号スイートが将来弱い場合があります。 このリスクを理解せずにこれらのシステム・プロパティを使用することはお薦めしません。
jdk.tls.client.disableExtensions1 デフォルトの拡張機能の構成 なし クライアント側で使用される拡張機能をブロックします。
jdk.tls.client.protocols1 TLSクライアントのデフォルトのハンドシェーク・プロトコル。 「SunJSSEプロバイダ」を参照してください。 なし クライアントで特定のSunJSSEプロトコルを有効にするには、カンマ区切りのリストで引用符で囲んで指定します。サポートされている他のすべてのプロトコルは、クライアントでは有効になりません。 たとえば、jdk.tls.client.protocols="TLSv1,TLSv1.1"の場合、TLSv1およびTLSv1.1のクライアントでのデフォルトのプロトコル設定は有効ですが、SSLv3、TLSv1.2、TLSv1.3およびSSLv2Helloは有効ではありません。
jdk.tls.client.SignatureSchemes1 クライアント側のTLS接続に使用できる署名スキームを指定する、サポートされている署名スキーム名のカンマ区切りリストが含まれます。 なし 認識されない、またはサポートされない署名スキーム名がプロパティに指定された場合は無視されます。 このシステム・プロパティが定義されていないか空である場合、プロバイダ固有のデフォルトが使用されます。 この名前は大/小文字が区別されません。 シグネチャ・スキーム名のリストについては、「付録D: シグネチャ・スキーム」を参照してください。
jdk.tls.ephemeralDHKeySize1 エフェメラルDiffie-Hellmanキーのサイズのカスタマイズ 2048ビット なし
jdk.tls.namedGroups1 TLSキー交換用にサポートされている名前付きグループのカスタマイズ このシステム・プロパティが定義されていないか値が空の場合は、実装のデフォルトのグループおよび設定が使用されます。 これには、引用符で囲まれたカンマ区切りリスト形式で、有効な名前付きグループが優先順位に従って格納されています。 たとえば: jdk.tls.namedGroups="secp521r1,secp256r1,ffdhe2048"
jdk.tls.rejectClientInitiatedRenegotiation1 サーバー側でクライアントが開始した再ネゴシエーションを拒否します。 このシステム・プロパティがtrueの場合、サーバーはクライアントによって開始された再ネゴシエーションを受け入れず、致命的なhandshake_failureアラートで失敗します。 クライアント側で初期化されたサーバー側再ネゴシエーションを拒否します。 false なし
jdk.tls.server.cipherSuites1 サーバー側の、デフォルトで有効な暗号化方式群。 「デフォルトで有効な暗号化方式群の指定」を参照してください デフォルトで有効になっている暗号化方式群を確認するには、「SunJSSE暗号化方式群」を参照してください 注意: これらのシステム・プロパティを使用して弱い暗号スイートを構成したり、構成済の暗号スイートが将来弱い場合があります。 このリスクを理解せずにこれらのシステム・プロパティを使用することはお薦めしません。
jdk.tls.server.disableExtensions1 デフォルトの拡張機能の構成 なし サーバー側で使用される拡張機能をブロックします。
jdk.tls.server.protocols 1 (JDK 8u261以降) TLSサーバーのデフォルトのハンドシェーク・プロトコル。 「SunJSSEプロバイダ」を参照してください。 なし SunJSSEプロバイダのサーバー側でデフォルトの有効なプロトコル・スイートを構成するには、カンマ区切りリストでプロトコルを引用符で囲んで指定します。 このリストのプロトコルは、「Javaセキュリティ標準アルゴリズム」で説明されている標準のSSLプロトコル名です。 このシステム・プロパティは、デフォルトのプロトコル・スイート(SSLおよびTLSアルゴリズムのSSLContext)にのみ影響します。 アプリケーションがバージョン固有のSSLContext (SSLv3、TLSv1、TLSv1.1、TLSv1.2またはTLSv1.3)を使用する場合、または有効なプロトコル・バージョンを明示的に設定する場合、このシステム・プロパティは影響しません。
jdk.tls.server.SignatureSchemes1 サーバー側のTLS接続に使用できる署名スキームを指定する、サポートされている署名スキーム名のカンマ区切りリストが含まれます。 なし 認識されない、またはサポートされない署名スキーム名がプロパティに指定された場合は無視されます。 このシステム・プロパティが定義されていないか空である場合、プロバイダ固有のデフォルトが使用されます。 この名前は大/小文字が区別されません。 シグネチャ・スキーム名のリストについては、「付録D: シグネチャ・スキーム」を参照してください。
jsse.enableFFDHEExtension 1 (JDK 8u261以降) TLSキー交換のFinite Field Diffie-Hellman Ephemeral (FFDHE)パラメータを有効または無効にします true FFDHEは、RFC 7919で定義されたTLS拡張子です。 これにより、TLS接続で既知の有限フィールドDiffie-Hellmanグループを使用できます。 かなり古い一部のTLSベンダーは、TLS拡張を処理できないことがあります。 この場合、このプロパティをfalseに設定してFFDHE拡張を無効化します。
jsse.enableMFLNExtension 1 (JDK 8u261以降) 最大フラグメント長ネゴシエーションのカスタマイズ(MFLN) Extension false なし
jsse.enableSNIExtension1 Server Name Indicationオプション true Server Name Indication (SNI)は、RFC 6066で定義されているTLS拡張です。 これは仮想サーバーへのTLS接続を可能にし、さまざまなネットワーク名に対して複数のサーバーが単一の基本ネットワーク・アドレスでホスティングされます。 かなり古い一部のTLSベンダーは、TLS拡張を処理できないことがあります。 この場合、SNI拡張を無効にするには、このプロパティをfalseに設定
jsse.SSLEngine.acceptLargeFragments1 大きいTLSパケット用のバッファのデフォルトのサイズ設定 なし このシステム・プロパティをtrueに設定すると、SSLSessionは、デフォルトで大きいデータ・パケットを処理するためにバッファのサイズを設定します(「SSLSessionおよびExtendedSSLSession」のノートを参照)。 これにより、アプリケーションが不要な大きいSSLEngineバッファを割り当てる場合があります。 かわりに、アプリケーションはバッファ・オーバーフロー条件を動的にチェックし、必要に応じてバッファのサイズを変更する必要があります。(「SSLEngine操作ステータスの理解」を参照してください)。
jdk.tls.client.enableStatusRequestExtension1 クライアント主導のOCSPを使用するためのJavaクライアントの設定 false trueの場合、status_requestおよびstatus_request_v2拡張が有効になり、サーバーによって送信されるCertificateStatusメッセージの処理が有効になります。
jdk.tls.server.enableStatusRequestExtension1 OCSPステイプルを使用するようにJavaサーバーを設定 false trueの場合、OCSPステッピングのサーバー側サポートが有効になります
sun.security.ssl.allowLegacyHelloMessages レガシーHelloメッセージの許可 (再交渉) true trueの場合、適切なRFC 5746メッセージを必要とせずにピアにハンドシェイクを許可します。 詳細は、「Transport Layer Security (TLS)再ネゴシエーションの問題」「フェーズ2の修正の説明」を参照してください。
sun.security.ssl.allowUnsafeRenegotiation 安全でないSSL/TLS再ネゴシエーションの許可 false trueの場合、完全な(安全でない)レガシー・ネゴシエーションを許可します。 詳細は、「Transport Layer Security (TLS)再ネゴシエーションの問題」「フェーズ2の修正の説明」を参照してください。

1このシステム・プロパティは、現在JSSE実装によって使用されていますが、他の実装によって検査および使用されることは保証されていません。 他の実装で調査する場合は、その実装で、JSSE実装と同じ方法でそれを処理すべきです。 今後のリリースでは、このプロパティが引き続き存在するか、同じタイプ(システムまたはセキュリティ)になる保証はありません。

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

JSSEの一部の側面は、セキュリティ・プロパティを設定してカスタマイズできます。 セキュリティ・プロパティは静的または動的に設定できます。

java.lang.Systemプロパティを指定する方法

JSSEの一部の側面は、システム・プロパティを設定してカスタマイズできます。 次のいくつかの方法によって、これらのプロパティを設定できます。

TLS 1.3の有効化

JDK 8u261以降には、Transport Layer Security (TLS) 1.3仕様(RFC 8446)の実装が含まれています。

TLS 1.3は、クライアント・エンドポイントのデフォルトのSSLContext (SSLまたはTLS)に対して有効です。

TLS 1.3には以前のバージョンとの直接的な互換性がない

TLS 1.3には、以前のバージョンとの直接的な互換性がありません。 TLS 1.3を下位互換性モードで実装することは可能ですが、TLS 1.3にアップグレードする際に考慮する互換性リスクはまだいくつかあります。

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

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

オプションで、別の実装を返すようにすることもできます。 これを行うには、cert.provider.x509v1という名前の「セキュリティ・プロパティ」の値として、他の実装のクラスの(パッケージ)という名前を指定します。 たとえば、クラスがMyX509CertificateImplという名前で、com.cryptoxパッケージに表示されている場合は、セキュリティ・プロパティ・ファイルに次の行を追加する必要があります:

cert.provider.x509v1=com.cryptox.MyX509CertificateImpl

デフォルトで有効な暗号化方式群の指定

アプリケーションで、またはシステム・プロパティjdk.tls.client.cipherSuitesおよびjdk.tls.server.cipherSuitesを使用して、デフォルトの有効な暗号スイートを指定できます。


ノート: 有効な暗号スイートの実際の使用は、アルゴリズムの制約によって制限されます。


デフォルトで有効化する暗号化方式群のセットは、この優先度順に従い、次のいずれかの方法で決定されます。

  1. アプリケーションによる明示的な設定
  2. システム・プロパティによる指定
  3. JSSEプロバイダのデフォルトによる指定

たとえば、アプリケーションでデフォルトの有効な暗号スイートを明示的に設定すると、jdk.tls.client.cipherSuitesまたはjdk.tls.server.cipherSuitesで指定された設定およびJSSEプロバイダのデフォルトがオーバーライドされます。

アプリケーションによる明示的な設定

次のいずれかのメソッドを使用して、どの暗号化方式群が有効であるかを設定できます。

システム・プロパティによる指定

システム・プロパティjdk.tls.client.cipherSuitesは、クライアント側で有効になっているデフォルトの暗号スイートを指定します。jdk.tls.server.cipherSuitesは、サーバー側で有効になっている暗号スイートを指定します。

これら2つのシステム・プロパティの値の構文は、サポートされている暗号化方式群の名前をカンマで区切ったリストです。 これらのプロパティで指定された暗号化方式群名のうち、認識されていないまたはサポートされていないものは無視されます。 JSSE暗号化方式群の標準名は、Javaセキュリティ標準アルゴリズムを参照してください。


ノート: これらのシステム・プロパティは、現在Oracle JDKでサポートされています。 これらが他のJDK実装によってサポートされることは保証されていません。



注意: これらのシステム・プロパティを使用して弱い暗号スイートを構成したり、構成済の暗号スイートが将来弱い場合があります。 このリスクを理解せずにこれらのシステム・プロパティを使用することはお薦めしません。


JSSEプロバイダのデフォルトによる指定

各JSSEプロバイダは、デフォルトで有効な暗号化方式群を独自に設定しています。 SunJSSEプロバイダでサポートされている暗号スイート名、およびデフォルトで有効になっている暗号スイート名については、「JDK 8のJava暗号化アーキテクチャOracleプロバイダ・ドキュメント」「SunJSSEプロバイダ」を参照してください。

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

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

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


ノート: 過去のJSSEリリースでは、JSSEのインストール中にjava.protocol.handler.pkgsシステム・プロパティを設定する必要がありました。 このステップは、com.sun.net.ssl.HttpsURLConnectionのインスタンスを取得する場合以外は不要になりました。 詳細については、「トラブルシューティング」セクションの「HttpsURLConnectionクラスを使用するコード」を参照してください。


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

JDK 1.4以降のリリースには、SunJSSEというJSSE暗号化サービス・プロバイダ(略称はプロバイダ)が標準で付属しています。 基本的に、プロバイダは特定の暗号化アルゴリズムのエンジン・クラスを実装するパッケージです。 JSSEのエンジン・クラスはSSLContextKeyManagerFactory、およびTrustManagerFactoryです。 プロバイダとエンジン・クラスの詳細は、「Java暗号化アーキテクチャ・リファレンス・ガイド」を参照してください。


ノート: SunJSSEがCipher.getInstance()を呼び出すとき、使用される変換文字列は「RSA/ECB/PKCS1Padding」、「RC4」、「DES/CBC/NoPadding」、「DESede/CBC/NoPadding」になります。 Cipherクラスと変換文字列の詳細は、「Java暗号化アーキテクチャ・リファレンス・ガイド」を参照してください。


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

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

プロバイダを静的に登録するには、セキュリティ・プロパティ・ファイルに次の形式の行を追加します:

security.provider.n=providerClassName

これはプロバイダを宣言し、その優先順位nを指定します。 優先順位とは、特定のプロバイダが要求されていない場合に、要求されたアルゴリズムについて検索されるプロバイダの順序です。「1」が最優先で次に「2」、というように続きます。

providerClassNameは、プロバイダ・クラスの完全修飾名です。 この名前は、プロバイダ・ベンダーから取得します。

JDK 6に同梱されている標準セキュリティ・プロバイダおよびSunJSSEプロバイダが自動的に登録されます。java.securityセキュリティ・プロパティ・ファイルに次の行が表示され、SunJCEセキュリティ・プロバイダをプリファレンス順序5で登録し、SunJSSEプロバイダをプリファレンス順序4で登録します:

security.provider.1=sun.security.pkcs11.SunPKCS11 \
${java.home}/lib/security/sunpkcs11-solaris.cfg
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider

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

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

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

プロバイダを静的に登録するかわりに、プログラム開始時にSecurity.addProvider()メソッドを呼び出して、実行時に動的にプロバイダを追加できます。 たとえば、プロバイダのクラス名がMyProviderで、そのMyProviderクラスがcom.ABCパッケージにあるプロバイダを動的に追加するには、次を呼び出します。

Security.addProvider(new com.ABC.MyProvider());

Security.addProviderメソッドは、次に利用できる優先順位に、指定したプロバイダを追加します。

この登録は恒久的ではなく、十分なアクセス権があるプログラムでしか実行できません。

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

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

デフォルトのSSLContextは、デフォルトのKeyManagerおよびデフォルトのTrustManagerで初期化されます。 キーストアがjavax.net.ssl.keyStoreシステム・プロパティおよび適切なjavax.net.ssl.keyStorePasswordシステム・プロパティで指定されている場合、デフォルトの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ファイルに限られた数の信頼できるルート証明書が付属しています。 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リファレンス実装と同じ方法でそれらを処理してください。


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

デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」で説明したように、デフォルトのSSLSocketFactorySSLServerSocketFactoryが作成され、このデフォルトの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リファレンス実装と同じ方法でそれらを処理してください。


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

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

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

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

レガシーの暗号化アルゴリズム

一部の環境では、特定のアルゴリズムが望ましくない可能性があっても、それがレガシー・アプリケーションで使用されている場合は無効化できません。 レガシー・アルゴリズムは引き続きサポートされますが、通常、レガシー・アルゴリズムはセキュリティ強度が十分でないため、アプリケーションでは使用しないでください。 TLSセキュリティ・パラメータのネゴシエーション中、他の候補がないかぎり、レガシー・アルゴリズムはネゴシエーションされません。 セキュリティ・プロパティjdk.tls.legacyAlgorithmsでは、Oracle JDKでレガシー・アルゴリズムとみなされるアルゴリズムを指定します。 このセキュリティ・プロパティの構文については、<java-home>/lib/security/java.securityファイルを参照してください。


ノート:


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

SunJSSEプロバイダは、その暗号化のすべてニーズに対してSunJCE実装を使用します。 プロバイダは通常の位置に置くことが推奨されていますが、SunJCEプロバイダより前に登録することにより、他のJCAまたはJCEプロバイダからの実装を使用できます。 「標準JCAメカニズム」は、セキュリティ・プロパティ・ファイルjava-home/lib/security/java.securityを介して静的に、またはjava.security.SecurityクラスのaddProvider()またはinsertProviderAt()メソッドを介して動的に、プロバイダを構成するために使用できます。

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

TLS接続では、ハンドシェーク中に一時的なDiffie-Hellmanの(DH)キーを内部的に使用できます。 SunJSSEプロバイダは、TLSハンドシェーク時のエフェメラルDHキー・サイズの強度をカスタマイズするための柔軟なアプローチを提供します。

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

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

次の表は、システム・プロパティjdk.tls.ephemeralDHKeySizeに指定可能な各値の許容可能な最小および最大DHキー・サイズをまとめたものです:

jdk.tls.ephemeralDHKeySizeの値 未定義 legacy matched 整数値(固定)
エクスポート可能なDHキー・サイズ 512 512 512 512
エクスポート不可能な匿名暗号化方式群 2048 768 2048 1024以上8192以下の64の倍数である有効な整数: エクスポート不可能な暗号化方式群に、指定した値の固定のephemeral DHキー・サイズ(ビット単位)が使われます。
認証証明書 2048 768 キーが1024ビット未満か2048ビットを超える場合を除き、キー・サイズは認証証明書と同じです。 キーが1024ビット未満の場合は、1024ビットのDHキーが使用されます。 キーが2048ビットを超える場合は、2048ビットのDHキーが使用されます。

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

固定キー・サイズは有効な整数プロパティ値で指定し、1024以上8192以下の64の倍数である必要があります。

最大フラグメント長ネゴシエーションのカスタマイズ(MFLN) Extension

より小さい最大フラグメント長をネゴシエートするために、クライアントはClientHelloメッセージにmax_fragment_length型の拡張を含めるオプションを持っています。 システム・プロパティjsse.enableMFLNExtensionを使用して、TLSのMFLN拡張を有効または無効にできます。

最大フラグメント長ネゴシエーション

メモリーの制限や帯域幅の制限により、制約されたTLSクライアントが最小のフラグメント長をネゴシエートすることが望ましい場合があります。 より小さい最大フラグメント長をネゴシエートするために、クライアントには、(拡張) ClientHelloメッセージにmax_fragment_length型の拡張子を含めるオプションがあります。 RFC 6066を参照してください。

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

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

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

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

システム・プロパティ 説明
jsse.enableMFLNExtension=true MFLN拡張機能を有効にします。 SSLParameters.getMaximumPacketSize()の戻り値が(212 + header-size)より小さい場合、最大フラグメント長のネゴシエーション拡張が有効になります。
jsse.enableMFLNExtension=false MFLN拡張機能を無効にします。

アルゴリズムでキー・セットを使用して暗号化可能なデータ量の制限

jdk.tls.keyLimitsセキュリティ・プロパティを使用して、アルゴリズムが特定のキー・セットで暗号化できるデータの量に制限を指定できます。 この制限に達すると、KeyUpdateポストハンドシェーク・メッセージが送信され、現在のキー・セットを更新するように要求します。 このセキュリティ・プロバイダは、TLS 1.3での対称暗号化にのみ使用できます。

このプロパティの構文は次のとおりです。

jdk.tls.keyLimits=KeyLimit { , KeyLimit }

KeyLimit:
AlgorithmName KeyUpdate Length

たとえば、次の例では、AES/GCM/NoPaddingアルゴリズムで237バイトを暗号化するとKeyUpdateメッセージが送信されるように指定します。

jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37

close_notifyアラートの受信時の送信の指定

jdk.tls.acknowledgeCloseNotifyシステム・プロパティがtrueに設定されている場合、クライアントまたはサーバーがclose_notifyアラートを受信すると、対応するclose_notifyアラートが送信され、接続は二重クローズされます。

TLS 1.2以前のバージョンでは、duplex-closeポリシーが使用されています。 しかし、TLS 1.3では、half-closeポリシーが使用されます。つまり、インバウンドおよびアウトバウンドのclose_notifyアラートは独立しています。 TLS 1.3にアップグレードする場合、アプリケーションがSSLEngine.closeInbound()またはSSLEngine.closeOutbound()メソッドの1つのみを使用してTLS接続をシャットダウンし、接続の両側で両方を使用しないと、予期しない動作が発生する可能性があります。 基礎となるTLS転送が二重クローズされていないときにアプリケーションが予期せずハングまたはタイムアウトした場合、このプロパティをtrueに設定する必要があります。

TLS接続が不要になった場合、クライアント・アプリケーションとサーバー・アプリケーションはそれぞれそれぞれの接続の両側を閉じる必要があります。

デフォルトの拡張機能の構成

TLS実装によっては、不明な拡張機能を正しく処理できないことがあります。 そのため、JDKで新しい拡張機能が導入されると、予期しない相互運用性の問題が発生する可能性があります。 2つのシステム・プロパティを使用すると、デフォルトの拡張機能をカスタマイズできます:

拡張機能が無効になっている場合、ハンドシェーク・メッセージで拡張機能は生成も処理もされません。

これらのシステム・プロパティの値は、カンマ区切りの標準TLS拡張名のリストです。 これらの名前のリストは、トランスポート・レイヤー・セキュリティ(TLS)の拡張を参照してください。 拡張名は大文字と小文字が区別され、不明な、サポートされていないスペルミスや重複した名前は無視されます。


ノート: jsse.enableMFLNExtensionjsse.enableSNIExtensionjsse.enableSNIExtensionなどの特定のTLS拡張を有効または無効にするシステム・プロパティが存在しますが、対応するシステム・プロパティであっても、jdk.tls.client.disableExtensionsまたはjdk.tls.server.disableExtensionsを使用して無効にすると、拡張は有効になりません。


OCSPによるX.509証明書失効ステータスの確認

トランスポート・レイヤー・セキュリティの(TLS)ハンドシェイク中にX.509証明書失効ステータスを確認するには、オンライン証明書ステータス・プロトコル(OCSP)を使用します。 クライアント主導型OCSPとOCSPステープリングを参照してください。

ハードウェア高速化およびスマート・カードのサポート

Java暗号化アーキテクチャ(JCA)は、暗号化、キー生成とキー合意およびメッセージ認証コード(MAC)アルゴリズム用のフレームワークと実装を提供するパッケージ・セットです。 SunJSSEプロバイダは、すべての暗号化操作にJCAのみを使用し、JCAによる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アプリケーションの存続期間の間、異なるスマートカードをスマートカード・リーダーに入れることができ、それらのスマートカードは異なるパスワードを使用して保護できます。

java.security.KeyStore.Builderクラスは、KeyStoreオブジェクトの構造と初期化データを抽象化します。 パスワードのプロンプト用にCallbackHandlerの使用をサポートし、そのサブクラスを使用して、アプリケーションに望まれる追加機能をサポートできます。 たとえば、Builderを実装して、個々のKeyStoreエントリを異なるパスワードで保護するようにすることが可能です。 その後、 javax.net.ssl.KeyStoreBuilderParametersクラスを使用し、これらのBuilderオブジェクトを1つ以上使用してKeyManagerFactoryを初期化できます。

NewSunX509と呼ばれる、SunJSSEプロバイダのX509KeyManager実装は、これらのパラメータをサポートしています。 複数の証明書が使用可能な場合は、適切なキーを使用する証明書を選択し、期限切れの証明書より有効な証明書を優先させます。

次の例に、PKCS#11キーストア(スマートカードを使用できる)とPKCS#12ファイルベース・キーストアの両方を使用するようJSSEに指示する方法を示します。

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暗号化方式群をサポートします。 次の暗号化方式群がサポートされていますが、デフォルトでは有効になっていません。

これらの暗号化方式群を使用できるようにするには、明示的に指定する必要があります。 詳細については、APIのドキュメントで、SSLEngine.setEnabledCipherSuites()およびSSLSocket.setEnabledCipherSuites()メソッドを参照してください。 その他のすべてのSSL/TLS暗号化方式群と同様、暗号化方式群がピアによってサポートされていない場合は、暗号化のネゴシエーション時に選択されません。 また、アプリケーションまたはサーバーが必要な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を使用するように構成されている必要があります。 Java SEでのKerberosの使用の詳細は、「Kerberos要件」のドキュメントを参照してください。

アプリケーションは、Java認証・承認サービス(JAAS)とKerberosログイン・モジュールを使用して、自身のKerberos資格を取得できます。 JDKは、Kerberosログイン・モジュールに付属しています。 JSSEでのKerberos暗号化方式群は、JAASプログラミングがある場合とない場合のJava Generic Security Services (Java GSS)を使用する方法と同様に、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を使用する方法の例は、「Java GSSチュートリアル」で説明されています。 Java GSS呼出しをJSSE呼出しに置き換えることにより、JSSEの使用例に適応できます。

JAASプログラミングありでKerberos暗号化方式群を使用するには、任意のインデックス名を使用できます。これは、アプリケーションが、インデックス名を使用してJAAS LoginContextを作成し、JSSE呼出しをSubject.doAs()またはSubject.doAsPrivileged()呼出しの内部にラップする役割を持つためです。 Java GSSおよびKerberosでJAASを使用する方法の例は、「Java GSSチュートリアル」で説明されています。 Java GSS呼出しをJSSE呼出しに置き換えることにより、JSSEの使用例に適応できます。

Kerberosを使用するようにJSSEアプリケーションを使用し、構成する場合の問題については、Java GSSチュートリアルの「トラブルシューティング」セクションを参照してください。

ピアのアイデンティティ情報

SSL接続のピアの識別情報を判別するには、次のクラスで、getPeerPrincipal()メソッドを使用します。

同様に、(ローカル・エンティティを識別するために)ピアに送信された識別情報を取得するには、これらのクラスで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 (個人情報交換構文標準)は、ユーザーの秘密キー、証明書、その他のシークレットおよびその他のアイテムのストレージまたは転送(あるいはその両方)のための移植可能な形式を指定します。 SunJSSEプロバイダは、PKCS12ファイルの読取りおよび書込みのためのPKCS12 java.security.KeyStore形式の完全な実装を提供します。 この形式は、Netscape/Mozilla、MicrosoftのInternet Explorer、OpenSSLなどほかのツールキットやアプリケーションでもサポートされ、キーと証明書をインポートおよびエクスポートします。 たとえば、これらの実装では、.p12ファイル名拡張子を使用してクライアント証明書およびキーをファイルにエクスポートできます。

SunJSSEプロバイダでは、PKCS12のキーストア・タイプを使用して、KeyStore APIを介してPKCS12キーにアクセスできます。 さらにkeytoolコマンドと、pkcs12に設定された-storetypeオプションを使用して、インストールされたキーおよび関連する証明書を表示できます。 keytoolの詳細は、「セキュリティ・ツール」を参照してください。

ノート: JKSストア形式とは異なり、PKCS#12ストアにアクセスするには、パスワードを指定する必要があります。

Server Name Indication (SNI)拡張

SNI拡張は、SSL/TLSプロトコルを拡張し、クライアントがハンドシェーク時に接続を試みるサーバー名を示す機能です。 サーバーはServer Name Indicationの情報を使って、特定のSSLSocketまたはSSLEngineインスタンスが接続を受け入れる必要があるかどうかを判定できます。 たとえば、単一の基礎となるネットワーク・アドレスで複数の仮想または名前ベースのサーバーがホストされている場合、サーバー・アプリケーションは、SNI情報を使用して、このサーバーが、クライアントがアクセスしようとしている正しいサーバーであるかどうかを判断できます。 このクラスのインスタンスは、サーバーによって、ホスト名などの特定のタイプの受け付け可能なサーバー名を確認するために使用できます。 詳細については、TLS拡張(RFC 6066)のセクション3を参照してください。

クライアント・アプリケーションの開発者は、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);

サーバー・アプリケーションの開発者はSNIMatcherクラスを使用して、サーバー名の表示を認識する方法を決定できます。 次の2つの例に、この機能を示します。

例1


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);

例2


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の動作の例を示しています。

SNI拡張を実装する新しいクラスの説明については、次を参照してください。

たとえば、「Server Name Indication (SNI)拡張の使用」を参照してください。

TLSアプリケーション層プロトコル・ネゴシエーション

JDK 8u251以降では、Application Layer Protocol Negotiation (ALPN)を使用すると、TLS接続用のアプリケーション・プロトコルをネゴシエートできます。「TLSアプリケーション・レイヤー・プロトコルのネゴシエーション」を参照してください。

Troubleshooting

このセクションにはJSSEのトラブルシューティングに関する情報が含まれます。 まず、一般的な構成の問題とそれらの解決方法を説明し、次に、役に立つデバッグ・ユーティリティについて説明します。

構成上の問題点

このセクションでは、JSSEの使用時に発生する可能性のある一般的な構成の問題について説明します。

ハンドシェーク時のCertificateException

問題: SSL接続のネゴシエーション中に、クライアントまたはサーバーがCertificateExceptionをスローします。

原因1: 一般に、リモート側がローカル側に不明な証明書を送信することが原因です。

解決法1: このタイプの問題をデバッグするもっともよい方法は、デバッグをオンにして(「デバッグ・ユーティリティ」を参照)、証明書のロード時およびネットワーク接続経由での証明書の受信時に観察することです。 多くの場合、間違ったトラスト・ファイルをロードしたため、受信した証明書がトラスト・メカニズムにとって不明です。 詳細については、次のセクションを参照してください。

原因2: システム・クロックが正しく設定されていません。 この場合、認識された時間が証明書の有効期間外になっている可能性があります。トラストストアからの有効な証明書と置き換えないかぎり、システムはこの証明書を無効とみなすため、例外をスローします。

解決法2: システム・クロックの時間を修正します。

java.security.KeyStoreException: TrustedCertEntry Not Supported

問題: 信頼できる証明書をPKCS12キーストアに格納しようとすると、java.security.KeyStoreException: TrustedCertEntry not supportedがスローされます。

原因: PKCS12キーストアへの信頼できる証明書の格納はサポートされていません。 PKCS12は、主に関連付けられた証明書チェーンによる秘密キーの配信に使用されます。 「信頼できる」証明書の概念はありません。 相互運用性の観点から、他のPKCS12ベンダーにも同じ制限があります。 MozillaやInternet Explorerなどのブラウザは、信頼できる証明書のみを含むPKCS12ファイルを受け付けません。

解決法: 信頼できる証明書の格納には、JKSキーストアを使用します。

実行時例外: 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コマンド行ユーティリティを使用して、キーストアと関連の内容を調べることです。

実行時例外: "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..."」を参照してください。)

問題2: DSAベースの証明書しかないサーバーのファイルにNetscape Navigatorや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

JSSEの最初のアクセスが遅い

問題: 最初のアクセスでJSSEが停止したように見えます。

原因: JSSEには乱数のセキュアなソースが必要です。 初期化には時間がかかります。

解決法: 別の乱数ジェネレータを使用するか、オーバーヘッドが通知されない場合は前もって初期化します。

SecureRandom sr = new SecureRandom();
sr.nextInt();
SSLContext.init(..., ..., sr);

java-home/lib/security/java.securityファイルには、SecureRandomのシード・データのソースを指定する方法もあります。 詳細は、ファイルの内容を参照してください。

HttpsURLConnectionクラスを使用するコードがJSSE 1.0.xでClassCastExceptionをスローする

問題: 次のコード(抜粋)は、JSSE 1.0.xのcom.sun.net.ssl.HttpsURLConnectionを使用して作成されたものです。

import com.sun.net.ssl.*;
...deleted...
HttpsURLConnection urlc = new URL("https://example.com/").openConnection();

JSSE 1.0.xで実行すると、このコードはjavax.net.ssl.HttpsURLConnectionオブジェクトを返し、ClassCastExceptionをスローします。

原因: デフォルトでは、HTTPS URLを開くとjavax.net.ssl.HttpsURLConnectionが作成されます。

解決法: 以前のリリースのJDK (リリース6以前)には、HTTPS URLの実装が付属していませんでした。 JSSE 1.0.x実装は、そのようなHTTPS URLハンドラを提供し、インストールガイドに、URLハンドラの検索パスを設定してJSSE 1.0.xのcom.sun.net.ssl.HttpsURLConnection実装を取得する方法が記載されています。

JDKでは、URLハンドラのデフォルトの検索パスにHTTPSハンドラがあります。 これは、javax.net.ssl.HttpsURLConnectionのインスタンスを返します。 java.protocol.handler.pkgs変数を使用して、以前のJSSE 1.0.x実装パスをURL検索パスの先頭に追加することにより、com.sun.net.ssl.HttpsURLConnectionを取得することもでき、前述のコードがキャスト例外をスローすることはなくなります。

次の例を参照してください。
% java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol YourClass
System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");

ClientHelloメッセージの送信後ソケットが切断される

問題: ソケットが接続を試み、ClientHelloメッセージを送信すると、ただちに切断されます。

原因: SSL/TLSサーバーの中には、理解できない形式や、サポートしていないプロトコル・バージョン番号でClientHelloメッセージを受信した場合、接続を切断するものがあります。

解決法: クライアント側で、有効なプロトコルの調整を試みてください。 これには、次のシステム・プロパティやメソッドの変更や呼び出しが含まれます。

下位互換性のために、一部のSSL/TLS実装(SunJSSEなど)は、「SSLv2 ClientHello」形式でカプセル化されたSSL/TLS ClientHelloメッセージを送信できます。 SunJSSEプロバイダはこの機能をサポートしています。 この機能を使用する場合は、必要に応じて「SSLv2Hello」を有効なプロトコル・リストに追加します。 (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、SSLv3、TLSv1、TLSv1.1およびTLSv1.2にしてください。) ステップ1から再度開始します。

ノート: 以前のバージョンにフォールバックすることは、通常、セキュリティ強度が弱いプロトコルにダウングレードすることを意味します。 本当に必要で、サーバーが上位のプロトコル・バージョンをサポートしていないことが確実にわかっている場合でないかぎり、フォールバック・スキームを使用することはお薦めしません。



ノート: 一部のサーバーはSSLv3無効化の過程でSSLv2Helloも無効にしていますが、それは、SSLv2Helloアクティブなクライアント(たとえばJDK 1.5/6)との通信が失敗することを意味します。 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を使用します。 デフォルトでは、Oracle JDKは標準拡張ClassLoaderを使用して、java-home/lib/ext/sunjce_provider.jarにあるSunJCEプロバイダをロードします。 ファイルが見つからないかロードできない場合、またはSunJCEプロバイダがProviderメカニズムから登録解除されており、JCEからの代替実装を利用できない場合、この例外がスローされます。

解決法: ファイルがロード可能であることをチェックしてSunJCEが使用可能であることを確認し、プロバイダがProviderインタフェースで登録されていることを確認します。 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コンソール、トレースおよびロギング」を参照してください。 問題の原因がjavax.net.ssl.SSLProtocolException: handshake alert: unrecognized_nameの場合、SNIのための仮想ホスト構成が正しくない可能性があります。 Apache HTTPサーバーを使用している場合、仮想ホストの構成については、「Name-based Virtual Host Support」を参照してください。 特に、<VirtualHost>ブロック内でServerNameディレクティブが正しく構成されていることを確認してください。

詳細については、次の情報を参照してください。

デバッグ・ユーティリティ

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アプリケーションは、デバッグのヘルプ情報が表示されると動作しなくなりますが、これはヘルプコードによりアプリケーションが終了するためです。

現在のオプション:

sslオプションとともに次のオプションを使用できます:

handshakeオプションによって生成されるメッセージは、次のオプションで拡張できます:

recordオプションによって生成されるメッセージは、次のオプションで拡張できます:

javax.net.debugプロパティ値は、allまたはsslを指定する必要があり、オプションでデバッグ指定子をその後に続けます。 1つまたは複数のオプションが使用できます。 オプションをセパレータで区切る必要はありませんが、コロン(:)やカンマ(,)などの区切り文字を使用すると読みやすくなります。 どのセパレータでも使用でき、オプション・キーワードの順序も重要ではありません。

このデバッグ情報の見方の説明は、ガイド「SSL/TLS接続のデバッグ」を参照してください。

次に、javax.net.debugプロパティの使用例を示します。

コード例

このセクションには次のコード例が含まれています。

セキュアでないソケットからセキュアなソケットへの変換

このセクションでは、JSSEを使って、セキュアでないソケット接続をセキュアなソケット接続に変換するソース・コードの例を説明します。 このセクションのコードは『Java SE 6 Network Security』(Marco Pistoiaほか著)から引用したものです。

まず、「SSLを使用しないソケットの例」で、セキュアでないソケットを使ってクライアントとサーバー間の通信を設定するサンプル・コードを示します。 次に、「SSLを使用するソケットの例」ではこのコードを変更し、JSSEを使用してセキュアなソケット通信を設定します。

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) { }

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接続のデバッグ」を参照してください。


サンプル・コードの場所

ほとんどのサンプル・コードは、このドキュメントと同じディレクトリのsamplesサブディレクトリに格納されています。 そのリンクから、すべてのサンプル・コード・ファイルとテキスト・ファイルのリストを表示できます。 このページでは、すべてのサンプル・コード・ファイルを取得するためにダウンロードできるZIPファイルのリンクもあり、このドキュメントをWeb経由で表示している場合に便利です。

次のセクションでは、サンプルについて説明します。 詳細については、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

samplecacertsトラスト・ストアのパスワードはchangeitです。 keytoolユーティリティを使用して、サンプルの独自の証明書を置き換えることができます。

Netscape NavigatorやMicrosoftのInternet Explorerなどのブラウザを使用して、ClassFileServerの例で提供されているサンプルのSSLサーバーにアクセスすると、ダイアログ・ボックスが開いて、証明書が認識されないというメッセージが表示されます。 これは、サンプル・プログラムで使用する証明書は自己署名付きのもので、テスト用にすぎないためです。 現在のセッションで証明書に同意できます。 SSLサーバーのテストが終了したあと、ブラウザを終了し、ブラウザの名前空間からテスト用証明書を削除します。

クライアント認証の場合、適切なディレクトリの別のduke証明書を使用できます。 公開キーおよび証明書も、samplecacertsファイルに格納されています。

SSLSocketClientの実行

SSLSocketClient.javaプログラムは、SSLSocketを使用するクライアントを作成し、HTTP要求を送信してHTTPSサーバーから応答を受け取る方法を示します。 このプログラムの出力は、https://www.verisign.com/index.htmlのHTMLソースです。

ファイアウォールの内側から、このプログラムを提供されたとおりに実行しないでください。 ファイアウォールの内側から実行すると、JSSEはファイアウォールを経由したwww.verisign.comへのパスを検出できないので、UnknownHostExceptionを受け取ります。 ファイアウォールの外側から実行できる同等のクライアントを作成するには、サンプル・プログラムSSLSocketClientWithTunnelingで示すように、プロキシ・トンネリングを設定します。

SSLSocketClientWithTunnelingの実行

SSLSocketClientWithTunneling.javaプログラムは、ファイアウォールの外側からセキュアなWebサーバーにアクセスするプロキシ・トンネリングの方法を示します。 このプログラムを実行するには、次のJavaシステム・プロパティに適切な値を設定する必要があります。

java -Dhttps.proxyHost=webproxy
-Dhttps.proxyPort=ProxyPortNumber
SSLSocketClientWithTunneling

ノート: -Dオプションによるプロキシ指定はオプションです。 webproxyは使用するプロキシ・ホスト名に、ProxyPortNumberは適切なポート番号に置き換えてください。

プログラムはhttps://www.verisign.com/index.htmlのHTMLソース・ファイルを返します。

SSLSocketClientWithClientAuthの実行

SSLSocketClientWithClientAuth.javaプログラムは、サーバーから要求された場合にキー・マネージャを設定し、クライアント認証を行う方法を示します。 このプログラムも、クライアントがファイアウォールの外側にはいないことを前提にしています。 SSLSocketClientWithTunnelingの例に従ってプログラムを変更すれば、ファイアウォールの内側から接続することもできます。

このプログラムを実行するには、ホスト、ポート、および要求されたファイル・パスの3つのパラメータを指定する必要があります。 前回の例を反映させるため、ホストにwww.verisign.com、ポート番号に443、要求されたファイル・パスにhttps://www.verisign.com/を設定して、このプログラムをクライアント認証なしで実行できます。 これらのパラメータを使用したときの出力が、Webサイトhttps://www.verisign.com/のHTMLソースです。

SSLSocketClientWithClientAuthを実行してクライアント認証を行うには、クライアント認証を要求するサーバーにアクセスする必要があります。 このサーバーには、サンプル・プログラムClassFileServerを使用できます。 これについては、次のセクションで説明します。

ClassFileServerの実行

ここでClassFileServerと呼ばれているプログラムは、ClassFileServer.javaClassServer.javaの2つのファイルで構成されています。

これらを実行するには、ClassFileServer.classを実行します。その際は次のパラメータが必要です。


ノート: TLSおよびtrueパラメータはオプションです。 それらを省略した場合は、TLSではない通常のファイルサーバーを認証なしで使用し、何も起こらないことを示します。 これは、一方の側(クライアント)がTLSとネゴシエーションを行おうとしても、もう一方の側(サーバー)は行おうとしないため、通信ができないからです。



ノート: サーバーはGET /path_to_fileの形式でGET要求を期待します。


ClassFileServerによるSSLSocketClientWithClientAuthの実行

サンプル・プログラムSSLSocketClientWithClientAuthおよび ClassFileServerを使用して、認証済の通信を設定できます。この通信では、クライアントとサーバーが相互に認証します。 サンプルのプログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウまたはコマンド・プロンプト・ウィンドウから両方を実行することもできます。 クライアントとサーバーの両方を設定するには、次を実行します。

  1. ClassFileServerの実行」に示すように、ClassFileServerプログラムを1台のマシンやターミナル・ウィンドウから実行します。
  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.net.URLクラスのドキュメントを参照してください。

JSSEでダウンロードできるサンプルには、HTTPS接続の作成方法を示すサンプル・プログラムが2つ含まれています。 これらのサンプル・プログラム(URLReader.javaURLReaderWithOptions.java)は、どちらもsamples/urlsディレクトリにあります。

URLReaderの実行

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の実行

URLReaderWithOptions.javaプログラムは基本的にはURLReader.javaプログラムと同じですが、実行時にプログラムの引数として次のシステム・プロパティのどれか、または全部をオプションで入力できる点が異なります。

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のサンプルに基づいており、基本的にはカスタムRMIソケット・ファクトリをインストールして使用するように変更された「Hello World」サンプルです。

Java RMIの詳細は、Java RMIドキュメントを参照してください。 このWebページは、Java RMIのチュートリアルとJava RMIに関する他の情報を示します。

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の実行

SSLEngineSimpleDemoは単純なアプリケーションであり、I/Oおよびスレッドの発行を単純化してSSLEngineの操作に重点を置いています。 このアプリケーションは、一般的なByteBufferオブジェクトによってSSL/TLSメッセージを交換する2つのSSLEngineオブジェクトを作成します。 1つのループがすべてのエンジン操作を順番に実行して、セキュアな接続の確立(ハンドシェーク)、アプリケーション・データの転送、およびエンジンのクローズを示します。

SSLEngineResultは、SSLEngineの現在の状態に関して多くの情報を提供します。 この例では、すべての状態を調べているわけではありません。 I/Oおよびスレッドの発行を適度に単純化しているため本番稼動環境に適した例ではありませんが、SSLEngineの全体的な機能の説明に有用です。

JSSEで使用するキーストアの作成

このセクションでは、keytoolユーティリティを使用して、JSSEでの使用に適した単純なJKSキーストアを作成する方法を説明します。 まずキーストア内に(公開キーおよび秘密キーを持つ) keyEntryを作成し、トラストストア内に対応するtrustedCertEntry (公開キーのみ)を作成します。 クライアント認証の場合、クライアントの証明書に対して同様の処理に従う必要があります。


ノート: PKCS12での信頼できるアンカーおよび秘密キーの格納は、JDK 8以降でサポートされています。



ノート: ここでは、各ステップに関する詳しい解説は省略します。 詳細は、「Solaris、LinuxまたはmacOS」またはMicrosoft Windowskeytoolドキュメントを参照してください。


ユーザー入力は太字で示します。

  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
    
    Enter key password for <duke>
    (RETURN if same as keystore password):  <CR>
    
    
  2. キーストアを調べます。 エントリの型はkeyEntryで、これは、このエントリに秘密キーが関連付けられていることを示します)。

    % keytool -list -v -keystore keystore
    
    Enter keystore password:  password
    
    Keystore type: jks
    Keystore provider: SUN
    
    Your keystore contains 1 entry
    
    Alias name: duke
    Creation date: Dec 20, 2001
    Entry type: keyEntry
    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: 3c22adc1
    Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
    Certificate fingerprints:
    MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
    SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
    
    
  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-----
    MIICXjCCAccCBDwircEwDQYJKoZIhvcNAQEEBQAwdjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
    MRIwEAYDVQQHEwlQYWxvIEFsdG8xHzAdBgNVBAoTFlN1biBNaWNyb3N5c3RlbXMsIEluYy4xFjAU
    BgNVBAsTDUphdmEgU29mdHdhcmUxDTALBgNVBAMTBER1a2UwHhcNMDExMjIxMDMzNDI1WhcNMDEx
    MjI4MDMzNDI1WjB2MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0
    bzEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywgSW5jLjEWMBQGA1UECxMNSmF2YSBTb2Z0d2Fy
    ZTENMAsGA1UEAxMERHVrZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1loObJzNXsi5aSr8
    N4XzDksD6GjTHFeqG9DUFXKEOQetfYXvA8F9uWtz8WInrqskLTNzwXgmNeWkoM7mrPpK6Rf5M3G1
    NXtYzvxyi473Gh1h9k7tjJvqSVKO7E1oFkQYeUPYifxmjbSMVirWZgvo2UmA1c76oNK+NhoHJ4qj
    eCUCAwEAATANBgkqhkiG9w0BAQQFAAOBgQCRPoQYw9rWWvfLPQuPXowvFmuebsTc28qI7iFWm6BJ
    TT/qdmzti7B5MHOt9BeVEft3mMeBU0CS2guaBjDpGlf+zsK/UUi1w9C4mnwGDZzqY/NKKWtLxabZ
    5M+4MAKLZ92ePPKGpobM2CPLfM8ap4IgAzCbBKd8+CMp8yFmifze9Q==
    -----END CERTIFICATE-----
    
    

    または、-certreqを使用して証明書署名リクエスト(CSR)を生成し、署名のために認証局(CA)に送信することもできます。keytoolドキュメントの"CAからの署名付き証明書のリクエスト" (「Solaris、LinuxまたはmacOS」またはWindows)の項を参照してください。

  4. 証明書を新しいトラスト・ストアにインポートします。

    % keytool -import -alias dukecert -file duke.cer -keystore truststore
    Enter keystore password:  trustword
    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: 3c22adc1
    Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
    Certificate fingerprints:
    MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
    SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
    Trust this certificate? [no]:  yes
    Certificate was added to keystore
    
    
  5. トラストストアを調べます。 エントリの型はtrustedCertEntryで、これは、秘密キーをこのエントリで使用できないことを示します。 これは、このファイルがKeyManagerのキーストアとして適切でないことも意味します。

    % keytool -list -v -keystore truststore
    Enter keystore password:  trustword
    
    Keystore type: jks
    Keystore provider: SUN
    
    Your keystore contains 1 entry
    
    Alias name: dukecert
    Creation date: Dec 20, 2001
    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: 3c22adc1
    Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001
    Certificate fingerprints:
    MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0
    SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74
    
    
  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拡張の理解を必要とするユース・ケースのリストです。

一般的なサーバー側使用例

次は、サーバー・アプリケーションを開発するためにSNI拡張の理解を必要とするユース・ケースのリストです。

仮想インフラストラクチャの操作

このセクションでは、仮想インフラストラクチャ内からServer Name Indication (SNI)拡張を使用する方法について説明します。 ここでは、ソケットからのClientHelloメッセージのパーサーの作成方法を示し、SSLSocketおよびSSLEngineを使用した仮想サーバー・ディスパッチャの例を示し、SNI拡張を使用できない場合に何が発生するかを説明して、フェールオーバーSSLContextを作成する方法を示します。

ClientHelloパーサーの準備

アプリケーションはソケットからのClientHelloメッセージを解析するAPIを実装する必要があります。 次の例に、これらの機能を実行できるSSLCapabilitiesクラスとSSLExplorerクラスを示します。

SSLCapabilities.javaはハンドシェーク中にSSL/TLSセキュリティ機能をカプセル化します(つまり、SSL/TLSハンドシェークで受け付けられる暗号化方式群のリスト、レコード・バージョン、helloバージョン、サーバー名表示)。 それは、SSLExplorer.explore()メソッドによって、SSL/TLS接続のネットワーク・データを調べることによって取得できます。

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の内容の妥当性をチェックしません。 レコード形式がSSL/TLS仕様に準拠していない場合、またはハンドシェークの起動後に、explore()メソッドが呼び出された場合、メソッドはIOExceptionをスローすることがあり、ネットワーク・データを生成できません。 そのような場合、SSL/TLS接続のネゴシエーションに使用されませんが、適切な警告メッセージで接続を閉じるフェールオーバー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();
}

付録A: 標準名

JDK Security APIは、アルゴリズム、証明書およびキーストアのタイプの一連の標準名を必要とし、これらを使用します。 以前にこの付録Aの仕様および他のセキュリティ仕様(JCA、CertPath)にあった仕様名は、標準名のドキュメントにまとめられました。 特定のプロバイダの情報は、「Oracle Provider Documentation」にあります。

付録B: プロバイダのプラグイン可能性

JSSEは完全にプラガブルであり、サード・パーティのJSSEプロバイダの使用には何の制限もありません。

付録C: TLS再ネゴシエーションの問題

2009年秋に、SSL/TLSプロトコルの問題が見つかりました。 IETF TLS Working Groupによってプロトコルの修正が開発され、JDKの現行バージョンにはこの修正が含まれています。 「Transport Layer Security (TLS)再ネゴシエーションの問題」ページでは、このプロトコル修正を含まない古い実装と通信する際の相互運用性の問題とともに、状況をより詳細に説明しています

付録D: シグネチャ・スキーム

次の表に、TLS接続のデジタル・シグネチャで使用されるアルゴリズムで、IANA TLSレジストリの「SignatureSchemeセクション」にも定義されている標準のシグネチャ・スキーム名を示します。

シグネチャ・スキーム 仕様
ecdsa_secp256r1_sha256 RFC 8446
ecdsa_secp384r1_sha384 RFC 8446
ecdsa_secp521r1_sha512 RFC 8446
ecdsa_sha1 RFC 8446
ed25519 RFC 8446
ed448 RFC 8446
rsa_pkcs1_sha1 RFC 8446
rsa_pkcs1_sha256 RFC 8446
rsa_pkcs1_sha384 RFC 8446
rsa_pkcs1_sha512 RFC 8446
rsa_pss_pss_sha256 RFC 8446
rsa_pss_pss_sha384 RFC 8446
rsa_pss_pss_sha512 RFC 8446
rsa_pss_rsae_sha256 RFC 8446
rsa_pss_rsae_sha384 RFC 8446
rsa_pss_rsae_sha512 RFC 8446

Copyright © 1993, 2025, Oracle and/or its affiliates. All rights reserved.