このガイドでは次のトピックについて説明します人妖 女優。
はじめに 特長と利点 JSSE標準API SunJSSEプロバイダ 関連項目 JREインストール・ディレクトリ 用語と定義 Secure Sockets Layer (SSL)プロトコルの节录 SSLを使用することの利点 SSLのしくみ JSSEクラスとインタフェース コア・クラスとインタフェース SocketFactoryおよびServerSocketFactoryクラス SSLSocketFactoryおよびSSLServerSocketFactoryクラス SSLSocketおよびSSLServerSocketクラス SSLEngineクラス SSLSessionおよびExtendedSSLSessionインタフェース HttpsURLConnectionクラス サポート・クラスとインタフェース SSLContextクラス TrustManagerインタフェース TrustManagerFactoryクラス X509TrustManagerインタフェース X509ExtendedTrustManagerクラス KeyManagerインタフェース KeyManagerFactoryクラス X509KeyManagerインタフェース X509ExtendedKeyManagerクラス TrustManagerとKeyManagerの関係 二次サポート・クラスおよびインタフェース SSLParametersクラス 暗号化神气群の優先順位 SSLSessionContextインタフェース SSLSessionBindingListenerインタフェース SSLSessionBindingEventクラス HandShakeCompletedListenerインタフェース HandShakeCompletedEventクラス HostnameVerifierインタフェース X509Certificateクラス AlgorithmConstraintsインタフェース StandardConstantsクラス SNIServerNameクラス SNIMatcherクラス SNIHostNameクラス JSSEのカスタマイズ Transport Layer Security (TLS)再ネゴシエーションの問題 この問題を解決するためのフェーズ別アプローチ フェーズ2修正の説明 SSL/TLS再ネゴシエーションに対する侧目法式と代替法式 実装の詳細 フェーズ1修正の説明 SSL/TLS再ネゴシエーションにおける安全でないサーバー証明書の変更の許可 ハードウェア高速化およびスマート・カードのサポート スマートカードをキーストアおよびトラストストアとして使用するためのJSSEの構成 複数の動的キーストア Kerberos暗号化神气群 Kerberos要件 ピアのアイデンティティ情報 セキュリティ・マネージャ その他のキーストア神气(PKCS12) Server Name Indication (SNI)拡張 トラブルシューティング 構成上の問題点 デバッグ・ユーティリティ コード例 セキュアでないソケットからセキュアなソケットへの変換 JSSEサンプル・コードの実行 JSSEで使用するキーストアの作成 Server Name Indication (SNI)拡張の使用 付録A: 標準名 付録B: プロバイダのプラグイン可能性 はじめにネットワークを通じてやり取りされるデータには、意図された受信者之外の东说念主も、簡単にアクセスできます。データにパスワードやクレジット・カード番号などの個情面報が含まれる場合、権限のない者がデータを融合できないよう、手艺を講じる必要があります。また、意図的であるかどうかにかかわらず、通讯中にデータが変更されていないことを確認することも蹙迫です。Secure Sockets Layer (SSL)およびTransport Layer Security (TLS)は、ネットワークを通じたデータの送信時に、データの機密性および整合性を保護するために設計されたプロトコルです。
Java Secure Socket Extension (JSSE)により、セキュアなインターネット通讯が可能になります。これにより、JavaバージョンのSSLおよびTLSプロトコルのフレームワークおよび実装が提供されます。また、データ暗号化、サーバー認証、メッセージの整合性の他、オプションでクライアント認証の機能が含まれます。JSSEを使用すると、開発者はHTTP、Telnet、FTPなど、TCP/IP上のアプリケーション・プロトコルを実行するクライアントとサーバーの間で、セキュアなデータのやり取りを実現できます。SSLの节录については、「Secure Sockets Layer (SSL)プロトコルの节录」を参照してください。
JSSEは、基盤となる複雑なセキュリティ・アルゴリズムやハンドシェーク・メカニズムを综合化することにより、識別するのが難しく、しかし危険なセキュリティ上の短处が生まれるリスクを最小限に抑えます。また、開発者がそれをアプリケーションに径直統合できる構築ブロックとして使用すると、アプリケーション開発が簡単になります。
JSSEは、アプリケーション・プログラミング・インタフェース(API)フレームワークと、そのAPIの実装を提供します。JSSE APIは、java.securityおよびjava.netパッケージによって定義されたコア・ネットワークおよび暗号化サービスを補い、拡張されたネットワーク・ソケット・クラス、トラスト・マネージャ、キー・マネージャ、SSLコンテキストおよびソケット作成動作をカプセル化するソケット・ファクトリのフレームワークを提供します。SSLSocketクラスはブロック入出力モデルに基づいているため、Java Development Kit (JDK)には、実装で独自の入出力メソッドを選択できるようにするために非ブロックSSLEngine クラスが含まれます。
JSSE APIでは、SSLバージョン2.0および3.0の他、TLS バージョン 1.0をサポートできます。これらのセキュリティ・プロトコルは、时常の两边向のストリーム・ソケットをカプセル化し、JSSE APIは認証、暗号化および整合性保護の透過的なサポートを追加します。JDKに付属しているJSSE実装は、SSL 3.0、TLS (1.0、1.1および1.2)およびDTLS(バージョン1.0および1.2)をサポートしています。SSL 2.0は実装しません。
JSSEはJava SE プラットフォームのセキュリティ・コンポーネントで、Java Cryptography Architecture (JCA)フレームワークの至るところで見られる同じ設計方針に基づいています。暗号化に関するセキュリティ・コンポーネントのこのフレームワークにより、実装の孤独性と、可能な場合にはアルゴリズムの孤独性を実現できます。JSSEはJCAフレームワークによって定義された暗号化サービス・プロバイダを使用します。
Java SE プラットフォームの他のセキュリティ・コンポーネントには、Java認証・承認サービス(JAAS)およびJavaセキュリティ・ツールがあります。JSSEはJCAと同じ想法およびアルゴリズムを多く含んでいますが、単純なストリーム・ソケットAPIの下でこれらを自動的に適用します。
JSSE APIは、その他のSSL/TLSプロトコルと公開鍵インフラストラクチャ(PKI)実装をシームレスにプラグインできる設計になっています。開発者が、リモート・ホストの信頼性やリモート・ホストに送信する認証鍵データを決定するロジックを提供することもできます。
特長と利点JSSEには次のような蹙迫な特長があります。
JDKの標準のコンポーネントとして含まれている 拡張可能なプロバイダ・ベースのアーキテクチャ 100% Pure Javaに実装される SSLバージョン2.0と3.0およびTLS 1.0以降のAPIをサポートし、SSL 3.0およびTLS 1.0を実装する セキュアなチャネルを作成するためにインスタンス化可能なクラスを含む(SSLSocket、SSLServerSocket、およびSSLEngine) セキュアな通讯を開始し、検証するのに使用されるSSLハンドシェーク機能の一部として、暗号群ネゴシエーションをサポートする 时常のSSLハンドシェーク機能の一部として、クライアントとサーバーの認証をサポートする SSLプロトコルでカプセル化されたHTTPをサポートし、これにより、HTTPSを使用するWebページなどのデータにアクセスできる メモリー常駐型のSSLセッションを搞定するためのサーバー・セッション搞定APIを提供する 表1に示すものを含む、暗号化神气群で一般的に使用される複数の暗号化アルゴリズムをサポートする 表1: JSSEで把握できる暗号化機能 暗号化アルゴリズム 脚注1 暗号化処理 鍵の長さ(ビット) Rivest Shamir Adleman (RSA) 認証と鍵交換 512以上 Rivest Cipher 4 (RC4) バルク暗号化 128 128 (40が有効) データ暗号化標準(DES) バルク暗号化 64 (56が有効) 64 (40が有効) トリプルDES (3DES) バルク暗号化 192 (112が有効) Advanced Encryption Standard (AES) バルク暗号化 256 脚注2 128 Diffie-Hellman (DH) 鍵合意 1024 512 デジタル签字アルゴリズム(DSA) 認証 1024脚注1 SunJSSE実装では、そのすべての暗号化アルゴリズムでJCAを使用します。
脚注2 AES_256を使用する暗号化神气群では、Java暗号化拡張(JCE)の強度が無制限の管轄ポリシー・ファイルがインストールされている必要があります。「Java SEダウンロード・ページ」を参照してください。
JSSE標準APIJSSE標準APIは、javax.netおよびjavax.net.sslパッケージで把握でき、次を提供します。
セキュアなソケットおよびサーバー・ソケット。 SSL/TLSデータのストリームを生成および消費する非ブロック・エンジン(SSLEngine)。 ソケット、サーバー・ソケット、SSLソケット、およびSSLサーバー・ソケットを作成するファクトリ。ソケット・ファクトリを使用すると、ソケットの作成および構成動作をカプセル化できます。 セキュアなソケット・ファクトリとエンジンのファクトリとして動作するセキュアなソケット・コンテキストを表すクラス。 X.509固有のキー・マネージャやトラスト・マネージャなどの鍵およびトラスト・マネージャ・インタフェース、およびそれらのインタフェースを作成するために使用可能なファクトリ。 セキュアなHTTP URL接続用のクラス(HTTPS)。 SunJSSEプロバイダOracleのJava SEの実装には、SunJSSEという名前のJSSEプロバイダが含まれており、これはあらかじめインストールされ、JCAに登録されています。このプロバイダが提供する暗号化サービスは次のとおりです。
SSL 3.0およびTLS 1.0セキュリティ・プロトコルの実装。 もっとも一般的なSSLおよびTLS暗号化神气群の実装で、認証、鍵合意、暗号化および整合性保護の組合わせを含みます。 標準JCAキーストアから適切な認証鍵を選択するX.509ベースのキー・マネージャの実装。 証明書チェーン・パスを検証する規則を実装する、X.509ベースのトラスト・マネージャの実装。 JCAキーストア型「pkcs12」としてPKCS12を実装。PKCS12の信頼できるアンカーの格納はサポートされていません。ユーザーは、Javaキーストア(JKS)神气で信頼できるアンカーを格納し、PKCS12神气で深重鍵を保存してください。このプロバイダの詳細は、Oracleプロバイダ・ドキュメントの「SunJSSE」セクションで説明されています。
関連項目次のリストにはオンライン・ドキュメントのリンクと、関連サブジェクトの文書名を示しています。
JSSE APIドキュメント javax.netパッケージ javax.net.sslパッケージ javax.security.certパッケージ Java SEのセキュリティ Java SEセキュリティ・ドキュメントの索引ページ Java SEセキュリティのホーム・ページ JavaチュートリアルのJava SEのセキュリティ機能トレール Java PKIプログラマーズ・ガイド Java 2プラットフォーム・セキュリティの詳細、第2版: アーキテクチャ、API設計および実装 暗号化 暗号化とセキュリティに関するページ、Ronald L. Rivest博士著(保守されなくなりました) 『Applied Cryptography, Second Edition』(Bruce Schneier著)、John Wiley and Sons, Inc.、1996年 『Cryptography Theory and Practice』(Doug Stinson著)、CRC Press, Inc.、1995年2005年発行第3版。 『Cryptography & Network Security: Principles & Practice』(William Stallings著)、Prentice Hall、1998年。2010年発行第5版。 Secure Sockets Layer (SSL) SSLプロトコル・バージョン3.0インターネット・ドラフト TLSプロトコル・バージョン1.0 RFC HTTP Over TLS RFC 『SSL and TLS: Designing and Building Secure Systems』(Eric Rescorla著)、Addison Wesley Professional、2000年 『SSL and TLS Essentials: Securing the Web』(Stephen Thomas著)、John Wiley and Sons, Inc.、2000年。 『Java 2 Network Security』、第2版(Marco Pistoia,、Duane F Reller、Deepak Gupta、Milind Nagnur、Ashok K Ramani著)、Prentice Hall、1999年。 米国の暗号化战术 米国商務省: コンピュータ・システムの寰球战术 連邦情報処理標準出书物(FIPS PUBS): 米国暗号化輸出規制(改訂版): _controls/regs_1_00.html Java Runtime Environment (JRE)インストール・ディレクトリこのドキュメント整体で使われているjava-home変数プレースホルダは、Java Runtime Environment (JRE)がインストールされているディレクトリを表します。このディレクトリは、実行しているJSSEにJDKがインストールされているか、インストールされていないかに基づいて決定されます。JDKにはJREが含まれていますが、ファイル階層の異なるレベルにあります。
様々なインストールのjava-homeのデフォルトの場所を確認するには、表2を参照してください。
表2: JREインストール・ディレクトリ オペレーティング・システム JDK JRE Solaris/Linux ~/jdk1.8.0/jre ~/jre1.8.0 Windows C:\jdk1.8.0\jre C:\jre1.8.0注: パス名内のチルド(~)は、Solaris、LinuxまたはMac OS Xオペレーティング・システムの現在のユーザーのホーム・ディレクトリを表します。
用語と定義このドキュメントでは、暗号化に関するいくつかの用語が使用されています。このセクションでは、こうした用語を定義します。
認証通讯している相手側の識別情報を確認するプロセスです。
暗号化神气群暗号化パラメータの組合わせで、認証、鍵合意、暗号化および整合性保護に使用するセキュリティ・アルゴリズムおよび鍵のサイズを定義します。
証明書デジタル签字付きの文で、あるエンティティ(东说念主や会社など)の識別情報および公開鍵の实验を保証します。証明書は、我方签字されるか証明書発行局(CA)(他のエンティティのために有効な証明書を発行する信頼されているエンティティ)によって発行されます。よく知られているCAにはVeriSign、Entrust、およびGTE CyberTrustがあります。X509は証明書の一般的な神气で、JDKのkeytoolで搞定できます。
暗号化ハッシュ関数データの大肆のブロックから比較的小さな固定サイズのビットの笔墨列(ハッシュと呼ばれる)を生成するために使われるアルゴリズム。暗号化ハッシュ関数はチェックサムに似ており、3つの主な特点があります。一场所の関数であるため、ハッシュからオリジナルデータを生成することはできません。オリジナルデータをわずかに変更しても、ハッシュでは大きな変更になります。暗号化鍵は必要ありません。
暗号化サービス・プロバイダ短縮形としてプロバイダとだけ呼ばれることもあり、Java暗号化アーキテクチャ(JCA)ではそれを、特定の暗号化アルゴリズムの1つまたは複数のエンジン・クラスを実装するパッケージ(または一連のパッケージ)と定義しています。エンジン・クラスは、具体的な実装のない综合的な法式で暗号化サービスを定義します。
復号化「暗号化/復号化」を参照してください。
デジタル签字デジタル签字とは、手書きの签字のデジタル版です。これは、ネットワークで伝送されるデータが、それを送信したと主張する东说念主物からのものであり、送信中にデータが変更されていないことを保証するものです。たとえば、RSAベースのデジタル签字を計算するには、まずデータの暗号化ハッシュを計算し、次に送信者の非公開鍵でハッシュを暗号化します。
暗号化/複合化暗号化は複雑なアルゴリズムを使用して、元のメッセージ(クリアテキスト)を、復号化しないかぎり、その实验を融合できないエンコードされたメッセージ(暗号テキスト)に変換するプロセスです。復号化とは、暗号テキストからクリアテキストを生成する逆のプロセスです。
データの暗号化および復号化に使用するアルゴリズムは一般に、深重鍵(対称)暗号化と公開鍵(非対称)暗号化の2つのカテゴリに分けられます。
ハンドシェーク・プロトコル2つのソケット同士が新しいセッションや既存のセッションの使用に承诺するネゴシエーションのフェーズです。ハンドシェーク・プロトコルは、レコード・プロトコルを介して交換される一連のメッセージです。ハンドシェークの終了時に、セッションの接続に固有の暗号化鍵や、整合性を保護するための鍵が、鍵合意による深重に基づいて新たに生成されます。
鍵合意二者が協力して共通鍵を確立するための法式です。それぞれの側が一定のデータを生成して交換します。そのあと、2つのデータが組み合わされて、1つの鍵が生成されます。適正な非公開初期化データを保捏しているユーザーのみが、最終的な鍵を赢得できます。Diffie-Hellman (DH)は、一般的な鍵合意アルゴリズムの一例です。
鍵交換鍵を交換する法式です。一方の側が深重鍵を生成し、標準的にはRSAにより、ピアの公開鍵を使用して暗号化します。データがピアに送信され、ピアは対応する深重鍵を使用して鍵を復号化します。
キー・マネージャ/トラスト・マネージャキー・マネージャとトラスト・マネージャは、それぞれの鍵データにキーストアを使用します。キー・マネージャはキーストアを搞定し、ユーザーを他のユーザーに対して承認する場合に使用するなど必要に応じて、他のユーザーに公開鍵を提供します。トラスト・マネージャは、搞定するトラストストアの情報に基づいて、トラストの対象者を決定します。
キーストア/トラストストアキーストアは、鍵データのデータベースです。鍵データにはさまざまな用途があり、それには認証やデータ整合性も含まれます。把握できるキーストアには様々なタイプがあり、その中にはPKCS12やOracleのJKSも含まれます。
一般に、キーストア情報は、鍵エントリと信頼される証明書エントリ2つのカテゴリに分類できます。鍵エントリはエンティティの識別情報とその深重鍵から構成されており、様々な暗号化の想法で使用できます。これとは対照的に、信頼される証明書のエントリには、公開鍵とそのエンティティの識別情報しか含まれていません。したがって、javax.net.ssl.KeyManagerの場合など、深重鍵が必要な場合は、信頼される証明書エントリを使用することはできません。JKSのJDK実装では、キーストアに鍵のエントリと、信頼される証明書エントリの両方を含めることができます。
トラストストアとは、トラストの対象を決めるときに使用するキーストアです。すでに信頼しているエンティティからデータを受け取る場合、およびそのエンティティが発信元を名乗るエンティティであることを確認できる場合は、データは実際にそのエンティティから届いたものであると仮定できます。
ユーザーがそのエンティティを信頼する場合にのみ、エントリをトラストストアに追加する必要があります。ユーザーは、鍵のペアを生成するか、証明書をインポートすることにより、そのエントリにトラストを与えます。トラストストア内のすべてのエントリは信頼されたエントリとみなされます。
2つの異なるキーストア・ファイルを捏つと便利な場合があります。1つは鍵エントリのみのファイル、もう1つはCA証明書を含む信頼された証明書エントリを含むファイルです。前者には機密性のある情報が含まれますが、後者には含まれません。単独のキーストア・ファイルではなく、2つのファイルを使用すると、独自の証明書(および対応する深重鍵)と他の証明書を論理的に区別した明確な分手が提供されます。深重鍵の保護を強化するには、アクセスが制限されたキーストアにそれらを保存し、必要に応じて、より公的にアクセスできるキーストアで信頼される証明書を提供することもできます。
メッセージ認証コード(MAC)信頼できない媒体に送信または格納された情報の整合性を、深重鍵に基づいてチェックする法式を提供します。时常、MACは深重鍵を共有する2つの事主間で、お互いが送信する情報を検証するために使用されます。
暗号化ハッシュ機能に基づくMACメカニズムは、HMACと呼ばれます。HMACは、共有する深重鍵と組み合せて、Secure Hash Algorithm (SHA-256)などの暗号化ハッシュ関数とともに使用できます。HMACについては、RFC 2104で規定されています。
公開鍵暗号化2つの鍵を生成する暗号化アルゴリズムを使用する鍵暗号化システムです。一方の鍵は公開されますが、他方は深重のままです。公開鍵と非公開鍵では、逆の暗号化処理がなされ、一方の鍵で暗号化したものを他方の鍵で復号化します。公開鍵暗号化は、非対称暗号化とも呼ばれます。
レコード・プロトコルすべてのデータ(アプリケーション・レベルであるかハンドシェーク・プロセスの一部であるかに関係なく)を孤独したデータのレコードにパッケージ化するプロトコルで、TCPストリーム・ソケットがアプリケーション・バイト・ストリームをネットワーク・パケットに変換するのとよく似ています。個々のレコードは、現在の暗号化鍵と整合性保護鍵によって保護されます。
深重鍵暗号化データの暗号化と復号化に同じ鍵を使用する暗号化アルゴリズムを使用する暗号化システム。深重鍵暗号化は対称暗号化とも呼ばれます。
セッション認証されたピア識別情報、暗号化神气群、鍵合意の深重を含む名前付きの状態情報のコレクションで、セキュアなソケット・ハンドシェークを通じてネゴシエーションが行われ、複数のセキュアなソケット・インスタンス間で共有できます。
トラスト・マネージャ「キー・マネージャ/トラスト・マネージャ」を参照してください。
トラストストア「キーストア/トラストストア」を参照してください。
Secure Sockets Layer (SSL)プロトコルの节录Secure Sockets Layer (SSL)は、Webで暗号化を実装する場合にもっともよく使用されるプロトコルです。SSLは、ネットワークでセキュアな通讯を行うために暗号化プロセスを組み合わせて使用します。このセクションでは、SSLおよびSSLが使用する暗号化プロセスについて簡単に説明します。
SSLは、インターネット通讯で使用される標準的なTCP/IPソケットプロトコルをセキュアに拡張します。表3に示すように、Secure Sockets Layerは標準TCP/IPプロトコル・スタックのトランスポート層とアプリケーション層の間に追加されます。SSLとともにもっともよく使用されるアプリケーションは、インターネットWebページ用のプロトコルであるHypertext Transfer Protocol (HTTP)です。この他にも、Net News Transfer Protocol (NNTP)、Telnet、Lightweight Directory Access Protocol (LDAP)、Interactive Message Access Protocol (IMAP)、File Transfer Protocol (FTP)などのアプリケーションがあり、同様にSSLとともに使用します。
注: 現在のところ、セキュアなFTPの標準は存在しません。
表3: SSLによるTCP/IPプロトコル・スタック TCP/IPの層 プロトコル アプリケーション層 HTTP、NNTP、Telnet、FTPなど Secure Sockets Layer SSL トランスポート層 TCP インターネット層 IPSSLは1994年にNetscape社によって開発され、インターネットの寰宇で使用されるようになると、標準的な存在になりました。現在では、国際的な標準化機構であるInternet Engineering Task Force (IETF)が搞定しています。IETFはSSLの称号をTransport Layer Security (TLS)に変更し、1999年1月に首先の仕様のバージョン1.0をリリースしました。TLS 1.0は、SSLの最新バージョン3.0を少しだけ変更したものです。SSL 3.0とTLS 1.0にはほとんど違いがありません。TLS 1.1は2006年4月にリリースされ、TLS 1.2は2008年8月にリリースされました。ただし、これらの更新されたバージョンはTLS 1.0やSSL 3.0ほど広くサポートされていません。
SSLを使用することの利点次の3つの原理から、機密情報をネットワークで送信する際に危険が伴う場合があります。
通讯相手のエンティティが、実際には必ずしも想定する相手とはかぎらない。 ネットワーク上のデータは傍受されることがあり、権限のない局外人(場合によっては攻撃者)にデータを読み取られてしまうことがある。 データを傍受する攻撃者はデータが受信者に届く前に实验を変更できる可能性があります。SSLはこれらの各問題に対処します。首先の問題には、認証と呼ばれるプロセスで、通讯の事主两边に相手側の識別情報をオプションで確認させることで対応しています。両者が認証されると、SSLはセキュアなメッセージ伝送のために両者間の暗号化接続を提供します。両者の通讯を暗号化することで機密性が保捏されるため、2番目の問題に対処します。SSLで使用する暗号化アルゴリズムには、セキュアなハッシュ関数が含まれており、これはチェックサムに似ています。これにより、送信中にデータが変更されていないことが保証されます。セキュアなハッシュ関数により、3番目のデータの整合性の問題に対処します。
注: 認証も暗号化もオプションであり、2つのエンティティ間でネゴシエーションされた暗号化神气群に依存します。
SSLを使用する場合の明確な例は電子商取引です。電子商取引では、通讯するサーバーの識別情報は保証されていると考えるべきではありません。クレジット・カードの番号を入力するだけですばらしいサービスが受けられるという偽のWebサイトを作成するのは簡単なことです。SSLを使うと、クライアントがサーバーの識別情報を認証することができます。また、サーバーもクライアントの情報を認証できますが、インターネット上の取引では、この法式はあまり使われていません。
クライアントとサーバーが互いの情報を認証すると、SSLは暗号化アルゴリズムを使用して機密性とデータの整合性を提供します。これにより、クレジット・カード番号のような機密情報をインターネット上でセキュアに送信することができます。
SSLは認証、機密性およびデータの整合性を提供しますが、非拒否サービスは提供しません。非拒否性とは、メッセージを送信したエンティティは、後になって送信を拒否することができないということを意味します。メッセージとデジタル签字が関連付けられていると、後になって通讯实验を証明することができます。SSL単独では、非拒否性を提供しません。
SSLのしくみSSLが有効な原理の1つに、複数の暗号化プロセスを使用していることがあります。SSLは、公開鍵暗号化で認証を行い、深重鍵暗号化とデジタル签字で機密性とデータの整合性を提供します。SSLについて融合する前に、暗号化の処理法式を融合しておくと役立ちます。
暗号化処理暗号化の主な想法は、2者間の深重の通讯に権限のない局外人がアクセスしたり、その实验を融合するのを困難にすることです。暗号化のプロセスによって、データに対する権限のないすべてのアクセスを必ずしも制限できるわけではありませんが、権限のない者が深重のデータを融合できないようにすることができます。暗号化では、複雑なアルゴリズムを使用して、元のメッセージ(クリアテキスト)をエンコードされたメッセージ(暗号テキスト)に変更します。ネットワーク上で転送されるデータの暗号化および復号化に使用するアルゴリズムは一般に、深重鍵暗号化と公開鍵暗号化の2つのカテゴリに分けられます。これらの暗号化の神气については、次のサブセクションで説明します。
深重鍵暗号化も公開鍵暗号化も、合意に基づく暗号鍵または暗号鍵のペアを使用します。鍵は、データの暗号化プロセスおよび復号化プロセスで暗号化アルゴリズムが使用するビット笔墨列です。暗号化鍵は、錠の鍵と同様、錠を開けることができるのは正しい鍵のみです。
通讯の事主が互いに鍵を安全に送信するのは、些細な問題ではありません。公開鍵証明書を使用すると、公開鍵を安全に送信し、受信者に公開鍵の信頼性を保証できます。公開鍵証明書については、後のセクションで説明します。
次の暗号化プロセスの説明では、セキュリティ・コミュニティで広く使用されている規則を使用します。通讯する両者がAliceとBobという名前でラベル付けされます。権限のない局外人は攻撃者とも呼ばれ、Charlieと名付けられます。
深重鍵暗号化深重鍵暗号化では、通讯するAliceとBobはメッセージの暗号化と復号化に同じ鍵を使用します。暗号化されたデータをネットワークで送信する前に、AliceとBobは鍵を捏っていることが必要で、暗号化と復号化に使用する暗号化アルゴリズムに承诺している必要があります。
深重鍵暗号化で大きな問題の1つが、攻撃者にアクセスされずに一方から他方に鍵を渡す法式の問題です。AliceとBobが深重鍵暗号化でデータを保護しても、Charlieがその鍵にアクセスできればAliceとBobの間で傍受した深重メッセージを融合できます。CharlieはAliceとBobのメッセージを復号化できるだけではなく、Aliceになりすまして暗号化データをBobに送信することもできるのです。Bobには、メッセージがCharlieから届いたものかAliceから届いたものかはわかりません。
深重鍵の配布の問題が解決すれば、深重鍵暗号化はたいへん貴重なツールになります。そのアルゴリズムにより、優れたセキュリティと暗号化データが比較的速即に提供できるからです。SSLセッションで送信される機密性の高いデータの多くは、深重鍵暗号化で送信されます。
深重鍵暗号化は、データの暗号化と復号化の両方に同じ鍵を使用するため、対称暗号化とも呼ばれます。よく知られている深重鍵暗号化アルゴリズムには、Advanced Encryption Standard (AES)、Triple Data Encryption Standard (3DES)およびRivest Cipher 4 (RC4)があります。
公開鍵暗号化公開鍵暗号化は、公開鍵と深重鍵の両方を使用することで鍵の配布法式の問題を解決しました。公開鍵はネットワークを通じて公開し、送信できますが、非公開鍵は通讯の1东说念主の事主にしか公開されません。公開鍵と非公開鍵は暗号化神气が逆で、一方の鍵で暗号化したものをもう一方の鍵で復号化します。
Bobが公開鍵暗号化を使用して、Aliceに深重のメッセージを送信するとします。Aliceは公開鍵と非公開鍵をどちらも捏っているので、非公開鍵は安全な場所に看护しておき、公開鍵をBobに送信します。BobはAliceの公開鍵を使ってAliceへの深重のメッセージを暗号化します。Aliceは非公開鍵を使ってメッセージを復号化します。
Aliceが自分の深重鍵を使用してメッセージを暗号化し、その暗号化されたメッセージをBobに送信すれば、Bobが受信するデータはAliceから届いたものだと考えることができます。BobがAliceの公開鍵でデータを復号化できれば、そのメッセージはAliceが自分の深重鍵で暗号化したものに間違いなく、Aliceの深重鍵を捏っているのはAliceのみです。問題は、Aliceの公開鍵が公開されているために、だれもがメッセージを読めてしまうことです。このシナリオは、セキュアなデータ通讯を考慮に入れていませんが、デジタル签字の基本を示しています。デジタル签字とは公開鍵証明書のコンポーネントの1つで、SSLでクライアントやサーバーを認証するために使用します。公開鍵証明書とデジタル签字については、後のセクションで説明します。
公開鍵暗号化は、データの暗号化と復号化に別の鍵を使用するので、非対称暗号化とも呼ばれます。SSLでよく使われる、よく知られている公開鍵暗号化アルゴリズムは、Rivest Shamir Adleman (RSA)アルゴリズムです。このほかにも、深重鍵を交換するために設計されたSSLを使う公開鍵暗号化アルゴリズムには、Diffie-Hellman (DH)があります。公開鍵暗号化には推广な計算が必要なため、速率が大幅に遅くなります。そこで、この神气は暗号化データ通讯整体に使用するよりもむしろ、深重鍵など少许のデータを暗号化する場合にだけ使用します。
深重鍵暗号化と公開鍵暗号化の比較深重鍵暗号化と公開鍵暗号化のどちらにも、長所と短所があります。深重鍵暗号化では、データの暗号化や復号化に時間はかかりませんが、通讯者同士が同じ深重鍵情報を共有する必要があり、鍵の交換の法式が問題になります。公開鍵暗号化では、鍵を深重にする必要がないので鍵の交換は問題になりませんが、データの暗号化と復号化に使用するアルゴリズムには推广な計算が必要で、著しく遅くなります。
公開鍵証明書公開鍵証明書を使用すると、エンティティは非対称暗号化で使用する公開鍵を安全に配布できます。公開鍵証明書は、次の状況を侧目します。Charlieが自分の公開鍵と深重鍵を作成すれば、自分はAliceだと名乗ってBobに公開鍵を送信できます。BobはCharlieと通讯できますが、データをAliceに送信していると念念い込んでしまいます。
公開鍵証明書は電子的なパスポートだと考えることができます。これは、信頼できる組織によって発行され、总共者に識別情報を提供します。公開鍵証明書を発行する信頼できる組織を、証明書発行局(CA)と呼びます。CAは公証东说念主にたとえることができます。CAから証明書を赢得するには、識別情報の証拠となるものを提供する必要があります。CAは、申請者が申し立てる組織の代表であるとの確証が得られたら、証明書に含まれる情報の得当性を証明する証明書に签字します。
公開鍵証明書には、次のようなフィールドがあります。
発行者 証明書を発行したCAです。証明書を発行したCAが信頼でき、証明書が有効であれば、証明書は信頼できます。 有効期間 証明書には有効期限があります。証明書の有効性を検証する場合は、この日付をチェックしてください。 サブジェクト 証明書が表すエンティティに関する情報が含まれます。 サブジェクトの公開鍵 証明書が提供する情報の主要な部分は、サブジェクトの公開鍵です。その他のフィールドは、この鍵の得当性を確認するためのものです。 签字 証明書は、証明書を発行したCAによってデジタルで签字されます。签字はCAの非公開鍵を使って作成され、証明書の得当性を保証するものです。証明書のみに签字され、SSLトランザクションで送信されるデータには签字されないので、SSLには非拒否性がありません。AliceがBobに公開鍵証明書で自分の公開鍵を送信するとき、BobがAliceの公開鍵のみを有効として受け付ける場合、CharlieがAliceになりすましたとしても、BobがだまされてCharlieに深重情報を送信することはありません。
複数の証明書を証明書チェーンでリンクすることもできます。証明書チェーンを使用する場合、首先の証明書は必ず送信者の証明書です。次は送信者の証明書を発行したエンティティの証明書です。チェーン内に他の証明書がある場合、それぞれ直前の証明書を発行した証明書発行局の証明書です。チェーンの最後の証明書は、ルートCAの証明書です。ルートCAは、広く信頼されている公開証明書発行局です。複数のルートCAの情報は、时常、クライアントのインターネット・ブラウザに保存されています。この情報には、CAの公開鍵が含まれています。よく知られているCAにはVeriSign、Entrust、およびGTE CyberTrustがあります。
暗号化ハッシュ関数暗号化されたデータを送信する場合、SSLは时常、暗号化ハッシュ関数を使ってデータの整合性を保証します。ハッシュ関数を使って、AliceがBobに送ったデータをCharlieが改ざんできないようにします。
暗号化ハッシュ関数はチェックサムに似ています。主な違いは、チェックサムがデータの偶発的変化を検出するのに対し、暗号化ハッシュ関数は成心による変更を検出するように設計されています。データが暗号化ハッシュ関数で処理されると、ハッシュと呼ばれる小さなビット笔墨列が生成されます。メッセージがごくわずかだけ変更された場合も、結果として生成されるハッシュは大きく変更されます。暗号化ハッシュ関数には、暗号化鍵が必要ありません。SSLとともによく使用されるハッシュ関数は、Secure Hash Algorithm (SHA)です。SHAは、U.S. National Institute of Standards and Technology (NIST)によって提案されました。
メッセージ認証コード メッセージ認証コード(MAC)は暗号化ハッシュに似ていますが、深重鍵をベースにしている点が異なります。深重鍵情報が暗号化ハッシュ関数で処理したデータに含まれている場合、その結果生成されるハッシュはHMACと呼ばれます。Aliceは、BobへのメッセージをCharlieが確実に改ざんしないようにする場合、メッセージのHMACを計算して元のメッセージにHMACを追加できます。次に、Bobと共有している深重鍵を使用してメッセージとHMACを暗号化できます。Bobは、メッセージを復号化してHMACを計算すれば、送信中にメッセージが変更されたかどうかを知ることができます。SSLでは、HMACを使ってセキュアなデータを送信します。
デジタル签字メッセージに暗号化ハッシュが作成されると、ハッシュは送信者の非公開鍵で暗号化されます。このような暗号化ハッシュをデジタル签字と呼びます。
SSLハンドシェークSSLを使った通讯は、クライアントとサーバー間の情報交換から始まります。この情報交換をSSLハンドシェークと呼びます。SSLハンドシェークには、次のステージがあります。
暗号化神气群のネゴシエーションSSLセッションは、どの暗号群を使用するかについて、クライアントとサーバーがネゴシエーションを行うことから始まります。暗号化神气群とは、コンピュータがデータを暗号化するために使用する暗号化アルゴリズムと鍵のサイズのセットです。秀气化神气には、公開鍵交換アルゴリズムまたは鍵合意アルゴリズム、および暗号化ハッシュ関数に関する情報が含まれます。クライアントは把握できる暗号群をサーバーに伝え、サーバーは、どちらにも適用できる暗号群を選択します。
サーバーの識別情報の認証(オプション)SSLの認証ステップはオプションです。しかし、Web上の電子商取引の例では、一般にクライアントがサーバーを認証します。サーバーの認証により、サーバーが表すとクライアントが信じているエンティティを、そのサーバーが実際に表していることをクライアントが確認できます。
サーバーは、自らが表すと唱える組織に属していることを証明するため、クライアントに公開鍵証明書を提醒します。この証明書が有効であれば、クライアントはサーバーの識別情報について確信できます。
クライアントとサーバーは、同じ深重鍵について承诺できる情報を交換します。たとえば、RSAを使う場合、クライアントは公開鍵証明書で赢得したサーバーの公開鍵を使用して、深重鍵情報を暗号化します。クライアントは暗号化された深重鍵情報をサーバーに送信します。復号化にはサーバーの非公開鍵が必要なので、サーバーでだけ、このメッセージを復号化できます。
暗号化メカニズムの合意クライアントとサーバーは、同じ深重鍵にアクセスします。それぞれのメッセージでは、ハンドシェークの首先のステップで選択した暗号化ハッシュ関数と、共有された深重情報を使用して、メッセージに添付されるHMACを計算します。次に、深重鍵と、ハンドシェークの首先のステップでネゴシエーションされた深重鍵アルゴリズムを使用し、セキュアなデータとHMACを暗号化します。そのあと、クライアントとサーバーは、暗号化されハッシュ化されたデータを使ってセキュアに通讯することができます。
SSLプロトコル前のセクションでは、SSLハンドシェークについて节录を説明しました。それは、暗号化されたメッセージを送信する前にクライアントとサーバーで行われる情報の交換です。このセクションでは、さらに詳しく説明します。
図1に、SSLハンドシェークで交換される一連のメッセージを示しています。特定の状況下でだけ送信されるメッセージには「optional」と記されています。各SSLメッセージについては図の下で説明しています。
SSLメッセージは、次の順序で送信されます。
Client hello クライアントは、それがサポートする最上位バージョンのSSLと暗号化神气群のリスト(TLS 1.0はSSL 3.1と示される)を含むサーバー情報を送信します。暗号化神气群の情報には、暗号化アルゴリズムと鍵のサイズが含まれます。 Server hello サーバーは、クライアントとサーバーの両方がサポートする最上位バージョンのSSLと最適な暗号化神气群を選択し、この情報をクライアントに送信します。 Certificate (オプション) サーバーはクライアントに証明書または証明書チェーンを送信します。証明書チェーンは时常、サーバーの公開鍵証明書で始まり、認証局のルート証明書で終わります。このメッセージはオプションで、サーバー認証を求められた場合に使用します。 Certificate request (オプション) サーバーがクライアントを認証する必要がある場合、クライアントに証明書要求を送信します。インターネット・アプリケーションでは、このメッセージが使われることはほとんどありません。 Server key exchange (オプション) certificateからの公開鍵情報が鍵交換を行うのに不十分な場合、サーバーはクライアントにサーバー鍵交換メッセージを送信します。たとえば、Diffie-Hellman (DH)に基づく暗号化神气群では、このメッセージにはサーバーのDH公開鍵が含まれています。 Server hello done サーバーは、首先のネゴシエーション・メッセージを終了したことをクライアントに伝えます。 Certificate (オプション) サーバーがクライアントに証明書を要求すると、クライアントはサーバーが前に行ったように、その証明書チェーンを送信します。注: クライアントに証明書を要求するのは、ごく一部のインターネット・サーバー・アプリケーションのみです。
Client key exchange クライアントは、対称暗号化で使用する鍵を作成するために使用される情報を生成します。RSAでは、クライアントはサーバーの公開鍵でこの鍵情報を暗号化してサーバーに送信します。DHに基づく暗号化神气群の場合、このメッセージにはクライアントのDH公開鍵が含まれています。 Certificate verify (オプション) このメッセージは、上述のとおりクライアントが証明書を提醒する場合にクライアントによって送信されます。このメッセージは、サーバーにクライアントの認証処理を已矣させるためのものです。このメッセージが使用されると、クライアントは暗号化ハッシュ関数で電子的に签字した情報を送信します。サーバーがクライアントの公開鍵でこの情報を復号化すれば、サーバーはクライアントを認証できます。 Change cipher spec クライアントはメッセージを送信し、暗号化モードに変更するようサーバーに伝えます。 Finished クライアントはサーバーに、セキュアなデータ通讯を開始する準備ができたことを伝えます。 Change cipher spec サーバーはメッセージを送信し、暗号化モードを変更するようクライアントに伝えます。 Finished サーバーはクライアントに、セキュアなデータ通讯を開始する準備ができたことを伝えます。SSLハンドシェークが終了します。 Encrypted data クライアントとサーバーは、client helloとserver hello時にネゴシエーションされた対称暗号化アルゴリズムと暗号化ハッシュ関数およびclient key exchange時にクライアントがサーバーに送信した深重鍵を使用して通讯します。このときハンドシェークの再ネゴシエーションを行うことができます。詳細は、次のセクションを参照してください。 Close Messages 接続の終わりに、それぞれの側がclose_notifyメッセージを送信し、接続が終了したことをピアに伝えます。SSLセッションで生成したパラメータを保存しておけば、异日のSSLセッションでこれらのパラメータを再把握できます。SSLセッションのパラメータを保存しておけば、暗号化通讯をすばやく開始できます。
ハンドシェークの再実行(再ネゴシエーション)初期のハンドシェークが已矣してアプリケーション・データが流れているとき、いずれの側からでも新しいハンドシェークをいつでも開始できます。特に蹙迫な操作について、アプリケーションで強力な暗号化神气群を使用したり、サーバー・アプリケーションでクライアント認証が必要になる場合もあります。
原理は何であれ、新しいハンドシェークが既存の暗号化セッションに置き換わり、新しいセッションが確立されるまで、アプリケーション・データとハンドシェーク・メッセージが交互に设置されます。
アプリケーションで次のいずれかのメソッドを使用して、新しいハンドシェークを開始できます。
SSLSocket.startHandshake() SSLEngine.beginHandshake()再ネゴシエーションに関するプロトコルの問題が2009年に見つかりました。プロトコルおよびJava SE実装はいずれも修正されています。詳細は、「Transport Layer Security (TLS)再ネゴシエーションの問題」を参照してください。
秀气化神气の選択とリモート・エンティティの検証 SSL/TLSプロトコルは、保護された接続を確保するための一連の特定のステップを定義します。ただし、暗号化神气群の選択が、接続で確保するセキュリティのタイプに径直影響します。たとえば、匿名暗号化神气群を選択した場合、アプリケーションにはリモート・ピアの識別情報を検証する法式がありません。暗号化しない神气群が選択された場合は、データの機密性を保護できません。またSSL/TLSプロトコルでは、受信した資格と、ピアから送信されることが予期される資格が一致するようにとは規定していません。接続がなんらかの原理で悪意のあるピアにリダイレクトされたときに、悪意のあるピアのクレデンシャルが現在のトラスト・データに基づいて受け付けられた場合、その接続は有効とみなされてしまいます。raw SSLSocketおよびSSLEngineクラスを使用する場合は、データの送信前に必ずピアのクレデンシャルをチェックしてください。SSLSocketおよびSSLEngineクラスは、URL内のホスト名がピアのクレデンシャル内のホスト名と一致することを自動的に検証しません。ホスト名が検証されない場合、URL不正行為によってアプリケーションが悪用される可能性があります。
HTTPS (HTTP Over TLS)などのプロトコルでは、ホスト名検証が必要です。アプリケーションは、HostnameVerifierを使用してデフォルトのHTTPSホスト名規則をオーバーライドできます。詳細は「HttpsURLConnection」を参照してください。
JSSEクラスとインタフェースセキュアな通讯を行うには、接続の両側がSSL対応であることが必要です。JSSE APIの接続のエンドポイント・クラスは、SSLSocketおよびSSLEngineです。図2では、SSLSocketとSSLEngineの作成に使用される主なクラスを論理的な順序で並べています。図の後のテキストで、図の实验を説明しています。
SSLSocketはSSLSocketFactoryまたはイン・バウンド接続を受け取るSSLServerSocketによって作成されます。SSLServerSocketはSSLServerSocketFactoryで作成されます。SSLSocketFactoryおよびSSLServerSocketFactoryオブジェクトはどちらもSSLContextで作成されます。SSLEngineは、SSLContextによって径直作成され、アプリケーションに依存してすべての入出力を処理します。
注: raw SSLSocketまたはSSLEngineクラスを使用する場合は、データの送信前に必ずピアのクレデンシャルをチェックしてください。SSLSocketおよびSSLEngineクラスは、たとえばURL内のホスト名がピアのクレデンシャル内のホスト名と一致することを自動的に検証しません。ホスト名が検証されない場合、URL不正行為によってアプリケーションが悪用される可能性があります。
SSLContextを赢得して初期化するには、次の2つの法式があります。
もっとも簡単な法式は、SSLSocketFactoryまたはSSLServerSocketFactoryクラスでgetDefault staticメソッドを呼び出すことです。このメソッドは、デフォルトのKeyManager、TrustManagerおよびSecureRandom (セキュアな乱数ジェネレータ)を使用してデフォルトのSSLContextを作成します。デフォルトのKeyManagerFactoryおよびTrustManagerFactoryを使用すると、KeyManagerおよびTrustManagerがそれぞれ作成されます。使用する鍵データは、「デフォルトのキーストアとトラストストア、ストア・タイプ、およびストア・パスワードのカスタマイズ」で説明するシステム・プロパティで指定されるデフォルトのキーストアおよびトラストストアにあります。 作成したコンテキストの動作を呼出し側でもっとも厳密に制御できるようにするアプローチは、SSLContextクラスでstaticメソッドgetInstance()を呼び出し、さらにそのインスタンスの適切なinit()メソッドを呼び出してコンテキストを初期化することです。init()メソッドの1つのバリアントは、KeyManagerオブジェクトの配列、TrustManagerオブジェクトの配列、およびSecureRandomオブジェクトの3つの引数を取ります。適切なインタフェースを実装するか、実装を生成するKeyManagerFactoryクラスとTrustManagerFactoryクラスを使用して、KeyManagerオブジェクトとTrustManagerオブジェクトが作成されます。次に、KeyManagerFactoryおよびTrustManagerFactoryを、TrustManagerFactoryまたはKeyManagerFactoryクラスのinit()メソッドへの引数として渡されたKeyStoreに含まれる鍵データでそれぞれ初期化できます。最後に、TrustManagerFactoryのgetTrustManagers()メソッドとKeyManagerFactoryのgetKeyManagers()メソッドを呼び出して、トラスト・データまたは鍵データの型ごとに1つずつトラスト・マネージャまたはキー・マネージャの配列を赢得できます。SSL接続が確立されると、SSLSessionが作成され、これには設定した識別情報、使用する暗号化神气群などの様々な情報が含まれます。次にSSLSessionを使用して、2つのエンティティ間の進行中の関係と状態情報が記述されます。各SSL接続には、一度に1つのセッションが含まれますが、そのセッションがエンティティ間の接続に、同時に、または連続して何度も使用されることがあります。
コア・クラスとインタフェースコアJSSEクラスは、javax.netおよびjavax.net.sslパッケージの一部です。
SocketFactoryおよびServerSocketFactoryクラス综合クラスjavax.net.SocketFactoryは、ソケットの作成に使われます。このクラスのサブクラスは、ソケットの特定のサブクラスを作成し、パブリック・ソケット・レベルの機能を追加するための汎用フレームワークを提供するファクトリです。たとえば、「SSLSocketFactoryおよびSSLServerSocketFactory」を参照してください。
javax.net.ServerSocketFactory综合クラスはSocketFactoryクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。
ソケット・ファクトリは、構築されるソケットに関する様々なポリシーを赢得するための簡単な法式であり、ソケットを要求する特別なコード構成を必要としない法式でそれらのソケットを生成します。
ファクトリとソケットに多相性があるため、種類が異なるファクトリを渡すだけで、種類が異なるソケットに同じアプリケーション・コードを使用できます。 ソケット構築時に使用するパラメータを使って、ファクトリ自己をカスタマイズできます。たとえば、ファクトリをカスタマイズして、異なるネットワーク・タイムアウトのソケットや、構成済のセキュリティ・パラメータを返すことができます。 アプリケーションに返されるソケットはjava.net.Socket (またはjavax.net.ssl.SSLSocket)のサブクラスにすることができます。そうすれば、圧縮、セキュリティ、レコード宣言、統計情報収集、ファイアウォール・トンネリングなどの機能の新しいAPIを径直公開できます。 SSLSocketFactoryおよびSSLServerSocketFactoryクラスjavax.net.ssl.SSLSocketFactoryクラスは、セキュアなソケットを作成するファクトリとして動作します。このクラスは、javax.net.SocketFactoryの综合サブクラスです。
セキュアなソケット・ファクトリは、セキュアなソケットの作成と初期設定の詳細情報をカプセル化します。これには、認証鍵、ピア証明書の検証、使用できる暗号化神气群などが含まれます。
javax.net.ssl.SSLServerSocketFactoryクラスはSSLSocketFactoryクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。
SSLSocketFactoryの赢得次の法式でSSLSocketFactoryを赢得できます。
SSLSocketFactory.getDefault() staticメソッドを呼び出してデフォルトのファクトリを赢得します。 APIパラメータとしてファクトリを受信する。つまり、ソケットを作成する必要があるが、そのソケットの構成法式の詳細に関与しないコードには、クライアントによって呼び出され、ソケットの作成時に使用するSSLSocketFactoryを指定できるSSLSocketFactoryパラメータを捏つメソッドを含めることができます(javax.net.ssl.HttpsURLConnectionなど)。 動作を指定した新規ファクトリを構築する。时常、デフォルトのファクトリはサーバー認証だけをサポートするように構成されています。このため、デフォルトのファクトリで作成されたソケットは、一般的なTCPソケット以上にクライアントの情報を漏らすことはありません。
ソケットを作成して使用するクラスの多くは、ソケットの作成法式を詳しく知る必要はありません。パラメータとして渡されたソケット・ファクトリを介してソケットを作成するのは、ソケット構成の詳細を分離し、ソケットを作成して使用するクラスの再把握性を高めるよい法式です。
新しいソケット・ファクトリ・インスタンスを作成するには、独自のソケット・ファクトリ・サブクラスを実装するか、ソケット・ファクトリのファクトリとして動作するクラスをべつに使用します。このようなクラスの1つの例がSSLContextで、これはプロバイダ・ベースの構成クラスとしてJSSE実装に提供されます。
SSLSocketおよびSSLServerSocketクラスjavax.net.ssl.SSLSocketクラスは標準のJava java.net.Socketクラスのサブクラスです。標準的なソケット・メソッドをすべてサポートし、セキュアなソケットに固有のメソッドを追加します。このクラスのインスタンスは、その作成に使用されたSSLContextをカプセル化します。ソケット・インスタンスのセキュアなソケット・セッションの作成を搞定するAPIもありますが、トラストおよび鍵搞定は径直公開されません。
javax.net.ssl.SSLServerSocketクラスはSSLSocketクラスに似ていますが、サーバー・ソケットの作成に特化して使われます。
ピアの不正行為を宝贵するには、常にSSLSocketに提醒されるクレデンシャルを検証してください。
注: SSLとTLSプロトコルは複雑なので、接続時の受信バイトがハンドシェークのデータとアプリケーション・データのどちらなのかを予測し、現在の接続状態にどのような影響を与えるか(処理を中断させることもある)を予測するのは困難です。Oracle JSSEの実装では、SSLSocket.getInputStream()によって赢得されたオブジェクトのavailable()メソッドは、SSL接続で平方に復号化されても、アプリケーションではまだ読み込まれていないデータのバイト数を返します。
SSLSocketの赢得 SSLSocketのインスタンスは、次のいずれかの法式で赢得できます。 SSLSocketは、そのクラスの複数のcreateSocket()メソッドのうちの1つを使用して、SSLSocketFactoryのインスタンスを作成できます。 SSLSocketはSSLServerSocketクラスのaccept()メソッドを使用して作成できます。 SSLEngineクラスSSL/TLSが把握される機会はますます増えています。広範な計算プラットフォームやデバイスを包含するさまざまなアプリケーションで使用されています。この升迁に伴い、アプリケーションのパフォーマンス、拡張性、サイズおよびその他の要件を満たすため、様々な入出力モデルやスレッド・モデルでSSL/TLSを使用することが求められています。ブロックおよび非ブロック入出力チャネル、非同时入出力、大肆の入力ストリームと出力ストリームおよびバイト・バッファでSSL/TLSの使用が求められています。また、数千のネットワーク接続を搞定することが必要な、十分に拡張性の高いパフォーマンス重視の環境で使用することも求められています。
Java SEのSSLEngineクラスを使用する入出力トランスポート・メカニズムの综合により、トランスポートに依存せずにSSL/TLSプロトコルをアプリケーションで使用できるようになったため、アプリケーション開発者はもっともニーズを満たすトランスポート・モデルや計算モデルを目田に選択できます。この新しい综合化により、非ブロック入出力チャネルや他の入出力モデルをアプリケーションで使用できるだけでなく、異なるスレッド・モデルにも対応できます。事実上これは、入出力とスレッドの決定がアプリケーション開発者に委ねられることになります。こうした柔軟性のため、アプリケーション開発者は、それ自体が複雑な問題でもある入出力とスレッドを搞定するとともに、SSL/TLSプロトコルをある进度融合する必要があります。このように、新しい综合は高度なAPIなので、初心者はSSLSocketを使用してください。
Newcomers to the API may wonder "Why not just have an SSLSocketChannel which extends java.nio.channels.SocketChannel?" There are the following reasons: There were a lot of very difficult questions about what an SSLSocketChannel should be, including its class hierarchy and how it should interoperate with a Selector and other types of SocketChannel. Each proposal brought up more questions than answers. It was noted that any new API abstraction extended to work with SSL/TLS would require the same significant analysis and could result in large and complex APIs. Any JSSE implementation of a new API would be free to choose the "best" I/O and compute strategy, but hiding any of these details is inappropriate for those applications needing full control. Any specific implementation would be inappropriate for some application segment.By abstracting the I/O and treating data as streams of bytes, these issues are resolved and the new API could be used with any existing or future I/O model. While this solution makes I/O and CPU handling the developers' responsibility, JSSE implementations are prevented from being unusable due to some unconfigurable and/or unchangeable internal detail.
-->Java Generic Security Services (Java GSS)やJava Simple Authentication Security Layer (Java SASL)などの他のJavaプログラミング言語APIのユーザーは、アプリケーションがデータをトランスポートする役割を担うことの類似点に気付くでしょう。
コア・クラスは、javax.net.ssl.SSLEngineです。これは、SSL/TLS状態マシンをカプセル化し、SSLEngineクラスのユーザーによって供給されるインバウンドとアウトバウンドのバイト・バッファ上で動作します。図3の図は、アプリケーションから、SSLEngineを経由して、トランスポート・メカニズムまで進み、戻ってくるデータのフローを示しています。
左側に示されるアプリケーションは、アプリケーションのプレーンテキスト・データをアプリケーション・バッファに供給し、それをSSLEngineに渡します。SSLEngineオブジェクトは、バッファに格納されているデータまたはハンドシェーク・データを処理してSSL/TLSエンコード・データを生成し、アプリケーションによって提供されるネットワーク・バッファに格納します。次にアプリケーションは、右側に示されている適切なトランスポートを使用して、ネットワーク・バッファの实验をピアに送信する役割を実行します。トランスポートを介してピアからSSL/TLSエンコード・データを受け取ると、アプリケーションはそのデータをネットワーク・バッファに格納し、SSLEngineに渡します。SSLEngineオブジェクトは、ネットワーク・バッファの实验を処理し、ハンドシェーク・データまたはアプリケーション・データを生成します。
If the application were to choose a stream-based socket as the transport mechanism, then this overview more or less corresponds to how an application would SSLSockets except that with the new abstraction, it is doing each exchange in two steps instead of one.The TLS (and SSL) protocol is actually a collection of protocols. One protocol supports application data exchange while the others support authentication, negotiation of the use of cipher suites and other parameters, and communication of warnings and errors. These non-application data exchange tasks are referred to as handshaking and affect the state of the SSLEngine. When handshaking data is fed to the SSLEngine (encapsulated within SSL/TLS encoded data received from the peer), it might change the engine's state such that the engine cannot process any more application data until it completes the handshaking.
-->SSLEngineクラスのインスタンスは次のいずれかの状態になります。
作成: 構成準備已矣 初期ハンドシェーク: 認証の実行と通讯パラメータのネゴシエーション アプリケーション・データ: アプリケーションの交換準備已矣 再ハンドシェーク: 通讯パラメータ/認証情報の再ネゴシエーション、ハンドシェーク・データはアプリケーション・データと夹杂可能 閉鎖: 接続のシャットダウン準備已矣 SSLEngineオブジェクトの作成SSLEngineオブジェクトを作成するには、SSLContext.createSSLEngine()メソッドを使用します。次に、クライアントまたはサーバーとして動作するようにエンジンを構成し、使用する暗号化神气群やクライアント認証が必要かどうかなどの他の構成パラメータも設定します。
例1に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("SunX509"); kmf.init(ksKeys, passphrase); // TrustManagers decide whether to allow connections TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ksTrust); sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); // Create the engine SSLEngine engine = sslContext.createSSLengine(hostname, port); // Use as client engine.setUseClientMode(true);SSL/TLSデータの生成と処理
2つの主要なSSLEngineメソッドはwrap()とunwrap()です。それらは、それぞれネットワーク・データの生成と消費を担当します。SSLEngineオブジェクトの状態に応じて、このデータはハンドシェーク・データかアプリケーション・データになります。
それぞれのSSLEngineオブジェクトには、存続期間中に数種類の段階があります。アプリケーション・データを送信または受信できるようにするには、SSL/TLSプロトコルで、暗号化パラメータを確立するためのハンドシェークが必要です。このハンドシェークでは、SSLEngineオブジェクトによる一連のやり取りのステップが必要です。「SSLハンドシェーク」セクションで、ハンドシェーク自体の詳細について説明しています。
初期ハンドシェーク時に、wrap()およびunwrap()メソッドはハンドシェーク・データを生成および消費し、アプリケーションはデータのトランスポートを担当します。wrap()およびunwrap()メソッド・シーケンスは、ハンドシェークが終了するまで繰り返されます。それぞれのSSLEngine操作によりSSLEngineResultクラスのインスタンスが生成され、その中のSSLEngineResult.HandshakeStatusフィールドは、ハンドシェークを進めるために実行する必要のある次の動作を決定するために使用されます。
表4に、一般的なハンドシェーク時に呼び出されるメソッドのシーケンスと、対応するメッセージおよびステータスを示します。
表4: 一般的なハンドシェーク クライアント SSL/TLSメッセージ HandshakeStatus wrap() ClientHello NEED_UNWRAP unwrap() ServerHello/Cert/ServerHelloDone NEED_WRAP wrap() ClientKeyExchange NEED_WRAP wrap() ChangeCipherSpec NEED_WRAP wrap() Finished NEED_UNWRAP unwrap() ChangeCipherSpec NEED_UNWRAP unwrap() Finished FINISHEDハンドシェークの已矣時に、wrap()をさらに呼び出すと、アプリケーション・データおよびパッケージを消費してトランスポートしようとします。unwrap()メソッドはその逆を試みます。
ピアにデータを送信するには、まずアプリケーションがSSLEngine.wrap()を介して送信するデータを提供し、対応するSSL/TLSエンコード・データを赢得します。次にアプリケーションは、選択したトランスポート・メカニズムを使用してエンコード・データをピアに送信します。アプリケーションは、トランスポート・メカニズムを介してピアからSSL/TLSエンコード・データを受け取ると、SSLEngine.unwrap()を介してそのデータをSSLEngineに送り、ピアによって送信されたプレーン・テキスト・データを赢得します。
例2に、非ブロックSocketChannelを使用してピアと通讯するSSLアプリケーションを示します。
注: この例は、非ブロックSocketChannelを組み込んだSelectorを使用することにより、堅牢性と拡張性を高めることができます。
例2では、例1で作成したSSLEngineを使用してエンコードすることにより、ピアに笔墨列helloを送信します。これは、バイト・バッファの大きさを決定するために、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 ... }
例3では、同じ非ブロックSocketChannelからデータを読み取り、例1で作成した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の操作のステータスについて
エンジンのステータスとアプリケーションの取るべきアクションを示すため、SSLEngine.wrap()メソッドとSSLEngine.unwrap()メソッドは、例2に示すようなSSLEngineResultインスタンスを返します。このSSLEngineResultオブジェクトには、エンジンの整体的なステータスとハンドシェークのステータスの2つのステータス情報が格納されます。
整体的なステータスは、SSLEngineResult.Status enumによって表されます。次のステータスがあります。
OK エラーはありませんでした。 CLOSED 操作によってSSLEngineが閉じられたか、操作はすでに閉じられていたために已矣できませんでした。 BUFFER_UNDERFLOW 入力バッファのデータが不十分で、アプリケーションがピアから追加のデータを赢得する(ネットワークから追加のデータを読み取ることによってなど)必要があることを示しています。 BUFFER_OVERFLOW 出力バッファに結果を保捏するためのスペースが不及しており、アプリケーションは想法のバッファをクリアするか、大きくする必要があることを示しています。例4は、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は、ハンドシェークへの応答におけるアクションとwrap()およびunwrap()メソッドの整体のステータスを表すアクションの2つのアクションを取る必要があることを示すことができます。たとえばエンジンは、1回のSSLEngine.unwrap()呼出しの結果として、SSLEngineResult.Status.OKを返して入力データが平方に処理されたことを示し、SSLEngineResult.HandshakeStatus.NEED_UNWRAPを返すことにより、ハンドシェークを継続するためにアプリケーションがピアからさらにSSL/TLSエンコード・データを赢得し、もう一度SSLEngine.unwrap()に供給すべきことを示します。お気付きのとおり、先の例はかなり単純化されていますが、これらすべてのステータスを適正に処理するにはコードをかなり拡張する必要があります。
例5に、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 ... }ブロック・タスクの処理
ハンドシェーク時に、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およびExtendedSSLSessionjavax.net.ssl.SSLSessionインタフェースは、SSLSocketまたはSSLEngine接続の2つのピアの間でネゴシエーションされたセキュリティ・コンテキストを表します。一度確立されたセッションは、同じ2つのピアの間で接続されるそのあとのSSLSocketまたはSSLEngineオブジェクトによっても共有できます。
場合によっては、ハンドシェーク中に取り決めたパラメータが、後のハンドシェークでトラストについて判断を下す際に必要になることもあります。たとえば、有効な签字アルゴリズムのリストによって、認証に使用できる証明書タイプが制限されることがあります。SSLSessionはハンドシェーク時に、SSLSocketまたはSSLEngineのgetHandshakeSession()を呼び出すことによって赢得できます。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初値に標準に準拠した16Kバイトのレコードを送信し、32Kバイトの着信レコードを許可します。侧目策については、「JSSEのカスタマイズ」のシステム・プロパティjsse.SSLEngine.acceptLargeFragmentsを参照してください。
HttpsURLConnectionクラスHTTPSプロトコルはHTTPプロトコルに似ていますが、データを要求または受信する前に、まずSSL/TLSソケットを把握してセキュアなチャネルを確立してピアの識別情報を検証します。javax.net.ssl.HttpsURLConnectionクラスはjava.net.HttpsURLConnectionクラスを拡張し、HTTPSに固有の機能のサポートを追加します。HTTPS URLの構築および使用法式の詳細は、java.net.URL、java.net.URLConnection、java.net.HttpURLConnectionおよびjavax.net.ssl.HttpURLConnectionクラスに関するAPIの仕様のセクションを参照してください。
HttpsURLConnectionインスタンスを赢得する際、URLConnection.connect()メソッドを使用して実際にネットワーク接続を開始する前に、複数のHTTPおよびHTTPSパラメータを構成できます。これらについては、次を参照してください。
割当て済のSSLSocketFactoryの設定 割当て済のHostnameVerifierの設定 割当て済の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()メソッドと似ています。
サポート・クラスとインタフェースこのセクションのクラスとインタフェースは、SSLSocketFactory、SSLServerSocketFactoryおよびSSLEngineオブジェクトを作成するために使用されるSSLContextオブジェクトの作成と初期化をサポートするために提供されます。サポート・クラスとインタフェースはjavax.net.sslパッケージに含まれています。
このセクションで説明する3つのクラス(SSLContext、KeyManagerFactoryおよびTrustManagerFactory)はエンジン・クラスです。エンジン・クラスとは、特定のアルゴリズムのAPIクラス(SSLContextの場合はプロトコル)です。その実装では1つまたは複数の暗号化サービス・プロバイダ(プロバイダ)パッケージで提供されることがあります。プロバイダとエンジン・クラスの詳細は、「Java暗号化アーキテクチャ・リファレンス・ガイド」の「設計方針」と「想法」のセクションを参照してください。
JSSEに標準で付属するSunJSSEプロバイダは、SSLContext、KeyManagerFactoryおよびTrustManagerFactory実装を提供し、標準のjava.security APIではエンジン・クラスの実装も提供します。表5に、SunJSSEによって提供される実装を一覧暗意します。
表5: SunJSSEによって提供される実装 実装されるエンジン・クラス アルゴリズムまたはプロトコル KeyStore PKCS12 KeyManagerFactory PKIX、SunX509 TrustManagerFactory PKIX (X509またはSunPKIX)、SunX509 SSLContext SSLv3(1)、TLSv1、TLSv1.1、TLSv1.2 SSLContextクラスjavax.net.ssl.SSLContextクラスは、セキュアなソケット・プロトコルの実装のエンジン・クラスです。このクラスのインスタンスは、SSLソケット・ファクトリおよびSSLエンジンのファクトリとして動作します。SSLContextオブジェクトは、そのコンテキストの下で作成されたすべてのオブジェクトで共有される状態情報をすべて保捏します。たとえば、セッションの状態は、ソケット・ファクトリにより作成され、コンテキストにより提供されたソケットによってハンドシェーク・プロトコルが取り決められると、SSLContextと関連付けられます。キャッシュに書き込まれたこれらのセッションは、同じコンテキストで作成された別のソケットで再把握したり共有することができます。
各インスタンスは、認証の実行に必要な鍵、証明書チェーン、および信頼されたルートCA証明書を使ってinitメソッドで構成されます。この構成は、鍵とトラスト・マネージャの形で提供されます。これらのマネージャは認証をサポートし、コンテキストによってサポートされる暗号群の鍵合意を提供します。
現在は、X.509ベースのマネージャだけがサポートされています。
SSLContextオブジェクトの作成他のJCAプロバイダ・ベースのエンジン・クラスと同様に、SSLContextオブジェクトは、SSLContextクラスのgetInstance()ファクトリ・メソッドを使用して作成されます。このようなstaticメソッドは、最低限要求されたセキュアなソケット・プロトコルを実装するインスタンスを返します。返されるインスタンスはその他のプロトコルも実装できます。たとえば、getInstance("TLSv1")はTLSv1、TLSv1.1およびTLSv1.2を実装するインスタンスを返すことができます。getSupportedProtocols()メソッドは、このコンテキストからSSLSocket、SSLServerSocketまたはSSLEngineが作成されたときに、サポート対象のプロトコルのリストを返します。実際のSSL接続でどのプロトコルを有効にするかは、setEnabledProtocols(String[] protocols)メソッドを使用して制御できます。
注: SSLSocketFactory.getDefault()メソッドを呼び出すと、SSLContextオブジェクトが自動的に作成され、初期化され、SSLSocketFactoryクラスに静的に割り当てられます。したがって、デフォルト動作をオーバーライドする場合を除き、SSLContextオブジェクトを径直作成したり初期化したりする必要はありません。
getInstance()ファクトリ・メソッドを呼び出してSSLContextオブジェクトを作成するには、プロトコル名を指定する必要があります。または、要求されたプロトコルの実装を提供するプロバイダを次のように指定することもできます。
public static SSLContext getInstance(String protocol); public static SSLContext getInstance(String protocol, String provider); public static SSLContext getInstance(String protocol, Provider provider);プロトコル名のみを指定すると、システムは、要求されたプロトコルの実装がその環境で把握できるかどうかを判断します。複数の実装がある場合、より望ましいものがあるかどうかを判断します。
プロトコル名とプロバイダの両方を指定すると、システムは、要求されたプロトコルの実装が要求されたプロバイダにあるかどうかを判断します。実装がない場合は、例外がスローされます。
プロトコルは、但愿するセキュアなソケット・プロトコルを記述する笔墨列(TLSなど)です。SSLContextオブジェクトの一般的なプロトコル名は、付録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にできます。その場合、デフォルト実装が使用されます。
里面のデフォルト・コンテキストが使用される場合(SSLContextはSSLSocketFactory.getDefault()またはSSLServerSocketFactory.getDefault()によって作成されるなど)、デフォルトのKeyManagerとTrustManagerが作成されます。また、デフォルトのSecureRandom実装も選択されます。
TrustManagerインタフェースTrustManagerは、提醒された認証クレデンシャルの信頼性を判定します。信頼できないクレデンシャルの場合、接続は割断されます。セキュアなソケット・ピアのリモート識別情報を認証するには、1つまたは複数のTrustManagerオブジェクトでSSLContextオブジェクトを初期化する必要があります。サポートされる認証メカニズムのそれぞれに対し、TrustManagerを1つずつ渡す必要があります。SSLContextの初期化にnullが渡されると、自動的にトラスト・マネージャが作成されます。时常、単一のトラスト・マネージャは、X.509公開鍵証明書(X509TrustManagerなど)に基づく認証をサポートしています。セキュアなソケット実装には、共有の深重鍵、Kerberos、またはほかのメカニズムに基づく認証をサポートするものもあります。
TrustManagerオブジェクトはTrustManagerFactoryによって、またはインタフェースの具体的な実装を提供することによって作成されます。
TrustManagerFactoryクラスjavax.net.ssl.TrustManagerFactoryはプロバイダ・ベースのサービスのエンジン・クラスで、1つまたは複数の型のTrustManagerオブジェクトのファクトリとして動作します。これはプロバイダ・ベースなので、追加のファクトリを実装して構成し、より高度なサービスを提供したり、インストール固有の認証ポリシーを実装する追加または代替のトラスト・マネージャを提供できます。
TrustManagerFactoryの作成 このクラスのインスタンスはSSLContextと同様の法式で作成しますが、getInstanceメソッドにプロトコル名ではなくアルゴリズム名の笔墨列を渡す点が異なります。TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm); TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm, String provider); TrustManagerFactory tmf = TrustManagerFactory.getInstance(String algorithm, Provider provider);
呼出しの例を次に示します。
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
前の呼出しは、SunJSSEプロバイダのPKIXトラスト・マネージャ・ファクトリのインスタンスを作成します。このファクトリを使用して、X.509 PKIXベースの証明書パス得当性検査を実行するトラスト・マネージャを作成できます。
SSLContextを初期化する場合は、トラスト・マネージャ・ファクトリから作成したトラスト・マネージャを使用するか、CertPath APIなどを使用して独自のトラスト・マネージャを記述できます。詳細については、「Java PKIプログラマーズ・ガイド」を参照してください。X509TrustManagerインタフェースを使用してトラスト・マネージャを実装する場合は、トラスト・マネージャ・ファクトリを使用する必要はありません。
新しく作成されたファクトリは、init()メソッドの1つを呼び出すことによって初期化してください。
public void init(KeyStore ks); public void init(ManagerFactoryParameters spec);
使用するTrustManagerFactoryに適したinit()メソッドを呼び出します。不解な場合は、プロバイダのベンダーに問い合わせてください。
「SunX509」TrustManagerFactoryなど、SunJSSEプロバイダが提供するファクトリは多半ありますが、TrustManagerFactoryを初期化するために必要な情報はKeyStoreのみであるため、首先にinitメソッドを呼び出すのが適切です。TrustManagerFactoryはKeyStoreに、認証チェック中に信頼すべきリモート証明書の情報を問い合わせます。
プロバイダでは、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.enableCRLDPをtrueに設定する必要があります。
PKIXおよびCertPath APIの詳細は、「Java PKIプログラマーズ・ガイド」を参照してください。
X509TrustManagerインタフェースjavax.net.ssl.X509TrustManagerインタフェースは、汎用のTrustManagerインタフェースを拡張したものです。X. 509ベースの認証を使用する場合、トラスト・マネージャによって実装される必要があります。
JSSEを使用したリモート・ソケット・ピアのX.509認証をサポートするには、このインタフェースのインスタンスをSSLContextオブジェクトのinitメソッドに渡す必要があります。
X509TrustManagerの作成このインタフェースは、ユーザーが径直実装することも、SunJSSEプロバイダによって提供されているものなど、プロバイダ・ベースのTrustManagerFactoryから赢得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたトラスト・マネージャに委譲することもできます。たとえば、結果の信頼性の判定をフィルタし、グラフィカル・ユーザー・インタフェースからエンド・ユーザーに問い合わせる場合に、これを実行できます。
注: nullのKeyStoreパラメータがSunJSSEのPKIXまたはSunX509 TrustManagerFactoryに渡された場合、ファクトリは次のプロセスでトラスト・データを検索します。
javax.net.ssl.trustStoreプロパティが定義されている場合、TrustManagerFactoryは、このシステム・プロパティで指定されたファイル名を使用してファイルを検索し、KeyStoreパラメータにそのファイルを使用しようとします。javax.net.ssl.trustStorePasswordシステム・プロパティも定義されている場合は、ファイルを開く前に、その値を使用してトラストストアのデータの整合性をチェックします。
javax.net.ssl.trustStoreプロパティが定義されているが、指定したファイルが存在しない場合、空のキーストアを使用するデフォルトのTrustManagerが作成されます。
javax.net.ssl.trustStoreシステム・プロパティが指定されていない場合: java-home/lib/security/jssecacertsファイルが存在すれば、そのファイルが使用されます。 java-home/lib/security/cacertsファイルが存在すれば、そのファイルが使用されます。 これらのどちらのファイルも存在しない場合、SSL暗号化神气群が匿名であり、認証を行わないので、トラストストアは必要ありません。java-homeが参照する情報については、「インストール・ディレクトリ」を参照してください。
ファクトリは、cacertsファイルをチェックする前に、javax.net.ssl.trustStoreセキュリティ・プロパティによって指定されたファイルまたはjssecacertsファイルを検索します。そのため、コード签字の想法で、cacerts内に存在するものとは別に、JSSE固有の一連の信頼されたルート証明書を提供できます。
独自のX509TrustManagerの作成指定したX509TrustManagerの動作が状況に適していない場合は、独自のTrustManagerFactoryを作成して登録するか、X509TrustManagerインタフェースを径直実装して、独自のX509TrustManagerを作成できます。
次の例に、デフォルトの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 TrustManagerFactoryはX509ExtendedTrustManagerインスタンスを返します。
独自の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");
前の呼出しでSunJSSEプロバイダのデフォルトのキー・マネージャ・ファクトリのインスタンスが作成され、これは、基本となるX.509ベースの認証鍵を提供します。
新しく作成されたファクトリは、initメソッドの1つを呼び出すことによって初期化してください。
public void init(KeyStore ks, char[] password); public void init(ManagerFactoryParameters spec);
使用するKeyManagerFactoryに適したinitメソッドを呼び出します。不解な場合は、プロバイダのベンダーに問い合わせてください。
デフォルトのSunX509 KeyManagerFactoryなど、SunJSSEプロバイダが提供するファクトリは多半ありますが、KeyManagerFactoryを初期化するために必要な情報はKeyStoreとパスワードのみであるため、首先にinitメソッドを呼び出すのが適切です。KeyManagerFactoryはKeyStoreに、リモートのソケット・ピアを認証するために使用すべき深重鍵、および対応する公開鍵証明書について問い合わせます。パスワード・パラメータは、KeyStoreの鍵にアクセスするメソッドで使用するパスワードを指定します。KeyStoreの鍵はすべて、同じパスワードで保護する必要があります。
プロバイダでは、KeyStoreとパスワード之外の初期化パラメータを必要とすることがあります。そのプロバイダのユーザーは、プロバイダによる定義に従って、適切なManagerFactoryParametersの実装を渡すことが期待されます。そのあと、プロバイダはManagerFactoryParameters実装の特定のメソッドを呼び出し、必要な情報を赢得できます。
一部のファクトリでは、KeyStoreオブジェクトやその他のパラメータで初期化されなくても、認証データにアクセスできます。たとえば、Java認証・承認サービス(JAAS)などのログイン・メカニズムの一部として鍵データにアクセスできる場合があります。
前に述べたように、SunJSSEプロバイダは、KeyStoreパラメータで初期化されている必要があるSunX509ファクトリをサポートします。
X509KeyManagerインタフェースjavax.net.ssl.X509KeyManagerインタフェースは、汎用のKeyManagerインタフェースを拡張したものです。X.509ベースの認証を行うキー・マネージャで実装します。JSSEを使用したリモート・ソケット・ピアのX.509認証をサポートするには、このインタフェースのインスタンスをSSLContextオブジェクトのinit()メソッドに渡す必要があります。
X509KeyManagerの作成このインタフェースは、ユーザーが径直実装することも、SunJSSEプロバイダによって提供されているものなど、プロバイダ・ベースのKeyManagerFactoryから赢得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたキー・マネージャに委譲することもできます。たとえば、結果の鍵をフィルタし、グラフィカル・ユーザー・インタフェースを使用してエンド・ユーザーに問い合わせる場合に、これを実行できます。
独自のX509KeyManagerの作成X509KeyManagerのデフォルトの動作が状況に適していない場合は、「独自のX509TrustManagerの作成」に示す同様の法式で独自のX509KeyManagerを作成できます。
X509ExtendedKeyManagerクラスX509ExtendedKeyManager综合クラスは、接続に固有の鍵の選択が可能なX509KeyManagerインタフェースの実装です。これは、鍵のタイプ、許可される発行者および現在のSSLEngineに基づいて、クライアントまたはサーバー用の鍵の別名を選択する2つのメソッドを追加します。
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)キー・マネージャがX509ExtendedKeyManagerクラスのインスタンスでない場合、SSLEngineクラスと連携して動作しません。
JSSEプロバイダおよびトラスト・マネージャの実装については、レガシーのX509KeyManagerインタフェースよりもX509ExtendedKeyManagerクラスの方が強く推奨されます。
TLS 1.2以降では、クライアントとサーバーの両方が、受け入れるハッシュ・アルゴリズムと签字アルゴリズムを指定できます。リモート側から要求される認証に及格するには、ローカルの鍵選択の決定が、X509証明書と、リモート側で受け入れられるハッシュ・アルゴリズムおよび签字アルゴリズムの両方に基づいていることが必要です。リモート側で受け入れられるハッシュ・アルゴリズムおよび签字アルゴリズムはExtendedSSLSession.getPeerSupportedSignatureAlgorithms()メソッドを使用して赢得できます。
「独自のX509ExtendedTrustManagerの作成」に示す同様の法式で、独自のX509ExtendedKeyManagerサブクラスを作成できます。
サーバー側でのServer Name Indication (SNI)拡張のサポートにより、キー・マネージャはサーバー名をチェックし、それに従って適切な鍵を選択できます。たとえば、キーストアに証明書付きの鍵エントリが3つあるとします。
cn=www.example.com cn=www.example.org cn=www.example.netClientHelloメッセージで、SNI拡張のwww.example.netに接続するように要求する場合、サーバーはサブジェクト cn=www.example.net で証明書を選択できるようにする必要があります。
TrustManagerとKeyManagerの関係これまでは、TrustManagerとKeyManagerの機能に関して芜杂がありました。
TrustManagerはリモート認証クレデンシャル(すなわち接続)が信頼できるかどうかを判定します。
KeyManagerはリモート・ホストに送信される認証クレデンシャルを決定します。
二次サポート・クラスおよびインタフェース二次サポート・クラスは、セキュアなソケットの作成、使用、および搞定をサポートするJSSE APIの一部として提供されます。このクラスは、セキュアなソケット・アプリケーションでは、コア・クラスやサポート・クラスほどには使用されません。セカンダリ・サポート・クラスおよびインタフェースはjavax.net.sslおよびjavax.security.certパッケージに含まれています。
SSLParametersクラスSSLParametersクラスはTLS接続に影響する次のパラメータをカプセル化します。
SSL/TLSハンドシェークで受け付けられる暗号化神气群のリスト 許可されるプロトコルのリスト SSL/TLSハンドシェーク中のエンド・ポイント識別アルゴリズム サーバー名とサーバー名のマッチャ(「Server Name Indication (SNI)拡張」を参照) アルゴリズムの制約 SSL/TLSサーバーがクライアント認証を要求するか、あるいは必要とするか SSL/TLSハンドシェークで使用される暗号化神气群のプリファレンス次のメソッドを使用して、SSLSocketまたはSSLEngineの現在のSSLParametersを赢得できます。
SSLSocket、SSLServerSocketおよびSSLEngine内のgetSSLParameters() SSLContext内のgetDefaultSSLParameters()およびgetSupportedSSLParamters()SSLSocket、SSLServerSocketおよびSSLEngineのsetSSLParameters()メソッドで、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(true)メソッドを呼び出して、クライアントの優先順位ではなく、独自の優先順位に基づいて暗号化神气群を選択することがあります。
SSLSessionContextインタフェースjavax.net.ssl.SSLSessionContextインタフェースは、1つのエンティティに関連付けられているSSLSessionオブジェクトのグループです。たとえば、多半のセッションに同時に插足するサーバーやクライアントに関連付けることができます。このインタフェースのメソッドを使用すると、コンテキストの全セッションを列挙したり、セッションIDで特定のセッションを検索したりできます。
SSLSessionContextは、SSLSessionのgetSessionContext()メソッドを呼び出してSSLSessionからオプションで赢得することもできます。一部の環境では、コンテキストが使用できないことがあり、その場合、getSessionContextメソッドはnullを返します。
SSLSessionBindingListenerインタフェースjavax.net.ssl.SSLSessionBindingListenerインタフェースは、SSLSessionからバインドまたはアンバインドされるときに见告を受けるオブジェクトによって実装されます。
SSLSessionBindingEventクラスjavax.net.ssl.SSLSessionBindingEventクラスは、SSLSessionからバインドまたはアンバインドされるときに、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());
HostnameVerifierをHttpsURLConnectionに割り当てる法式の詳細は、「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_CIPHER、MESSAGE_DIGEST、SIGNATUREなどのフィールドを含む列挙です。
したがって、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ホスト名(クライアントから融合できる)を指定します。この引数は、次の場合に不正です。
引数が空である。 引数の末尾がピリオドで終わっている。 引数がRFC 3490仕様に準拠した有効なInternationalized Domain Name (IDN)でない。エンコードされたホスト名値をバイト配列で指定して、SNIHostNameをインスタンス化することもできます。このメソッドは一般に、要求されたSNI拡張でエンコードされた名前値を解釈するために使用します。そうでない場合、SNIHostName(String hostname)コンストラクタを使用します。encoded引数は、次の場合に不正です。
引数が空である。 引数の末尾がピリオドで終わっている。 引数がRFC 3490仕様に準拠した有効なInternationalized Domain Name (IDN)でない。 引数がUTF-8またはUS-ASCIIでエンコードされていない。注: 引数として渡されたencoded バイト配列は、以降の変更から保護するために、クローンが作成されます。
US-ASCIIエンコーディングのSNIHostNameオブジェクトのホスト名を返すには、getAsciiName()メソッドを使用します。サーバー名を他のオブジェクトと比較するには、equals()メソッドを使用します(比較は大笔墨と小笔墨が区別されません)。SNIHostNameのハッシュ・コード値を返すには、hashCode()メソッドを使用します。DNSホスト名を含むSNIHostNameの笔墨列表現を返すには、toString()メソッドを使用します。
createSNIMatcher()メソッドに、1つ以上の照合するホスト名を表す正規表現を渡すことによって、SNIHostNameオブジェクトのSNIMatcherオブジェクトを作成します。
JSSEのカスタマイズJSSEには、様々な実装をプラグインしたり、デフォルトのキーストアを指定したりして、カスタマイズ可能な標準実装が含まれます。表6では、カスタマイズが可能な側面、デフォルトの实验、およびカスタマイズを提供するために使用するメカニズムを要約しています。表の首先の列には、指定した機能と、カスタマイズ法式の詳細が説明されているサイトへのリンクが設定してあります。
一部の機能は、システム・プロパティやセキュリティ・プロパティの値を設定してカスタマイズできます。表に続くセクションでは、プロパティ値の設定法式について説明します。
注: この表に示すプロパティの多くは、現在JSSE実装で使用されていますが、それらの名前や型(システムまたはセキュリティ)が引き続き同じで、それらが异日のリリースにも存在するという保証はありません。それらのすべてのプロパティは「*」でフラグ付けされています。ここでは、JSSE実装で使用する場合の参考として、それらに言及しています。
表6: JSSEのカスタマイズ可能な項目 カスタマイズ項目 デフォルト カスタマイズ法式 X509証明書実装 OracleからのX509Certificate実装 cert.provider.x509v1セキュリティ・プロパティ HTTPSプロトコル実装 Oracleからの実装 java.protocol.handler.pkgsシステム・プロパティ プロバイダ実装 SunJSSE セキュリティ・プロパティ・ファイルのsecurity.provider.n=行 デフォルトのSSLSocketFactory実装 OracleからのSSLSocketFactory実装 * ssl.SocketFactory.providerセキュリティ・プロパティ デフォルトのSSLServerSocketFactory実装 OracleからのSSLServerSocketFactory実装 * ssl.ServerSocketFactory.providerセキュリティ・プロパティ デフォルトのキーストア なし * javax.net.ssl.keyStoreシステム・プロパティシステム・プロパティ値NONEを指定できます。この設定は、ハードウェア・トークンに存在する場合など、キーストアがファイルベースでない場合に適切。 デフォルトのキーストア・パスワード なし * javax.net.ssl.keyStorePasswordシステム・プロパティ。パスワードをコマンド・ラインに指定するなど、他のユーザーに検出される法式でパスワードを指定することはお薦めできません。パスワードのセキュリティを維捏するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します。 デフォルトのキーストア・プロバイダ なし * javax.net.ssl.keyStoreProviderシステム・プロパティ デフォルトのキーストア・タイプ KeyStore.getDefaultType() * javax.net.ssl.keyStoreTypeシステム・プロパティ デフォルトのトラストストア 存在する場合は、jssecacerts。そうでない場合、cacerts。 * javax.net.ssl.trustStoreシステム・プロパティ デフォルトのトラストストア・パスワード なし * javax.net.ssl.trustStorePasswordシステム・プロパティパスワードをコマンド・ラインに指定するなど、他のユーザーに検出される法式でパスワードを指定することはお薦めできません。パスワードのセキュリティを維捏するには、アプリケーションでパスワードの入力を求めるか、適切に保護されたオプション・ファイルにパスワードを指定します。 デフォルトのトラストストア・プロバイダ なし * javax.net.ssl.trustStoreProviderシステム・プロパティ デフォルトのトラストストア・タイプ KeyStore.getDefaultType() * javax.net.ssl.trustStoreTypeシステム・プロパティ値NONEを指定可能。この設定は、ハードウェア・トークンに存在する場合など、トラストストアがファイルベースでない場合に適切。 デフォルトのキー・マネージャ・ファクトリのアルゴリズム名 SunX509 ssl.KeyManagerFactory.algorithmセキュリティ・プロパティ デフォルトのトラスト・マネージャ・ファクトリのアルゴリズム名 PKIX ssl.TrustManagerFactory.algorithmセキュリティ・プロパティ 無効化された証明書検証暗号化アルゴリズム(「無効化された制限付き暗号化アルゴリズム」を参照)MD2、MD5、SHA1 jdkCA & usage TLSServer、RSA keySize < 1024、DSA keySize < 1024、EC keySize < 224
この無効化されたアルゴリズムのリストは、変更される可能性があります。最新の値については、JDKインストールのjava.securityファイルを参照してください。
jdk.certpath.disabledAlgorithmsセキュリティ・プロパティ 無効化された制限付き暗号化アルゴリズムSSLv3、RC4、MD5withRSA、DH keySize < 1024、EC keySize < 224、DES40_CBC、RC4_40、3DES_EDE_CBC
この無効化されたアルゴリズムのリストは、変更される可能性があります。最新の値については、JDKインストールのjava.securityファイルを参照してください。
jdk.tls.disabledAlgorithmsセキュリティ・プロパティ。 レガシーの暗号化アルゴリズムK_NULL、C_NULL、M_NULL、DH_anon、ECDH_anon、RC4_128、RC4_40、DES_CBC、DES40_CBC、3DES_EDE_CBC
このレガシー・アルゴリズムのリストは、変更される可能性があります。最新の値については、JDKインストールのjava.securityファイルを参照してください。
jdk.tls.legacyAlgorithmsセキュリティ・プロパティ。 デフォルトのプロキシ・ホスト なし * https.proxyHostシステム・プロパティ デフォルトのプロキシ・ポート 80 * https.proxyPortシステム・プロパティ Server Name Indicationオプション true * jsse.enableSNIExtensionシステム・プロパティ。 Server Name Indication (SNI)はTLS拡張で、RFC 6066で定義されています。これは仮想サーバーへのTLS接続を可能にし、さまざまなネットワーク名に対して複数のサーバーが単一の基本ネットワーク・アドレスでホスティングされます。 かなり古い一部のSSL/TLSベンダーは、SSL/TLS拡張を処理できないことがあります。この場合、このプロパティをfalseに設定してSNI拡張を無効化します。 デフォルトの暗号化神气群 ソケット・ファクトリによって決定 * https.cipherSuitesシステム・プロパティ。HttpsURLConnectionで使用できる暗号群を指定する暗号群名リスト(カンマ区切り神气)を含む。SSLSocket.setEnabledCipherSuites(String[])メソッドを参照してください。このメソッドは、渡されたString配列から径直ClientHello暗号スイートの優先順位を設定することに正经してください。 デフォルトのハンドシェーク・プロトコル ソケット・ファクトリによって決定 * https.protocolsシステム・プロパティ。HttpsURLConnectionで有効にするプロトコルを指定するプロトコル名リスト(カンマ区切り神气)を含む。SSLSocket.setEnabledProtocols(String[])メソッドを参照してください デフォルトのHTTPSポート 443 * HTTPS URL内のportフィールドによってカスタマイズします。 SunJSSEプロバイダが使用するJCE暗号化アルゴリズム SunJCE実装 代替のJCEアルゴリズム・プロバイダにSunJCEプロバイダより古い高い優先順位を与えます。 大きいSSL/TLSパケット用のバッファのデフォルトのサイズ設定 なし * jsse.SSLEngine.acceptLargeFragmentsシステム・プロパティ。このシステム・プロパティをtrueに設定すると、SSLSessionはデフォルトで大きいデータ・パケットを処理するようにバッファをサイズ設定します。これにより、アプリケーションが不要な大きいSSLEngineバッファを割り当てる場合があります。代わりに、アプリケーションはバッファ・オーバーフロー条目を動的にチェックして、バッファを適宜サイズ変更する必要があります。 安全でないSSL/TLSネゴシエーションを許可 false * sun.security.ssl.allowUnsafeRenegotiationシステム・プロパティ。このシステム・プロパティをtrueに設定すると、透彻な(安全でない)レガシーの再ネゴシエーションが許可されます。 レガシーのHelloメッセージの許可(再ネゴシエーション) true * sun.security.ssl.allowLegacyHelloMessagesシステム・プロパティ。このシステム・プロパティをtrueに設定すると、適切なRFC 5746メッセージを必要とすることなくピアがハンドシェークを実行できます。 デフォルトで有効にされているTLSプロトコル なし jdk.tls.client.protocolsシステム・プロパティ。 クライアント上で特定のSunJSSEプロトコルを有効化するには、援用符で囲んでカンマ区切りリスト神气で指定します。それ之外のサポートされたプロトコルはクライアント上で無効にされます。たとえば、このプロパティの値が"TLSv1,TLSv1.1"の場合、TLSv1とTLSv1.1用のクライアント上のデフォルト・プロトコル設定がクライアント上で使用可能になり、SSLv3、TLSv1.2およびSSLv2Helloはクライアント上で無効になります。 エフェメラルDiffie-Hellman鍵のサイズ 1024ビット jdk.tls.ephemeralDHKeySizeシステム・プロパティ。* このプロパティは現在JSSE実装で使用されていますが、他の実装で調査され、使用されている保証はありません。他の実装で調査する場合は、その実装で、JSSE実装と同じ法式でそれを処理すべきです。プロパティが今後も存在すること、またはシステム型やセキュリティ型が异日のリリースでも変更されないことの保証はされません。
注: java.lang.Systemプロパティを設定してカスタマイズする項目と、java.security.Securityプロパティを設定してカスタマイズする項目があります。次のセクションでは、両方のプロパティ型の値を設定する法式を説明します。
java.lang.Systemプロパティの指定法式JSSEの一部の側面は、システム・プロパティを設定してカスタマイズできます。次のいくつかの法式によって、これらのプロパティを設定できます。
システム・プロパティを静的に設定するには、javaコマンドの-Dオプションを使用します。たとえば、MyAppというアプリケーションを実行して、javax.net.ssl.trustStoreシステム・プロパティを設定し、MyCacertsFileというトラストストアを指定するには、次のように入力します。
java -Djavax.net.ssl.trustStore=MyCacertsFile MyApp
システム・プロパティを動的に設定するには、次のコードでjava.lang.System.setProperty()メソッドを呼び出します。
System.setProperty("propertyName", "propertyValue");
たとえば、システム・プロパティjavax.net.ssl.trustStoreを設定してMyCacertsFileというトラストストアを指定する、前の例に対応したsetProperty呼出しでは:
System.setProperty("javax.net.ssl.trustStore", "MyCacertsFile");
Java配備環境(プラグイン/Web Start)では、いくつかの法式でシステム・プロパティを設定できます。詳細は、Java Platform, Standard Edition配備ガイドを参照してください。
Javaコントロール・パネルを使用して、Runtime Environment PropertyをローカルまたはVM単位で設定します。これにより、ローカルでdeployment.propertiesファイルが作成されます。配備担当開発者はdeployment.configメカニズムを使用して、企業整体のdeployment.propertiesファイルを配布することもできます。詳細については、「配備構成ファイルおよびプロパティ」を参照してください。
特定のアプレットにプロパティを設定するには、<APPLET>タグ内のHTMLサブタグ<PARAM> "java_arguments"を使用します。詳細は、Java Platform, Standard Edition配備ガイドのコマンドライン引数に関する項を参照してください。
特定のJava Web Startアプリケーションまたはアプレット内でPlugin2を使用してプロパティを設定するには、resources身分のJNLP propertyサブ身分を使用します。詳細については、Java Web Startガイドのresources身分に関するセクションを参照してください。
java.security.Securityプロパティの指定法式JSSEの一部の側面は、セキュリティ・プロパティを設定してカスタマイズできます。セキュリティ・プロパティは静的または動的に設定します。
セキュリティ・プロパティを静的に設定するには、セキュリティ・プロパティ・ファイルに1行追加します。セキュリティ・プロパティ・ファイルは、java-home/lib/security/java.securityにあります。
java-homeは、「インストール・ディレクトリ」に説明するように、JREがインストールされているディレクトリを表します。
セキュリティ・プロパティ・ファイルでセキュリティ・プロパティ値を指定するには、次の行を追加します。
propertyName=propertyValue
たとえば、デフォルトのSunX509之外のキー・マネージャ・ファクトリのアルゴリズム名を指定するとします。これを実行するには、ssl.KeyManagerFactory.algorithmというセキュリティ・プロパティの値として、アルゴリズム名を指定します。たとえば、値をMyX509に設定するには、次の行をセキュリティ・プロパティ・ファイルに追加します。
ssl.KeyManagerFactory.algorithm=MyX509
セキュリティ・プロパティを動的に設定するには、次のコードでjava.security.Security.setPropertyメソッドを呼び出します。
Security.setProperty("propertyName," "propertyValue");
たとえば、キー・マネージャ・ファクトリのアルゴリズム名を指定する、前の例に対応したsetProperty()メソッドの呼出しでは:
Security.setProperty("ssl.KeyManagerFactory.algorithm", "MyX509");X509証明書実装のカスタマイズ
X509Certificate.getInstance()メソッドで返されたX509証明書実装は、デフォルトでJSSE実装の実装です。
オプションで、別の実装を返すようにすることもできます。そうするには、他の実装のクラスの名前(およびパッケージ)を、cert.provider.x509v1というセキュリティ・プロパティの値として指定します。たとえば、クラスがMyX509CertificateImplと呼ばれ、com.cryptoxパッケージにある場合、セキュリティ・プロパティ・ファイルに次の行を追加してください。
cert.provider.x509v1=com.cryptox.MyX509CertificateImplHTTPSプロトコルの代替実装の指定
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のエンジン・クラスはSSLContext、KeyManagerFactory、および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.getDefaultやSSLServerSocketFactory.getDefaultを呼び出すことでデフォルトのSSLSocketFactoryやSSLServerSocketFactoryが作成され、このデフォルトの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というトラストストアを検索し、それが存在していれば使用します。java-homeの詳細は、「インストール・ディレクトリ」を参照してください。トラスト・ストアが見つからない場合、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リファレンス実装と同じ法式でそれらを処理してください。
デフォルトのキー・マネージャおよびトラスト・マネージャのカスタマイズ「デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ」で説明したように、デフォルトのSSLSocketFactoryやSSLServerSocketFactoryが作成され、このデフォルトのSSLSocketFactory (またはSSLServerSocketFactory)がJSSEリファレンス実装に由来する場合は、常にデフォルトのSSLContextはソケット・ファクトリに関連付けられます。
デフォルトのSSLContextは、KeyManagerおよびTrustManagerで初期化されます。デフォルトのSSLContextに提供されたKeyManagerとTrustManagerの両方またはどちらか一方は、前のセクションで説明したように、指定したキーストアまたはトラストストアを搞定するための実装になります。
選択されるKeyManager実装は、まずssl.KeyManagerFactory.algorithmセキュリティプロパティを調査することによって決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのKeyManagerFactory実装が検索されます。実装を提供する首先のプロバイダの実装が使用されます。そのgetKeyManagers()メソッドが呼び出され、デフォルトのSSLContextに提供するKeyManagerが決定されます。技術的には、getKeyManagers()は、鍵データの型ごとに1つずつのKeyManagerで、KeyManagerオブジェクトの配列を返します。そのようなセキュリティ・プロパティ値が指定されていない場合、SunX509のデフォルト値を使用して検索を実行します。
注: SunX509アルゴリズムのKeyManagerFactory実装はSunJSSEプロバイダによって提供されます。それが指定するKeyManagerはjavax.net.ssl.X509KeyManager実装です。
同様に、選択されるTrustManager実装は、まずssl.TrustManagerFactory.algorithmセキュリティプロパティを調査することによって決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのTrustManagerFactory実装が検索されます。実装を提供する首先のプロバイダの実装が使用されます。そのgetTrustManagersメソッドが呼び出され、デフォルトのSSLContextに提供するTrustManagerが決定されます。技術的には、getTrustManagers()は、トラスト・データの型ごとに1つずつのTrustManagerで、TrustManagerオブジェクトの配列を返します。そのようなセキュリティ・プロパティ値が指定されていない場合、PKIXのデフォルト値を使用して検索を実行します。
注: PKIXアルゴリズムのTrustManagerFactory実装はSunJSSEプロバイダによって提供されます。それが指定するTrustManagerはjavax.net.ssl.X509TrustManager実装です。
注: このセクションでは、現在のJSSEリファレンス実装の動作を説明します。このセクションで説明するシステム・プロパティの名前と型(システムまたはセキュリティ)が引き続き同じで、异日のリリースにも存在するという保証はありせん。また、他のJSSE実装での検証や使用も保証されていません。実装で検証された場合、ここで説明するように、実装では、JSSEリファレンス実装と同じ法式でそれらを処理してください。
無効化された制限付き暗号化アルゴリズム一部の環境では、TLS/DTLSの使用時は、特定のアルゴリズムまたは鍵の長さが不適切である場合があります。Oracle JDKでは、jdk.certpath.disabledAlgorithmsおよびjdk.tls.disabledAlgorithmセキュリティ・プロパティを使用して、バージョンのネゴシエーション、暗号化神气群の選択、ピア認証および鍵交換メカニズムなど、TLS/DTLSプロトコルのネゴシエーション中にアルゴリズムを無効にします。これらのセキュリティ・プロパティが他のJDK実装によって使用される保証はないことに正经してください。これらのセキュリティ・プロパティの構文とその現在アクティブな値については、<java-home>/lib/security/java.securityファイルを参照してください。
jdk.certpath.disabledAlgorithmsプロパティ: CertPathコードは、このセキュリティ・プロパティを使用してCertPathチェックの際に使用しないアルゴリズムを決定します。たとえば、TLSサーバーによって識別証明書チェーンが送信される場合、受け取ったチェーンをCertPath実装を使用して検証するクライアントTrustManagerでは、示された条目は許可されません。たとえば、次の行は、cacaertsキーストアにプレインストールされている信頼できるアンカーに連鎖するSHA1 TLSServer証明書と同様に、MD2ベースの証明書をブロックします。さらに、この行は、1024ビット未満のRSA鍵をブロックします。
jdk.certpath.disabledAlgorithms=MD2, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024
jdk.tls.disabledAlgorithmsプロパティ: SunJSSEコードは、このセキュリティ・プロパティを使用してTLS/DTLSプロトコル、暗号化スイート、鍵などを無効化します。この構文は、jdk.certpath.disabledAlgorithmsセキュリティ・プロパティに似ています。たとえば、次の行は、SSLv3アルゴリズムおよびすべてのTLS_*_RC4_*暗号化神气群を無効にします。
jdk.tls.disabledAlgorithms=SSLv3, RC4
特定の条目が必要な場合は、java.securityファイル内のセキュリティ・プロパティで関連する値を削除するか、JSSEの初期化前に正しいセキュリティ・プロパティを動的に設定することで、それを再アクティブ化できます。
これらのセキュリティ・プロパティでは暗号化神气群の3番目のセットDisabledが事実上作成されることに正经してください。次のリストで、これら3つのセットを説明します。
Disabled: 暗号化神气群に無効リスト内のコンポーネント(RC4など)が含まれている場合(たとえば、RC4がjdk.tls.disabledAlgorithmsセキュリティ・プロパティで指定されている)、その暗号化神气群は無効になり、接続ハンドシェークに考慮されません。 Enabled: 接続に考慮される特定の暗号化神气群のリストです。 Not Enabled: 接続に考慮されない、無効でない暗号化神气群のリストです。これらの暗号化神气群を再度有効にするには、適切なsetEnabledCipherSuitesまたはsetSSLParametersメソッドを呼び出します。 レガシーの暗号化アルゴリズム一部の環境では、特定のアルゴリズムが望ましくない可能性があっても、それがレガシー・アプリケーションで使用されている場合は無効化できません。レガシー・アルゴリズムは引き続きサポートされますが、时常、レガシー・アルゴリズムはセキュリティ強度が十分でないため、アプリケーションでは使用しないでください。TLS/DTLSセキュリティ・パラメータのネゴシエーション中に、他に候補がない場合を除き、レガシー・アルゴリズムはネゴシエートされません。セキュリティ・プロパティjdk.tls.legacyAlgorithmsでは、Oracle JDKでレガシー・アルゴリズムとみなされるアルゴリズムを指定します。このセキュリティ・プロパティの構文については、<java-home>/lib/security/java.securityファイルを参照してください。
正经:
レガシー・アルゴリズムがjdk.tls.disabledAlgorithmsプロパティまたはjava.security.AlgorithmConstraints API (javax.net.ssl.SSLParameters.setAlgorithmConstraintsメソッドを参照)でも制限されている場合、そのアルゴリズムは透彻に無効化されてネゴシエートされません。 セキュリティ・プロパティjdk.tls.legacyAlgorithmsで指定されたアルゴリズムをアプリケーションで使用している場合は、できるだけ早く別のアルゴリズムを使用してください。异日のJDKリリースでは、レガシー・アルゴリズムが制限付きアルゴリズムに指定される可能性があります。 暗号化アルゴリズム・プロバイダのカスタマイズSunJSSEプロバイダは、その暗号化のすべてニーズに対してSunJCE実装を使用します。プロバイダは时常の位置に置くことが推奨されていますが、SunJCEプロバイダより前に登録することにより、他のJCAまたはJCEプロバイダからの実装を使用できます。セキュリティ・プロパティ・ファイルjava-home/lib/security/java.securityを介して静的に、またはjava.security.SecurityクラスのaddProvider()またはinsertProviderAt()メソッドを介して動的に、標準JCAメカニズムを使用して、プロバイダを構成できます。java-homeについては、「インストール・ディレクトリ」を参照してください。
エフェメラルDiffie-Hellman鍵のサイズのカスタマイズ1024ビット未満のサイズのDiffie-Hellman (DH)鍵は強度が不十分なため、非推奨になりました。JDK 8では、システム・プロパティjdk.tls.ephemeralDHKeySizeによって、ephemeral DH鍵のサイズをカスタマイズできます。このシステム・プロパティは、エクスポート可能な暗号化神气群のServerKeyExchangeメッセージ内のDH鍵のサイズには影響しません。これは、JSSE OracleプロバイダのDHE_RSA、DHE_DSSおよびDH_anonベースの暗号化神气群にのみ影響します。
このプロパティには次のいずれかの値を指定できます。
不决義: 1024ビットのサイズのDH鍵は、常にエクスポート不能能な暗号化神气群に使用されます。これが、このプロパティのデフォルト値です。 legacy: JSSE Oracleプロバイダは、JDK 7过去のリリースのレガシーの動作を保捏しています(512ビットおよび768ビットのサイズのephemeral DH鍵の使用など)。 matched: エクスポート不能能な匿名の暗号化神气群の場合、ServerKeyExchangeメッセージ内のDH鍵のサイズは1024ビットです。X.509証明書ベースの認証(エクスポート不能能な暗号化神气群の)の場合、サイズが1024ビットから2048ビットでなければならないことを除けば、対応する認証鍵に一致するDH鍵のサイズが使われます。たとえば、認証証明書の公開鍵サイズが2048ビットの場合、暗号化神气群がエクスポート可能でないかぎり、ephemeral DH鍵サイズは2048ビットにすべきです。この鍵サイズ設定スキームにより、認証鍵と鍵交換鍵間の暗号化強度の整合性を確保しています。 1024以上2048以下の有効な整数: エクスポート不能能な暗号化神气群に、指定した値の固定のephemeral DH鍵サイズ(ビット単位)が使われます。次の表に、システム・プロパティjdk.tls.ephemeralDHKeySizeの可能性のある各値について、DH鍵の最小および最大許容サイズをまとめています。
jdk.tls.ephemeralDHKeySizeの値 不决義 legacy matched 整数値(固定) エクスポート可能なDH鍵サイズ 512 512 512 512 エクスポート不能能な匿名暗号化神气群 1024 768 1024 固定鍵サイズは有効な整数プロパティ値で指定し、1024以上2048以下である必要があります。 認証証明書 1024 768 鍵サイズは認証証明書と同じですが、1024ビット以上2048ビット以下である必要があります。ただし、SunJCEプロバイダは1024ビットより大きい2048ビットDH鍵のみをサポートします。結果として、使用できる値は1024または2048のみになります。 固定鍵サイズは有効な整数プロパティ値で指定し、1024以上2048以下である必要があります。 Transport Layer Security (TLS)再ネゴシエーションの問題2009年秋に、SSL/TLSプロトコルの問題が見つかりました。IETF TLS Working Groupによってプロトコルの修正が開発され、JDKの現行バージョンにはこの修正が含まれています。このセクションでは、このプロトコル修正を含まない过去の実装との通讯時における相互運用性の問題を含め、状況をさらに詳しく説明します。
この脆弱性により、選択されたプレーン・テキストを接頭辞としてTLS接続に注入できるというMan-In-The-Middle (MITM)攻撃を許していました。この脆弱性は、クライアントとサーバーがセッションのネゴシエーションに奏效した後、傍受されたネットワーク通讯を攻撃者が復号化または変更することを許すものではありません。
詳細については、CVE-2009-3555 (MitreのCommon Vulnerabilities and Exposures List、2009年に投稿)およびTLS再ネゴシエーション攻撃について (Eric Rescorlaのブログ、Educated Guesswork、2009年10月5日)の記事を参照してください。
この問題を解決するためのフェーズ別アプローチこの問題の修正は、2つのフェーズに分けて扱われています。
フェーズ1: プロトコル修正が開発されるまで、SSL/TLSの再ネゴシエーションをデフォルトで無効化する中間修正が、「March 30, 2010 Java SE and Java for Business Critical Patch Update」から把握できるようになりました。
フェーズ2: IETFによって、再ネゴシエーション・プロトコルの問題を扱うRFC 5746が発表されました。次の表に、RFC 5746を実装してセキュアな再ネゴシエーションをサポートする修正を含むJDKおよびJREリリースを示します。
表7: TLS再ネゴシエーション問題の修正を含むJDKおよびJREリリース JDKファミリ 脆弱性のあるリリース フェーズ1の修正(再ネゴシエーションの無効化) フェーズ2の修正(RFC 5746) JDKおよびJRE 6 Update 18过去 更新19-21 Update 22 JDKおよびJRE 5.0 Update 23过去 更新24-25 Update 26 JDKおよびJRE 1.4.2 Update 25过去 更新26-27 Update 28注: 再ネゴシエーションを必要としないアプリケーションはフェーズ2のデフォルト構成に影響を受けません。ただし、再ネゴシエーションを必要とするアプリケーション(首先は匿名のクライアント・ブラウズを許可するが、後でSSL/TLS認証済のクライアントを要求するWebサーバーなど)は:
ピアもRFC 5746に準拠している場合は影響を受けません ピアがRFC 5746にアップグレードしていない場合は影響を受けます(詳細は次のセクションを参照してください) フェーズ2修正の説明SunJSSE実装は、RFC 5746に準拠したピアへの接続について、再ネゴシエーションをデフォルトで再び有効にします。つまり、セキュアに再ネゴシエーションを行うためには、クライアントとサーバーが両方ともRFC 5746をサポートする必要があります。まだアップグレードされていないピアとの接続について、SunJSSEではある进度の相互運用性モードが提供されていますが、ユーザーがクライアントとサーバーの両方の実装をできるだけ早く更新することを強く推奨します。
フェーズ2修正により、SunJSSEは現在3つの再ネゴシエーション相互運用性モードを宅心しています。どのモードもRFC 5746のセキュアな再ネゴシエーションを透彻にサポートしていますが、アップグレードされていないピアと通讯する場合、次のような意味合いが加わります。
厳密モード: クライアントとサーバーの両方がRFC 5746にアップグレードされていること、および適切なRFC 5746メッセージを送信することが求められます。そうでない場合、初期の(または後続の)ハンドシェークが失敗して接続が割断されます。
相互運用モード(デフォルト): 正しいRFC 5746メッセージの使用はオプションですが、適切なメッセージが使用されない場合はレガシーの(元のSSL/TLS仕様の)再ネゴシエーションが無効になります。首先のレガシー接続は許可されますが、レガシーの再ネゴシエーションは無効化されます。これはセキュリティと相互運用性の最適な組み合わせであるため、デフォルト設定です。
セキュアでないモード: レガシーの再ネゴシエーションを透彻に許可します。レガシーのピアとの相互運用性がもっとも高いですが、正本のMITM攻撃に対して脆弱です。
3つのモード分手は、アップグレードされていないピアとの接続にのみ影響します。すべてのクライアントおよびサーバーで厳密モード(透彻なRFC 5746モード)を使用することが望ましいのですが、配備されているすべてのSSL/TLS実装がRFC 5746をサポートするようになるまである进度時間がかかるため、今のところは相互運用モードがデフォルトになっています。
表8に、クライアントとサーバーがRFC 5746をサポートするように更新されている場合と更新されていない場合の様々な例でのモードに関する相互運用性格報を示しています。
表8: 相互運用性格報 クライアント サーバー モード 更新済み 更新済みすべてのモードで再ネゴシエーションがセキュリティ保護されます。
レガシー 脚注1 更新済み 厳密クライアントが適切なRFC 5746メッセージを送信しない場合、首先の接続がサーバーによってすぐに割断されます(SSLHandshakeExceptionまたはhandshake_failure)。 相互運用可能: レガシー・クライアントからの初期接続(RFC 5746メッセージが欠落している)は許可されますが、再ネゴシエーションはサーバーによって許可されません。 脚注2 脚注3 セキュアでないレガシー・クライアントとの接続および再ネゴシエーションは許可されますが、元のMITM攻撃に対して脆弱です。 更新済み レガシー 脚注1 厳密サーバーが正しいRFC 5746メッセージで応答しない場合、クライアントは接続をすぐに割断します(SSLHandshakeExceptionまたはhandshake_failure)。 相互運用可能レガシー・サーバーからの初期接続(RFC 5746メッセージが欠落している)は許可されますが、再ネゴシエーションはサーバーによって許可されません。脚注2 脚注3 セキュアでないレガシー・サーバーとの接続および再ネゴシエーションは許可されますが、元のMITM攻撃に対して脆弱です。 レガシー 脚注1 レガシー 脚注1 既存のSSL/TLS動作を行い、MITM攻撃に対して脆弱です。脚注1 「レガシー」とは元のSSL/TLS仕様を意味します(つまり、RFC 5746でない)。
脚注2 SunJSSEフェーズ1実装は、昭示的に再有効化されないかぎり再ネゴシエーションを拒否します。再ネゴシエーションが再有効化された場合、それらは正しいRFC 5746メッセージを送信しないため、RFC 5746に準拠したピアによって「レガシー」として扱われます。
脚注3 SSL/TLSでは、再ネゴシエーションをいずれの側からでも開始できます。フェーズ1修正のように、アップグレードされていないピアと相互運用モードで通讯しているアプリケーションが(SSLSocket.startHandshake()またはSSLEngine.beginHandshake()を使用して)再ネゴシエーションを開始しようとすると、アプリケーションはSSLHandshakeException (IOException)を受け取り、接続は住手されます(handshake_failure)。まだアップグレードされていないピアから再ネゴシエーション要求を受け取ったアプリケーションは、現在の接続のタイプに応じて応答します。
TLSv1no_renegotiation(100)タイプの熏陶メッセージがピアに送信され、接続は開いたままになります。古いバージョンのSunJSSEは、no_renegotiationアラートを受け取ると接続を住手します。 SSLv3 アプリケーションはSSLHandshakeExceptionを受け取り、接続は閉じられます(handshake_failure)。no_renegotiationアラートはSSLv3仕様に定義されていません。モードを設定するために、次のシステム・プロパティを使用します。
sun.security.ssl.allowUnsafeRenegotiation (フェーズ1で導入)は、レガシー(安全でない)再ネゴシエーションを許可するかどうかを制御します。 sun.security.ssl.allowLegacyHelloMessages (フェーズ2で導入)は、適切なRFC 5746メッセージを必要とすることなくピアがハンドシェーク・プロセスを実行することを許可します。 表9: 相互運用性モードを設定するためのシステム・プロパティの値 モード allowLegacyHelloMessages allowUnsafeRenegotiation 厳密 false false 相互運用(デフォルト) true false セキュアでない true true正经: セキュアでないSSL/TLS再ネゴシエーションは、脆弱性が再確立されるため、再有効化しないでください。
システム・プロパティを設定することによって特定のモードを構成する法式については、「java.lang.Systemプロパティの設定法式」を参照してください。
SSL/TLS再ネゴシエーションに対する侧目法式と代替法式すべてのピアは、できるだけ早くRFC 5746準拠の実装に更新する必要があります。このRFC 5746修正を適用しても、再ネゴシエーションが必要な場合は、アップグレードされていないピアとの通讯に影響が生じます。推奨されるいくつかの法式を次に示します。
ピアを再構築して再ネゴシエーションを要求しないようにする。
再ネゴシエーションは时常、Webサーバーが首先は匿名のクライアント・ブラウズを許可するが、後でSSL/TLS認証済クライアントを要求する場合や、Webサーバーが首先は弱い暗号化神气群を許可するが、後で強い暗号化神气群を必要とする場合に、Webサーバーによって使用されます。代替策は、首先のネゴシエーション中にクライアント認証および強い暗号化神气群を必要とすることです。これを行うには、2つの選択肢があります。
アプリケーションに、あるポイントに到達して、再ネゴシエーションが必要になるまでの「ブラウズ・モード」がある場合、「ブラウズ・モード」を削除し、すべての初期接続を強化するようにサーバーを再構築できます。
サーバーを2つのエンティティに分割して、1つのエンティティ上でブラウズ・モードを実行し、2つ目のエンティティをよりセキュアなモードで使用します。ネゴシエーション・ポイントに到達したら、関連情報をサーバー間で転送します。
これらのどちらのオプションも、ある进度の作業が必要ですが、元のセキュリティ上の欠陥が再度発生することはありません。
システム・プロパティを使用して、再ネゴシエーション相互運用性モードを「セキュアでない」に設定します。
情報と熏陶については、「フェーズ2修正の説明」を参照してください。
実装の詳細RFC 5746では2つの新しいデータ構造が定義されており、上級ユーザーのために、ここで説明します。
Signaling Cipher Suite Value (SCSV)と呼ばれる擬似暗号化神气群、「TLS_EMPTY_RENEGOTIATION_INFO_SCSV」 Renegotiation Info (RI)と呼ばれるTLS拡張。これらのいずれも、実装がRFC 5746に準拠していることと、セキュアな再ネゴシエーションが実行できることを见告するために使用できます。関連する技術的な議論については、2009年11月から2010年2月までのIETFの電子メールによる議論を参照してください。
RFC 5746により、クライアントは首先のClientHelloでSCSVまたはRIを送信できます。相互運用性を最大限に高めるため、SunJSSEはデフォルトでSCSVを使用しますが、これは、いくつかのTLSサーバー/SSLサーバーが不解な拡張機能を正しく処理できないためです。有効化された暗号化神气群(SSLSocket.setEnabledCipherSuites()またはSSLEngine.setEnabledCipherSuites())にSCSVが存在することによって、首先のClientHello内でSCSVを送信するか、あるいはRIをかわりに送信すべきかどうかが判別されます。
SSLv2はSSL/TLS拡張機能をサポートしません。SSLv2Helloプロトコルが有効化された場合、SCSVが首先のClientHello内で送信されます。
フェーズ1修正の説明前述のとおり、フェーズ1修正は、RFC 5746に準拠した修正が開発されるまでの間、再ネゴシエーションをデフォルトで無効にするためのものでした。再ネゴシエーションは、sun.security.ssl.allowUnsafeRenegotiationシステム・プロパティを設定することによって再び有効化できました。フェーズ2修正では同じsun.security.ssl.allowUnsafeRenegotiationシステム・プロパティを使用するだけでなく、それにRFC 5746メッセージを使用させる必要もあります。
すべてのアプリケーションを、できるだけ早くフェーズ2 RFC 5746修正にアップグレードする必要があります。
SSL/TLS再ネゴシエーションにおける安全でないサーバー証明書の変更の許可次の場合、SSL/TLS再ネゴシエーションでサーバー証明書を変更することは、安全でないことがあります。
エンドポイント識別がSSL/TLSハンドシェークで有効でない場合、および 过去のハンドシェークがセッション再開不详初期ハンドシェークである場合、および 両方の証明書によって表されるアイデンティティが同じと見なせる場合。2つの証明書は、次の場合に、同じアイデンティティを表すと見なせます。
IPアドレスのサブジェクトの代替名が両方の証明書に存在する場合、吞并であるはずです。または、 DNS名のサブジェクトの代替名が両方の証明書に存在する場合、吞并であるはずです。または、 サブジェクト・フィールドが両方の証明書に存在する場合、証明書のサブジェクトと発行东说念主は吞并であるはずです。JDK 8u25以降では、SSL/TLS再ネゴシエーションでの安全でないサーバー証明書の変更は、デフォルトでできません。新しいシステム・プロパティjdk.tls.allowUnsafeServerCertChangeを使用して、SSL/TLS再ネゴシエーションにおける安全でないサーバー証明書の変更を制限するかどうかを定義できます。
このシステム・プロパティのデフォルト値はfalseです。
正经: どうしても必要でないかぎり、このシステム・プロパティを"true"に設定しないでください。安全でないサーバー証明書変更の脆弱性が再び確立される可能性があります。
ハードウェア高速化およびスマート・カードのサポート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暗号化神气群をサポートします。次の暗号化神气群がサポートされていますが、デフォルトでは有効になっていません。
TLS_KRB5_WITH_RC4_128_SHA TLS_KRB5_WITH_RC4_128_MD5 TLS_KRB5_WITH_3DES_EDE_CBC_SHA TLS_KRB5_WITH_3DES_EDE_CBC_MD5 TLS_KRB5_WITH_DES_CBC_SHA TLS_KRB5_WITH_DES_CBC_MD5 TLS_KRB5_EXPORT_WITH_RC4_40_SHA TLS_KRB5_EXPORT_WITH_RC4_40_MD5 TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5これらの暗号化神气群を使用できるようにするには、昭示的に指定する必要があります。詳細については、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()メソッドを使用します。
javax.net.ssl.SSLSession javax.net.ssl.HttpsURLConnection javax.net.HandshakeCompletedEvent同様に、(ローカル・エンティティを識別するために)ピアに送信された識別情報を赢得するには、これらのクラスでgetLocalPrincipal()メソッドを使用します。X509ベースの暗号化神气群の場合、これらのメソッドはjavax.security.auth.x500.X500Principalのインスタンスを返します。Kerberos暗号化神气群の場合、これらのメソッドはjavax.security.auth.kerberos.KerberosPrincipalのインスタンスを返します。
JSSEアプリケーションは、getPeerCertificates()と、javax.net.ssl.SSLSession、javax.net.ssl.HttpsURLConnection、javax.net.HandshakeCompletedEventの類似のメソッドを使用して、ピアに関する情報を赢得します。ピアに証明書がない場合、SSLPeerUnverifiedExceptionがスローされます。
アプリケーションでピアの識別情報またはピアに送信された識別情報のみを判別する必要がある場合は、それぞれgetPeerPrincipal()およびgetLocalPrincipal()メソッドを使用してください。getPeerCertificates()およびgetLocalCertificates()メソッドは、それらの証明書の实验を調べる必要がある場合にのみ使用してください。また、アプリケーションでは、認証されたピアに証明書がない場合の処理を準備しておく必要があります。
セキュリティ・マネージャセキュリティ・マネージャが有効な場合、ピアとの通讯に必要なSocketPermissionに加えて、Kerberos暗号化神气群を使用するTLSクライアント・アプリケーションには次のアクセス権も必要です。
javax.security.auth.kerberos.ServicePermission(serverPrincipal, "initiate");
前のコードで、serverPrincipalは、TLSクライアントが通讯するTLSサーバーのKerberosプリンシパル名です(host/mach1.imc.org@IMC.ORGなど)。TLSサーバー・アプリケーションには、次のアクセス権が必要です。
javax.security.auth.kerberos.ServicePermission(serverPrincipal, "accept");
前のコードで、serverPrincipalは、TLSサーバーのKerberosプリンシパル名です(host/mach1.imc.org@IMC.ORGなど)。サーバーまたはクライアントがKDCに接続する必要がある場合(そのクレデンシャルがローカルにキャッシュされていない場合など)、次のアクセス権も必要です。
javax.security.auth.kerberos.ServicePermission(tgtPrincipal, "initiate");前のコードで、tgtPrincipalはKDCのプリンシパル名です(krbtgt/IMC.ORG@IMC.ORGなど)。 その他のキーストア神气(PKCS12)
PKCS#12 (Personal Information Exchange Syntax Standard)では、移植可能な保存思气、およびユーザーの非公開鍵、証明書、その他の深重およびほかの項目の転送について規定されています。SunJSSEプロバイダは、PKCS12ファイルの読取りおよび書込みのためのPKCS12 java.security.KeyStore神气の透彻な実装を提供します。この神气は、Netscape/Mozilla、MicrosoftのInternet Explorer、OpenSSLなどほかのツールキットやアプリケーションでもサポートされ、鍵と証明書をインポートおよびエクスポートします。たとえば、これらの実装は、クライアントの証明書と鍵を.p12ファイル名拡張子を使用してファイルにエクスポートできます。
SunJSSEプロバイダでは、PKCS12のキーストア・タイプを使用して、KeyStore APIを介してPKCS12鍵にアクセスできます。さらにkeytoolコマンドと、pkcs12に設定された-storetypeオプションを使用して、インストールされた鍵および関連する証明書を暗意できます。keytoolの詳細は、「セキュリティ・ツール」を参照してください。
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の動作の例を示しています。
www\\.example\\.comに構成されたマッチャ:
要求されたホスト名がwww.example.comの場合、それは受け付けられ、ServerHelloメッセージで確認が送信されます。 要求されたホスト名がwww.example.orgの場合、それはunrecognized_name致命的エラーで拒否されます。 要求されたホスト名がないか、空の場合、要求は受け付けられますが、ServerHelloメッセージで確認が送信されません。www\\.invalid\\.comに構成されたマッチャ:
要求されたホスト名がwww.example.comの場合、それはunrecognized_name致命的エラーで拒否されます。 要求されたホスト名がwww.example.orgの場合、それは受け付けられ、ServerHelloメッセージで確認が送信されます。 要求されたホスト名がないか、空の場合、要求は受け付けられますが、ServerHelloメッセージで確認が送信されません。マッチャが構成されていない:
要求されたすべてのホスト名が受け付けられますが、ServerHelloメッセージで確認は送信されません。
SNI拡張を実装する新しいクラスの説明については、次を参照してください。
StandardConstantsクラス SNIServerNameクラス SNIMatcherクラス SNIHostNameクラスたとえば、「Server Name Indication (SNI)拡張の使用」を参照してください。
トラブルシューティングこのセクションにはJSSEのトラブルシューティングに関する情報が含まれます。まず、一般的な構成の問題とそれらの解決法式を説明し、次に、役に立つデバッグ・ユーティリティについて説明します。
構成上の問題点このセクションでは、JSSEの使用時に発生する可能性のある一般的な構成の問題について説明します。
ハンドシェーク時のCertificateException問題: SSL接続のネゴシエーション中に、クライアントまたはサーバーがCertificateExceptionをスローします。
原因1: 一般に、リモート側がローカル側に不解な証明書を送信することが原因です。
解決法1: このタイプの問題をデバッグするもっともよい法式は、デバッグをオンにして(「デバッグ・ユーティリティ」を参照)、証明書のロード時およびネットワーク接続経由での証明書の受信時に観察することです。多くの場合、間違ったトラスト・ファイルをロードしたため、受信した証明書がトラスト・メカニズムにとって不解です。詳細については、次のセクションを参照してください。
JSSEクラスとインタフェース TrustManagerインタフェース KeyManagerインタフェース原因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を参照してください。
正しいキーストアおよび証明書を渡す法式については、次のセクションを参照してください。
JSSEクラスとインタフェース デフォルトのキーストアとトラストストア、ストア・タイプおよびストア・パスワードのカスタマイズ その他のキーストア神气 実行時例外: 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 rsaJSSEの首先のアクセスが遅い
問題: 首先のアクセスで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メッセージを受信した場合、接続を割断するものがあります。
解決法: クライアント側で、有効なプロトコルの調整を試みてください。これには、次のシステム・プロパティやメソッドの変更や呼び出しが含まれます。
HttpsURLConnectionクラスのシステム・プロパティhttps.protocols システム・プロパティjdk.tls.client.protocols SSLContext.getInstanceメソッド SSLEngine.setEnabledProtocolsメソッド SSLSocket.setEnabledProtocolsメソッド SSLParameters.setProtocolsおよびSSLEngine.setSSLParametersメソッド SSLParameters.setProtocolsおよびSSLSocket.setSSLParametersメソッド Some older server implementations speak only SSLv3 and do not understand TLS. Ideally, these implementations should negotiate to SSLv3, but some simply hang up. For backwards compatibility, some SSL/TLS implementations (such as SunJSSE) can send SSLv3/TLS ClientHello messages encapsulated in an SSLv2 ClientHello packet. The SunJSSE provider supports this feature. (See the section Protocols, which lists the protocols that are enabled by default for the SunJSSE provider.) If you want to use this feature, add the SSLv2Hello protocol to the enabled protocol list, if necessary.Similarly, some other older server implementations can speak to TLSv1 but do not understand TLSv1.1 or TLSv1.2. In this situation, consider using a SSL/TLS version fallback scheme:
-->後方互換性のため、一部のSSL/TLS実装(SunJSSEなど)はSSL/TLSのClientHelloメッセージをSSLv2のClientHello神气にカプセル化して送信できます。SunJSSEプロバイダはこの機能をサポートしています。この機能を使用する場合は、必要に応じて「SSLv2Hello」を有効なプロトコル・リストに追加します。(SunJSSEプロバイダでデフォルトで有効にされているプロトコルを一覧暗意しているセクション「プロトコル」も参照してください。)
SSL/TLS RFC標準で、実装は、両側で使用されている最新バージョンとネゴシエーションする必要がありますが、認識できないバージョンを提醒されると、一部の非準拠実装は単にハングアップします。たとえば、SSLv3のみを認識する一部の古いサーバー実装は、TLSv1.2を要求されると、シャットダウンします。この状況では、SSL/TLSバージョンのフォールバック・スキームを使用することを検討してください。
サーバーでTLSv1.2を融合しない場合、TLSv1.2からTLSv1.1にフォールバックします。 前のステップが機能しない場合は、TLSv1.1からTLSv1.0にフォールバックします。たとえば、クライアントの有効なプロトコル・リストがTLSv1、TLSv1.1およびTLSv1.2の場合、一般的なSSL/TLSバージョンのフォールバック・スキームが次のように見えます。
サーバーに接続を試みます。サーバーがSSL/TLS接続要求をただちに拒否した場合は、ステップ2に進みます。 有効なプロトコル・リスト内の最高のプロトコル・バージョン(首先の失敗の場合TLSv1.2など)を削除して、バージョン・フォールバック・スキームを試行します。 再度サーバーに接続を試みます。サーバーが接続を拒否した場合、サーバーがフォールバックできるバージョンがない場合を除いて、ステップ2に進みます。 接続が失敗し、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はStandard Extension 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ディレクティブが正しく構成されていることを確認してください。
詳細については、次の情報を参照してください。
「Apache HTTP Server Wiki」の「SSL with Virtual Hosts Using SNI」 「Apache HTTP Server Documentation」の「SSL/TLS Strong Encryption: FAQ」 RFC 3546、Transport Layer Security (TLS) Extensions バグ7194590: SSL handshaking error caused by virtual server misconfiguration デバッグ・ユーティリティJSSEには、動的デバッグのトレースをサポートする機能があります。これは、Java SE プラットフォームでデバッグのアクセス制御に失敗した場合に使用するサポート機能に似ています。一般的なJava動的デバッグ・トレースのサポートにはjava.security.debugシステム・プロパティを使用してアクセスしますが、JSSE固有の動的デバッグ・トレースのサポートにはjavax.net.debugシステム・プロパティを使用してアクセスします。
注: debugユーティリティは、公式にサポートされているJSSEの機能ではありません。
JSSE動的デバッグ・ユーティリティのオプションを暗意するには、javaコマンドで次のコマンド行オプションを使用します。
-Djavax.net.debug=help
注: ユーティリティがデバッグするように設計されたクラスを使用しないプログラムの実行中に、いずれかの動的デバッグ・ユーティリティで値helpを指定しても、デバッグ・オプションは得られません。
次の透彻な例では、いくつかのJSSEクラスを使用するMyAppというアプリケーションのデバッグ・オプションのリストを赢得する法式を示しています。
java -Djavax.net.debug=help MyApp
MyAppアプリケーションは、デバッグのヘルプ情報が暗意されると動作しなくなりますが、これはヘルプコードによりアプリケーションが終了するためです。
現在のオプション:
all: すべてのデバッグを有効にします ssl: SSLデバッグを有効にしますsslオプションとともに次のオプションを使用できます:
record: レコードごとのトレースを有効にします handshake: 各ハンドシェーク・メッセージを出力します keygen: 鍵生成データを出力します session: セッション・アクティビティを出力します defaultctx: デフォルトのSSL初期化を出力します sslctx: SSLContextのトレースを出力します sessioncache: セッション・キャッシュのトレースを出力します keymanager: キー・マネージャのトレースを出力します trustmanager: トラスト・マネージャのトレースを出力しますhandshakeオプションによって生成されるメッセージは、次のオプションで拡張できます:
data: 各ハンドシェイク・メッセージの16進ダンプ verbose: ハンドシェイク・メッセージの詳細出力recordオプションによって生成されるメッセージは、次のオプションで拡張できます:
plaintext: レコードのプレーン・テキストの16進ダンプ packet: raw SSL/TLSパケットを出力しますjavax.net.debugプロパティ値は、allまたはsslを指定する必要があり、オプションでデバッグ指定子をその後に続けます。1つまたは複数のオプションが使用できます。オプションをセパレータで区切る必要はありませんが、コロン(:)やカンマ(,)などの区切り笔墨を使用すると読みやすくなります。どのセパレータでも使用でき、オプション・キーワードの順序も蹙迫ではありません。
このデバッグ情報の見方の説明は、ガイド「SSL/TLS接続のデバッグ」を参照してください。
次に、javax.net.debugプロパティの使用例を示します。
デバッグ・メッセージをすべて暗意する場合は、次のように入力します。
java -Djavax.net.debug=all MyApp
各ハンドシェーク・メッセージを16進ダンプで暗意するには、次のように入力します(コロンはオプションです)。
java -Djavax.net.debug=ssl:handshake:data MyApp
各ハンドシェーク・メッセージを16進ダンプで暗意し、さらにトラスト・マネージャのトレース状態を暗意するには、次のように入力します(カンマはオプションです)。
java -Djavax.net.debug=SSL,handshake,data,trustmanager MyAppコード例
このセクションには次のコード例が含まれています。
セキュアでないソケットからセキュアなソケットへの変換 SSLを使用しないソケットの例 SSLを使用するソケットの例 JSSEサンプル・コードの実行 クライアントとサーバーのセキュアなソケット接続を表すサンプル・コード 構成要件 SSLSocketClientの実行 SSLSocketClientWithTunnelingの実行 SSLSocketClientWithClientAuthの実行 ClassFileServerの実行 ClassFileServerによるSSLSocketClientWithClientAuthの実行 HTTPS接続を表すサンプル・コード URLReaderの実行 URLReaderWithOptionsの実行 セキュアなRMI接続を表すサンプル・コード SSLEngineの使用を表すサンプル・コード SSLEngineSimpleDemoの実行 NIOベースのサーバーの実行 JSSEで使用するキーストアの作成 Server Name Indication (SNI)拡張の使用 一般的なクライアント側使用例 一般的なサーバー側使用例 仮想インフラストラクチャの操作 ClientHelloパーサーの準備 SSLSocketに基づいた仮想サーバー・ディスパッチャ SSLEngineに基づいた仮想サーバー・ディスパッチャ 使用可能なSNI拡張がない SSLContextのフェールオーバー セキュアでないソケットからセキュアなソケットへの変換このセクションでは、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を使って次の処理を行う法式を示します。
クライアントとサーバーの間のセキュアなソケット接続の作成 HTTPS Webサイトへのセキュアな接続の作成 RMIでのセキュアな通讯 SSLEngineの使用サンプル・コードを使用する場合、サンプル・プログラムは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の実行」に示しています。同様の変更をして、URLReader、SSLSocketClientまたはSSLSocketClientWithTunnelingをClassFileServerで実行できます。
クライアントとサーバーとの間で通讯中に認証エラーが発生する場合(WebサーバーとClassFileServerのどちらを使用しているか関係なく)、必要な鍵がトラストストア(トラスト鍵データベース)にないためである可能性があります。たとえば、ClassFileServerは、SSLハンドシェーク中に必要なlocalhostの公開鍵を格納するtestkeysというキーストアを使用します。testkeysキーストアはClassFileServerソースと同じsamples/sockets/serverディレクトリにあります。参照するトラストストアで、localhostの対応する公開鍵の証明書をクライアントが見つけられない場合、認証エラーが発生します。次のセクションで説明するように、samplecacertsトラストストア(localhostの公開鍵と証明書を格納する)を使用してください。
構成要件クライアントとサーバーとの間のセキュアなソケット接続を作成するサンプル・プログラムを実行する場合は、適切な証明書ファイル(トラストストア)を把握できるようにしておく必要があります。クライアント・プログラムとサーバー・プログラムの両方で、samplesディレクトリのsamplecacerts証明書ファイルを使用してください。この証明書ファイルを使用すると、クライアントがサーバーを認証できるようになります。このファイルには、JDK (cacertsファイルにある)に付属する一般的な証明書発行局(CA)のすべての証明書と、サンプルサーバーClassFileServerとの通讯時にクライアントがlocalhostを認証するために必要なlocalhostの証明書が含まれています。ClassFileServerは、samplecacertsの公開鍵に対応するlocalhostの公開鍵を含むキーストアを使用します。
クライアントとサーバーの両方でsamplecacertsファイルを使用できるようにするには、それをjava-home/lib/security/jssecacertsファイルにコピーして名前をcacertsに変更し、java-home/lib/security/cacertsファイルと置き換えるか、クライアントとサーバーの両方に対してjavaコマンドを実行する場合に、次のオプションをコマンド行に追加します。
-Djavax.net.ssl.trustStore=path_to_samplecacerts_file
java-homeの詳細は、「JREインストール・ディレクトリ」を参照してください。
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.javaとClassServer.javaの2つのファイルで構成されています。
これらを実行するには、ClassFileServer.classを実行します。その際は次のパラメータが必要です。
portは、把握できる未使用のポート番号です。たとえば、2001のような数字を使用できます。 docrootは、赢得するファイルを含むサーバーのディレクトリを表します。たとえば、Solarisでは/home/userid/ (useridは特定のUIDを表す)を使用でき、Microsoft Windowsシステムではc:\を使用できます。 TLSは、サーバーがSSLを使用するかTLSを使用するかを示すオプションのパラメータです。 trueは、クライアント認証が必要であることを示すオプションのパラメータです。このパラメータは、TLSパラメータが設定されているかどうかだけを参照します。注: TLSおよびtrueパラメータはオプションです。それらを不详した場合は、TLSではない时常のファイルサーバーを認証なしで使用し、何も起こらないことを示します。これは、一方の側(クライアント)がTLSとネゴシエーションを行おうとしても、もう一方の側(サーバー)は行おうとしないため、通讯ができないからです。
注: サーバーはGET /path_to_fileの神气でGET要求を期待します。
ClassFileServerによるSSLSocketClientWithClientAuthの実行サンプル・プログラムSSLSocketClientWithClientAuthおよび ClassFileServerを使用して、認証済の通讯を設定できます。この通讯では、クライアントとサーバーが相互に認証します。サンプルのプログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウまたはコマンド・プロンプト・ウィンドウから両方を実行することもできます。クライアントとサーバーの両方を設定するには、次を実行します。
「ClassFileServerの実行」に示すように、ClassFileServerプログラムを1台のマシンやターミナル・ウィンドウから実行します。 SSLSocketClientWithClientAuthプログラムを別のマシンやターミナル・ウィンドウで実行します。SSLSocketClientWithClientAuthには、次のパラメータが必要です。 hostは、ClassFileServerを実行するために使用するマシンのホスト名です。 portは、ClassFileServerに指定したものと同じポートです。requestedfilepathは、サーバーから赢得するファイルのパスを示します。このパラメータには、/filepathと指定する必要があります。GET文の一部として使用されるので、ファイル・パスにはフォワード・スラッシュが必要です。GET文には、稼動中のオペレーティング・システムの種類にかかわらず、フォワード・スラッシュが必要です。文の構成は次のようになります。
"GET " + requestedfilepath + " HTTP/1.0"
注: ClassFileServerが動作しているローカル・マシンに接続するように、他のSSLClient*アプリケーションのGETコマンドを変更できます。
午夜伦理伦理片在线观 HTTPS接続を表すサンプル・コードJSSEを介してセキュアな通讯にアクセスするためのプライマリAPIは2つあります。1つの法式は、SSLSocketClient、SSLSocketClientWithTunnelingおよび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.javaとURLReaderWithOptions.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");
Note: When running on Windows 95 or Windows 98, the maximum number of characters allowed in an MS-DOS prompt may not be enough to include all the command-line options. If you encounter this problem, either create a BAT file with the entire command or add the system properties to the source code and recompile the source code.
--> URLReaderWithOptionsの実行URLReaderWithOptions.javaプログラムは基本的にはURLReader.javaプログラムと同じですが、実行時にプログラムの引数として次のシステム・プロパティのどれか、または一皆をオプションで入力できる点が異なります。
java.protocol.handler.pkgs https.proxyHost https.proxyPort https.cipherSuitesURLReaderWithOptionsを実行するには、次のコマンドを入力します。
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の整体的な機能の説明に有效です。
NIOベースのサーバーの実行SSLEngineによって提供される柔軟性を十分に把握するには、首先にI/Oやスレッド・モデルなどの相補的なAPIを融合する必要があります。
大規模なアプリケーションの開発者が有效と考えるI/Oモデルは、NIO SocketChannelです。NIOは、java.net.Socket APIに内在するスケーリングの問題のいくつかを解決するために部分的に導入されました。SocketChannelには、次のような様々な操作モードがあります。
ブロック 非ブロック セレクタによる非ブロック新しい多くのNIO APIを示すだけでなく、セキュアなHTTPSサーバーを作成するためにSSLEngineを採用する法式も示す、基本的なHTTPサーバーのサンプル・コードが提供されています。サーバーは本番稼動の品質ではありませんが、これらの多くの新しいAPIの動作を示しています。
サンプル・ディレクトリにはREADME.txtファイルがあり、サーバーの紹介、サーバーの構築および構成法式の説明、コード・レイアウトの节录が含まれています。SSLEngineのユーザーにとってもっとも蹙迫なファイルは、ChannelIO.javaおよびChannelIOSecure.javaです。
注: このセクションで説明するサーバーの例は、JDKに含まれています。コードは、jdk-home/samples/nio/serverディレクトリにバンドルされています。
JSSEで使用するキーストアの作成このセクションでは、keytoolユーティリティを使用して、JSSEでの使用に適した単純なJKSキーストアを作成する法式を説明します。まずキーストア内に(公開鍵および深重鍵を捏つ) keyEntryを作成し、トラストストア内に対応するtrustedCertEntry (公開鍵のみ)を作成します。クライアント認証の場合、クライアントの証明書に対して同様の処理に従う必要があります。
注: PKCS12での信頼できるアンカーおよび深重鍵の格納は、JDK 8以降でサポートされています。
注: ここでは、各ステップに関する詳しい解説は不详します。詳細は、Solaris、LinuxまたはMac OS XまたはMicrosoft Windowsのkeytoolのドキュメントを参照してください。
ユーザー入力は太字で示します。
対応する公開鍵および深重鍵によって、新しいキーストアと我方签字付き証明書を作成します。
% 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>
キーストアを調べます。エントリの型は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
我方签字付き証明書をエクスポートし、实验を調べます。
% 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 -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
トラストストアを調べます。エントリの型は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
ここで、適切なキーストアを使用してアプリケーションを実行します。この例では、デフォルトの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)拡張を使用する法式およびそれを仮想インフラストラクチャに適用する法式を示すコード例について説明します。
このセクションのすべての例で、パラメータの設定後にそれらを適用するには、対応するSSLSocket、SSLEngineまたはSSLServerSocketオブジェクトで、setSSLParameters(SSLParameters)メソッドを呼び出します。
一般的なクライアント側使用例次は、クライアント・アプリケーションを開発するためにSNI拡張の融合を必要とするユース・ケースのリストです。
ケース1. クライアントはwww.example.comにアクセスする必要があります。
ホスト名を昭示的に設定します。
SNIHostName serverName = new SNIHostName("www.example.com"); List<SNIServerName> serverNames = new ArrayList<>(1); serverNames.add(serverName); sslParameters.setServerNames(serverNames);
クライアントは常にホスト名を昭示的に指定してください。
ケース2. サーバーでサポートしていないため、クライアントはSNIを使用する必要はありません。
空のサーバー名リストでSNIを無効にします。
List<SNIServerName> serverNames = new ArrayList<>(1); sslParameters.setServerNames(serverNames);
ケース3. クライアントはURL https://www.example.comにアクセスする必要があります。
OracleプロバイダはデフォルトでSNI拡張にホスト名を設定しますが、サード・パーティ・プロバイダがデフォルトのサーバー名暗意をサポートしていないことがあります。アプリケーションでプロバイダに依存しないようにするには、常にホスト名を昭示的に設定します。
ケース4. クライアントはソケットをサーバー・モードからクライアント・モードに切り替える必要があります。
まず、メソッドsslSocket.setUseClientMode(true)でモードを切り替えます。次に、ソケットでサーバー名暗意パラメータをリセットします。
一般的なサーバー側使用例次は、サーバー・アプリケーションを開発するためにSNI拡張の融合を必要とするユース・ケースのリストです。
ケース1. サーバーはすべてのサーバー名暗意タイプを受け付ける必要があります。
SNI拡張を処理するコードがない場合、サーバーはすべてのサーバー名暗意型を無視します。
ケース2. サーバーは型 host_nameのすべてのサーバー名暗意型を拒否する必要があります。
host_nameに無効なサーバー名パターンを設定します。
SNIMatcher matcher = SNIHostName.createSNIMatcher(""); Collection<SNIMatcher> matchers = new ArrayList<>(1); matchers.add(matcher); sslParameters.setSNIMatchers(matchers);
他の法式は、matches()メソッドで、常にfalseを返すSNIMatcherサブクラスを作成することです。
class DenialSNIMatcher extends SNIMatcher { DenialSNIMatcher() { super(StandardConstants.SNI_HOST_NAME); } @Override public boolean matches(SNIServerName serverName) { return false; } } SNIMatcher matcher = new DenialSNIMatcher(); Collection<SNIMatcher> matchers = new ArrayList<>(1); matchers.add(matcher); sslParameters.setSNIMatchers(matchers);
ケース3. サーバーはexample.comドメイン内のすべてのホスト名への接続を受け付ける必要があります。
すべての*.example.comアドレスを含むパターンとして、host_nameの認識可能なサーバー名を設定します。
SNIMatcher matcher = SNIHostName.createSNIMatcher("(.*\\.)*example\\.com"); Collection<SNIMatcher> matchers = new ArrayList<>(1); matchers.add(matcher); sslParameters.setSNIMatchers(matchers);
ケース4. サーバーはソケットをクライアント・モードからサーバー・モードに切り替える必要があります。
まず、メソッドsslSocket.setUseClientMode(false)でモードを切り替えます。次に、ソケットでサーバー名暗意パラメータをリセットします。
仮想インフラストラクチャの操作このセクションでは、仮想インフラストラクチャ内からServer Name Indication (SNI)拡張を使用する法式について説明します。ここでは、ソケットからのClientHelloメッセージのパーサーの作成法式を示し、SSLSocketおよびSSLEngineを使用した仮想サーバー・ディスパッチャの例を示し、SNI拡張を使用できない場合に何が発生するかを説明して、フェールオーバーSSLContextを作成する法式を示します。
ClientHelloパーサーの準備アプリケーションはソケットからのClientHelloメッセージを领略するAPIを実装する必要があります。次の例に、これらの機能を実行できるSSLCapabilitiesクラスとSSLExplorerクラスを示します。
SSLCapabilities.javaはハンドシェーク中にSSL/TLSセキュリティ機能をカプセル化します(つまり、SSL/TLSハンドシェークで受け付けられる暗号化神气群のリスト、レコード・バージョン、helloバージョン、サーバー名暗意)。それは、SSLExplorer.explore()メソッドによって、SSL/TLS接続のネットワーク・データを調べることによって赢得できます。
SSLExplorer.javaはTLSクライアントからの初期ClientHelloメッセージを調査しますが、ハンドシェークを開始したり、ネットワーク・データを消費したりしません。SSLExplorer.explore()メソッドはClientHelloメッセージを领略し、SSLCapabilitiesにセキュリティ・パラメータを赢得します。このメソッドは、TLS接続でハンドシェークが行われる前に呼び出す必要があります。
SSLSocketに基づいた仮想サーバー・ディスパッチャこのセクションでは、SSLSocketに基づいて、仮想サーバー・ディスパッチャを使用する手順を説明します。
サーバー名ハンドラを登録します。
このステップで、アプリケーションは様々なサーバー名暗意の様々なSSLContextオブジェクトを作成したり、特定のサーバー名暗意を指定した仮想マシンまたは踱步システムにリンクしたりできます。
たとえば、サーバー名がwww.example.orgの場合、登録されたサーバー名ハンドラはローカル仮想ホスティングWebサービス用などになります。ローカル仮想ホスティングWebサービスは指定したSSLContextを使用します。サーバー名がwww.example.comの場合、登録されたサーバー名ハンドラは10.0.0.36でホストしている仮想マシン用などになります。ハンドラはこの接続を仮想マシンにマッピングできます。
ServerSocketを作成し、新しい接続を受け付けます。
ServerSocket serverSocket = new ServerSocket(serverPort); Socket socket = serverSocket.accept();
ソケット入力ストリームからバイトを読み取り、バッファして、バッファ済のバイトを調査します。
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()); }
調査済の機能から要求されたサーバー名を赢得します。
List<SNIServerName> serverNames = capabilities.getServerNames();
このサーバー名暗意の登録済のサーバー名ハンドラを検索します。
ホスト名のサービスが仮想マシンまたは他の踱步システムに存在する場合、アプリケーションは接続を転送先に転送する必要があります。アプリケーションは、ソケット・ストリームからの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に基づいて、仮想サーバー・ディスパッチャを使用する手順を説明します。
サーバー名ハンドラを登録します。
このステップで、アプリケーションは様々なサーバー名暗意の様々なSSLContextオブジェクトを作成したり、特定のサーバー名暗意を指定した仮想マシンまたは踱步システムにリンクしたりできます。
たとえば、サーバー名がwww.example.orgの場合、登録されたサーバー名ハンドラはローカル仮想ホスティングWebサービス用などになります。ローカル仮想ホスティングWebサービスは指定したSSLContextを使用します。サーバー名がwww.example.comの場合、登録されたサーバー名ハンドラは10.0.0.36でホストしている仮想マシン用などになります。ハンドラはこの接続を仮想マシンにマッピングできます。
ServerSocketまたはServerSocketChannelを作成し、新しい接続を受け付けます。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(...); ... SocketChannel socketChannel = serverSocketChannel.accept();
ソケット入力ストリームからバイトを読み取り、バッファして、バッファ済のバイトを調査します。
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
調査済の機能から要求されたサーバー名を赢得します。
List<SNIServerName> serverNames = capabilities.getServerNames();
このサーバー名暗意の登録済のサーバー名ハンドラを検索します。
ホスト名のサービスが仮想マシンまたは他の踱步システムに存在する場合、アプリケーションは接続を転送先に転送する必要があります。アプリケーションは、ソケット・ストリームからの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プロバイダの使用には何の制限もありません人妖 女優。