ネットワークを通じてやり取りされるデータには、意図された受信者以外の人も、簡単にアクセスできます。データにパスワードやクレジットカード番号などの個人情報が含まれる場合、権限のない者がデータを理解できないよう、手段を講じる必要があります。また、意図的であるかどうかに関わらず、通信中にデータが変更されないようにすることも重要です。Secure Sockets Layer (SSL) および Transport Layer Security (TLS) は、ネットワークを通じたデータの送信時に、データの機密性および整合性を保護するために設計されたプロトコルです。Java Secure Socket Extension (JSSE) により、安全なインターネット通信が可能になります。JSSE では、Java バージョンの SSL および TLS プロトコルのフレームワークおよび実装が提供されます。また、データ暗号化、サーバ認証、メッセージの整合性のほか、オプションでクライアント認証の機能が含まれます。JSSE を使うと、開発者は Hypertext Transfer Protocol (HTTP)、Telnet、FTP など、TCP/IP のアプリケーションプロトコルを実行するクライアントとサーバの間で、安全なデータのやり取りを実現できます。SSL の概要については、「Secure Sockets Layer (SSL) の概要」を参照してください。
JSSE は、基盤となる複雑なセキュリティアルゴリズムや「ハンドシェーク」機構を抽象化することにより、識別するのが難しく、しかし危険なセキュリティ上の弱点が生まれるリスクを最小限に抑えます。また、JSSE を開発者がアプリケーションに直接統合できる構築ブロックとして使うと、アプリケーション開発が簡単になります。
従来の JSSE は、JavaTM 2 SDK, Standard Edition (J2SDK) バージョン 1.2 と 1.3 のオプションパッケージ (標準拡張) でした。新しいバージョンでは、JSSE は J2SDK v 1.4 に統合されました。
JSSE は、アプリケーションプログラミングインタフェース (API) フレームワークと、その API の実装を提供します。 JSSE API は、Java 2 SDK v 1.4 の
java.securityパッケージとjava.netパッケージで定義されたコア暗号化サービスを補い、拡張されたネットワークソケットクラス、トラストマネージャ、キーマネージャ、SSLContext、およびソケット作成動作をカプセル化するソケットファクトリのフレームワークを提供します。 また、Java Development Kit (JDK) 1.1 ベースのプラットフォームと互換性がある公開鍵証明書 API も制限付きで提供します。ただし、この制限付きのjavax.security.cert証明書 API は JSSE 1.0.x との下位互換のためだけに提供されるので、使用しないようにしてください。 標準のjava.security.cert証明書 API を使用してください。JSSE API では、SSL バージョン 2.0 および 3.0 のほか、Transport Layer Security (TLS) 1.0 をサポートします。これらのセキュリティプロトコルは、通常の双方向のストリームソケットをカプセル化し、JSSE API は認証、暗号化、および整合性保護の透過的なサポートを追加します。J2SDK v 1.4 の JSSE 実装は、SSL 3.0 と TLS 1.0 を実装します。SSL 2.0 は実装しません。
すでに説明したように、JSSE は Java 2 プラットフォームのセキュリティコンポーネントで、Java Cryptography Architecture (JCA) フレームワーク上の別の場所にあるものと同じ設計方針に基づいています。暗号化に関するセキュリティコンポーネントのこのフレームワークにより、実装の独立性と、可能な場合にはアルゴリズムの独立性を実現できます。JSSE は、JCA で定義されたのと同じプロバイダアーキテクチャを使用します。
Java 2 プラットフォームの他のセキュリティコンポーネントには、Java 暗号化拡張機能 (JCE)、Java 認証・承認サービス (JAAS)、および Java セキュリティツール があります。JSSE は JCE と同じ概念およびアルゴリズムを多数含んでいますが、単純なストリームソケット API の下でこれらを自動的に適用します。
JSSE API は、その他の SSL/TLS プロトコルと公開鍵インフラストラクチャ (PKI) 実装をシームレスにプラグインできる設計になっています。 開発者が、リモートホストの信頼性やリモートホストに送信する認証鍵データを決定するロジックを提供することもできます。
注: JSSE API は基盤となる実装の交換 (接続性) をサポートします。しかし、米国の輸出制限により、今回のリリースでは SSL/TLS アルゴリズムの交換はサポートされていません。 なお、TrustManagerFactoryおよびKeyManagerFactoryは完全にプラグイン可能です。
特長と利点
JSSE には次のような重要な特長があります。
- 100% Pure Java に実装される
- ほとんどの国に輸出できる
- SSL バージョン 2.0 と 3.0、および SSL バージョン 3.0 の実装に API サポートを提供する
- TLS バージョン 1.0 に API サポートと実装を提供する
- 安全なチャネルを作成するためにインスタンス化できるクラスを含む (
SSLSocketおよびSSLServerSocket)
- 安全な通信を開始し、検証するのに使用される SSL ハンドシェーク機能の一部として、暗号群ネゴシエーションをサポートする
- 通常の SSL ハンドシェーク機能の一部として、クライアントとサーバの認証をサポートする
- SSL プロトコル (HTTPS) でカプセル化された Hypertext Transfer Protocol (HTTP) をサポートする。これにより、HTTPS を使用する Web ページなどのデータにアクセスできる
- メモリ常駐型の SSL セッションを管理するためのサーバセッション管理 API を提供する
- RSA や RC4 など、RSA Data Security Inc. がライセンスを与えたコードを含む
- 暗号群で一般的に使用される複数の暗号化アルゴリズムをサポートする。次の表に示すアルゴリズムが含まれる
JSSE で利用できる暗号化機能
暗号化アルゴリズム *
暗号化処理
鍵の長さ (ビット)
RSA
認証と鍵交換
2048 (認証)
2048 (鍵の交換)
512 (鍵の交換)RC4
バルク暗号化
128
128 (40 が有効)DES
バルク暗号化
64 (56 が有効)
64 (40 が有効)Triple DES
バルク暗号化
192 (112 が有効)
Diffie-Hellman
鍵の承認
1024
512DSA
認証
1024
* 注: SunJSEE プロバイダ付属の暗号化アルゴリズムは、Java 暗号化アーキテクチャ (JCA) プロバイダフレームワークに登録されていません。このため、その他のアプリケーションでは利用できません。
JSSE 標準 API
JSSE 標準 API は、
javax.net、javax.net.ssl、およびjavax.security.certパッケージで利用できる API で、次の点をカバーします。
- 安全なソケット (SSL) およびサーバソケット
- ソケット、サーバソケット、SSL ソケット、および SSL サーバソケットを作成するファクトリ。ソケットの作成および構成をカプセル化できるソケットファクトリの使用
- 安全なソケットファクトリのファクトリとして動作する安全なソケットコンテキストを表すクラス
- 鍵およびトラストマネージャのインタフェース (X.509 固有の鍵およびトラストマネージャ)、およびこれらを作成するファクトリ
- 安全な HTTP URL 接続用のクラス
- JDK 1.1 ベースのプラットフォームと互換性がある公開鍵証明書 API
SunJSSEプロバイダJ2SDK v 1.4 には、「
SunJSSE」という名前の JSSE プロバイダが付属しています。このプロバイダはあらかじめインストールされ、JCA に登録されています。このプロバイダが提供する暗号化サービスは次のとおりです。以下の表に、
- Java 2 プラットフォームの、署名に関連した JCA 機能の RSA サポート
- SSL 3.0 および TLS 1.0 セキュリティプロトコルの実装
- もっとも一般的な SSL および TLS 暗号群の実装。一組の認証、鍵の承認、暗号化、および整合性保護を含む
- X.509 ベースのキーマネージャの実装。標準的な JCA KeyStore から適切な認証キーを選択する
- X.509 ベースのトラストマネージャの実装。証明書チェーンのパスを検証する RFC 2459 規則のサブセットを実装する
- PKCS12 の読み取り専用の実装。JCA キーストア型「pkcs12」と見なされる
SunJSSEでサポートされる暗号群とデフォルトで利用できる暗号群を一覧します。
サポート対象の暗号群 SSL_RSA_WITH_RC4_128_SHASSL_RSA_WITH_RC4_128_MD5SSL_RSA_WITH_DES_CBC_SHASSL_RSA_WITH_3DES_EDE_CBC_SHASSL_DHE_DSS_WITH_DES_CBC_SHASSL_DHE_DSS_WITH_3DES_EDE_CBC_SHASSL_RSA_EXPORT_WITH_RC4_40_MD5SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHASSL_RSA_WITH_NULL_MD5SSL_RSA_WITH_NULL_SHASSL_DH_anon_WITH_RC4_128_MD5SSL_DH_anon_WITH_DES_CBC_SHASSL_DH_anon_WITH_3DES_EDE_CBC_SHASSL_DH_anon_EXPORT_WITH_RC4_40_MD5SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA
デフォルトで利用できる暗号群 (優先順) SSL_RSA_WITH_RC4_128_SHASSL_RSA_WITH_RC4_128_MD5SSL_RSA_WITH_DES_CBC_SHASSL_RSA_WITH_3DES_EDE_CBC_SHASSL_DHE_DSS_WITH_DES_CBC_SHASSL_DHE_DSS_WITH_3DES_EDE_CBC_SHASSL_RSA_EXPORT_WITH_RC4_40_MD5SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHAJ2SDK v 1.4 での JSSE の新機能
J2SDK v 1.4 の JSSE の、JSSE 1.0.2 との相違点は次のとおりです。
- JSSE が J2SDK に含まれる
javax.security.certは使用できない
- SunJSSE プロバイダは JCE プロバイダを使って暗号化を行うことができる
- com.sun.net.ssl のクラスは javax.net.ssl に移動
- 新規メソッドとインタフェース
- クラスとメソッドの変更
- ドキュメントの変更
JSSE が J2SDK に含まれる
これまでの JSSE は、JavaTM 2 SDK Standard Edition (J2SDK) バージョン 1.2 と 1.3 のオプションパッケージ (標準拡張) でした。新しいバージョンでは、JSSE は J2SDK v 1.4 に統合されました。SunJSSE プロバイダも含まれており、J2SDK v 1.4 の
java.securityセキュリティプロパティファイルにあらかじめ登録されています。
javax.security.certは使用できないJSSE は
java.security.certパッケージが広く利用される前に開発されたものなので、JSSE の初期バージョンjavax.security.certでは補完的な証明書パッケージが導入されていました。現在、JSSE は J2SDK に付属しており、java.security.certパッケージにあるさらに完成度の高い証明書 API を利用しています。 新しいアプリケーションはすべてjava.security.certを使用することになっています。javax.security.certパッケージは以前のリリースの JSSE との後方互換性を確保するために含められているだけです。このパッケージの使用は避けてください。SunJSSE プロバイダは JCE プロバイダを使って暗号化を行うことができる
SunJSSE プロバイダは、暗号化アルゴリズムとして JCE プロバイダを利用できるようになりました。 以前は、暗号化アルゴリズムとして、もっぱら内部実装が利用されていました。 現在では、SunJSSE よりも優先順位の高いプロバイダの実装を利用できます。 詳細については、「暗号化アルゴリズムプロバイダのカスタマイズ」を参照してください。
com.sun.net.ssl のクラスは javax.net.ssl に移動
JSSE 1.0.x で
com.sun.net.sslパッケージにあったクラスとインタフェースは、すべてjavax.net.sslパッケージに移動しました。 これまでのcom.sun.net.sslとインタフェースもそのままの状態で SunJSSE プロバイダに含まれていますが、これは後方互換性を確保するために過ぎません。実際には、新しいjavax.net.sslクラスとインタフェースを参照する「ラッパー」が提供されます。実装で使用されるのは
javax.net.ssl.SSLPermissionsであり、com.sun.net.ssl.SSLPermissionは使用されません。com.sun.net.ssl.SSLPermissionを示すために使用されたポリシーファイルでは、今後はjavax.net.ssl.SSLPermissionsを使用する必要があります。新規メソッドとインタフェース
新規メソッドsetWantClientAuthおよびgetWantClientAuthがjavax.net.sslのSSLSocketおよびSSLServerSocketに追加され、任意のクライアント認証ができるようになりました。
SSLContext.getInstance(protocol)メソッドは、少なくとも指定されたプロトコルをサポートするソケットファクトリを返します。SSLSocketとSSLServerSocketに新しくsetEnabledProtocolsとgetEnabledProtocolsが追加されました。その結果、現在の接続で利用できるプロトコルが増えました。SSLSocketとSSLServerSocketには、もう 1 つの新しいメソッドgetSupportedProtocolsも追加されています。getSupportedProtocolsを使って、SSL 接続で利用できるプロトコルのバージョンを取得することができます。SSLSessionに、セッションで使用するプロトコルの標準名を取得するための新しいメソッドgetProtocolが追加されました。
SocketFactoryおよびServerSocketFactoryには新規メソッドcreateSocketおよびcreateServerSocketがそれぞれ追加され、接続されていないソケットが作成できるようになりました。
SSLContextに新しいメソッドgetServerSessionContextとgetClientSessionContextが追加されました。 開発者は、これらのメソッドを使って、ハンドシェーク中に繰り返し利用できる SSL クライアントのセットまたはサーバセッションを取得できます。
SSLSessionContextに新しいメソッドsetSessionTimeoutとgetSessionTimeoutが追加されました。 開発者は、これらのメソッドを使って、セッションがタイムアウトし、無効になるタイミングを制御できます。 次回以降の接続で再利用するためにセッションをいくつまでキャッシュできるかを制御する新しいメソッドsetSessionCacheSizeとgetSessionCacheSizeが追加されました。
javax.net.ssl内のHttpsURLConnection、SSLSession、およびHandshakeCompletedEventに新しいメソッドが追加されました。これらのメソッドを利用して、既存のメソッドから返されるjavax.security.cert.X509Certificate証明書のほかに、汎用の Java 2java.security.cert.Certificate証明書を取得できます。新しいメソッドは次の 3 つです。SSLSession.getPeerCertificates HandshakeCompletedEvent.getPeerCertificates HttpsURLConnection.getServerCertificates
getLocalCertificatesメソッドがSSLSession、HandshakeCompletedEvent、およびHttpsURLConnectionに追加されました。このメソッドは、ハンドシェーク中に相手に送信された証明書を返します。これにより、任意の SSL セッションのローカルサイドを認証するため、どの証明書チェーンを実際に使ったかを判断できます。プロバイダが拡張できる基本インタフェースとして新規インタフェース
ManagerFactoryParametersが追加されました。プロバイダが初期化パラメータKeyManagerFactoryおよびTrustManagerFactoryを必要とする場合には拡張でき、これらのクラスの KeyStore ベースのinitメソッドにパラメータを渡すことができる場合は拡張されません。KeyManagerFactoryおよびTrustManagerFactoryクラスはそれぞれ、ManagerFactoryParametersを引数に取る新規メソッドinitを持ちます。特定のプロバイダの利用者は、プロバイダによる定義に従って、適切なManagerFactoryParametersの実装を渡す必要があります。クラスとメソッドの変更
javax名前空間にcom.sunAPI を追加する準備を行なっている間に、このバージョンのjavaxで API の制限事項の一部が修正されました。 以前の JSSE オプションパッケージ内の古いcom.sun.*API はそのままの状態になっています。 以下で説明する変更は、同じ名前の新規クラスjavax.*にだけ適用されます。
HttpsURLConnectionコンストラクタが変更され、保護されるようになりました。これにより、java.netパッケージのURLConnection、JarURLConnection、HttpURLConnectionなど、類似した他のクラスとの一貫性が確保されます。 また、javax.security.cert証明書を返すメソッドは削除されました。汎用性を高めるため、ホスト名の再検証を行うようになりました。 検証先の
verifyメソッドには、受け取った証明書に含まれているホスト名の代わりに、ネゴシエーション済みのSSLSessionが渡されるようになりました。 このため、新しいSSLSessionでは、ネゴシエーション済みの暗号群、交換済みの証明書などを照会できます。
X509TrustManager isClientTrustedはcheckClientTrusted、isServerTrustedはcheckServerTrustedに名称変更されました。 証明書チェーンがこのTrustManagerによって信頼されない場合、checkClientTrustedメソッドとcheckServerTrustedメソッドは例外をスローします (以前のメソッドはbooleanを返していた)。 これを利用して、実装は、信頼が得られなかった原因を突き止めることができます。checkClientTrustedとcheckServerTrustedにより、証明書が鍵使用拡張に対応した操作で使用されているかどうかの検証を含むチェックが行われます。 このチェックを正しく実行するためには、両メソッドに認証のタイプを指定し、String authType引数を追加する必要があります。1 つのパラメータが追加され、
X509KeyManager chooseClientAliasおよびchooseServerAliasメソッドの 1 つのパラメータが変更されました。 両メソッドには、接続に使用するソケットを指定するSocket socketパラメータが追加されています。chooseClientAliasメソッドのkeytypeパラメータが、単一の文字列から鍵のアルゴリズムの型名を指定する文字列の配列に変更され、最優先の型が最初に来るようになりました。たとえば、chooseClientAliasメソッドのシグニチャーはこれまで、次のような形式でした。これは、次のような形式になります。chooseClientAlias(String keyType, Principal[] issuers)パラメータを使うと、リモートホストへの接続時にどの証明書を使用するかを決めることができます。chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)デフォルトのキーマネージャファクトリのアルゴリズム名が、
sun.ssl.keymanager.typeからssl.KeyManagerFactory.algorithmに変更されました。同様に、デフォルトのトラストマネージャファクトリのアルゴリズム名が、sun.ssl.trustmanager.typeからssl.TrustManagerFactory.algorithmに変更されました。ドキュメントの変更
このドキュメント自体も更新され、内容が増補されました。
JSSE javadoc には、主として不正な引数と明示的には記述されていない動作について、細かな改良が多数加えられました。
関連ドキュメント
Java Secure Socket Extension 関連ドキュメント
- JSSE ホームページ。JavaOneSM カンファレンスのスライド、JSSE FAQ、法律上の問題など -
http://java.sun.com/products/jsse/
- Sun の Java セキュリティチーム ( java-security@sun.com) に寄せられた API に関する質問と回答 -
http://archives.java.sun.com/archives/java-security.html注:上記のメーリングリストは、購読リストやサポート機構ではありません。これは、Java 2 Standard Edition セキュリティチームへのコメントの送付のみを目的としています。
- JSSE API 関連ドキュメント -
Java 2 プラットフォームのセキュリティ関連ドキュメント
- Java 2 セキュリティホームページ -
http://java.sun.com/security/
- その他の Java 2 プラットフォームセキュリティドキュメント -
http://java.sun.com/j2se/1.4/ja/docs/ja/guide/security/
- Java 2 プラットフォームセキュリティのチュートリアル -
http://java.sun.com/docs/books/tutorial/security1.2/
- Java 2 プラットフォームセキュリティに関する文書 -
Inside Java 2 Platform Security:Architecture, API Design, and Implementation (Li Gong 著)Addison Wesley Longman, Inc., 1999. ISBN: 0201310007.暗号化に関する輸出上の問題
米国の暗号政策については、次のサイトを参照してください。
- 米国商務省:
http://www.doc.gov/
- 輸出規制に関するページ -
http://www.crypto.com/
- Computer Systems Public Policy (CSPP) -
http://www.cspp.org/
- 連邦情報処理標準出版物 (FIPS PUBS) のホームページ。データ暗号化規格 (DES) へのリンクあり -
http://www.itl.nist.gov/fipspubs/
- 米国暗号化輸出規制 (改訂版) -
http://www.epic.org/crypto/export_controls/regs_1_00.html暗号化に関するドキュメント
オンラインリソース
- Rivest 博士の暗号化とセキュリティのページ -
http://theory.lcs.mit.edu/‾rivest/crypto-security.html書籍:
- Applied Cryptography, Second Edition (Bruce Scheneier 著)John Wiley and Sons, Inc., 1996
- Cryptography Theory and Practice (Doug Stinson 著) CRC Press, Inc., 1995.
- Cryptography & Network Security: Principles & Practice (William Stallings 著) Prentice Hall, 1998.
Secure Sockets Layer 関連ドキュメント
オンラインリソース
- Netscape による SSL に関するドキュメント:
http://developer.netscape.com/docs/manuals/security.html#SSL
- iPlanet による SSL に関する入門ドキュメント:
http://www.iplanet.com/developer/docs/articles/security/
ssl.html
- SSL プロトコルバージョン 3.0 インターネットドラフト:
http://home.netscape.com/eng/ssl3/ssl-toc.html
- TLS プロトコルバージョン 1.0 インターネットドラフト:
http://www.ietf.org/rfc/rfc2246.txt
- "HTTP Over TLS" の RFC 情報:
http://www.ietf.org/rfc/rfc2818.txt書籍:
- 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, Second Edition (Marco Pistoia, Duane F Reller, Deepak Gupta, Milind Nagnur, and Ashok K Ramani 著)Prentice Hall, 1999. Copyright 1999 International Business Machines
このドキュメントでは、暗号化に関する用語が使用されます。この節では、こうした用語を定義します。
認証
認証とは、通信相手の識別情報を確認するプロセスです。暗号群
暗号群とは、暗号化パラメータの組み合わせで、認証、鍵の承認、暗号化、および整合性保護に使用するセキュリティアルゴリズムおよび鍵のサイズを定義します。証明書
証明書とは、デジタル署名付きの文で、あるエンティティ (人や会社など) の識別情報および公開鍵の内容を保証します。証明書には、自己署名付き証明書と証明書発行局 (CA) から発行された証明書があります。証明書発行局とは、ほかのエンティティのために有効な証明書を発行する信頼のおけるエンティティです。よく知られている CA には VeriSign、Entrust、および GTE CyberTrust があります。X509 は証明書の一般的な形式で、JDK の keytool で管理することができます。暗号化ハッシュ関数
暗号化ハッシュ関数はチェックサムと似ています。データは、ハッシュと呼ばれる、比較的小さなビット文字列を生成するアルゴリズムで処理されます。暗号化ハッシュ関数には、次のような 3 つの主な特徴があります。(1) 一方向の関数であるため、ハッシュからオリジナルデータを生成することはできません。(2) オリジナルデータをわずかに変更しても、ハッシュでは大きな変更になります。(3) 暗号化鍵は必要ありません。暗号化サービスプロバイダ
JCA では、さまざまな暗号化アルゴリズムの実装が、暗号化サービスプロバイダ (略称は「プロバイダ」) によって提供されます。プロバイダは、基本的には、特定のアルゴリズムのエンジンクラスを実装するパッケージです。エンジンクラスは、具体的な実装のない抽象的な方法で暗号化サービスを定義します。デジタル署名
デジタル署名とは、手書きの署名のデジタル版です。これは、ネットワークで伝送されるデータが、それを送信したと主張する人物からのものであり、送信中にデータが変更されていないことを保証するものです。たとえば、RSA ベースのデジタル署名を計算するには、まずデータの暗号化ハッシュを計算し、次に送信者の非公開鍵でハッシュを暗号化します。暗号化および暗号解読
暗号化とは、複雑なアルゴリズムを使用して、元のメッセージ (クリアテキスト) を符号化されたメッセージ (暗号テキスト) に変換するプロセスです。暗号テキストは、復号化しない限り、その内容を理解できません。復号化とは、クリアテキストから暗号テキストを作成するのとは逆のプロセスです。通常、データの暗号化および復号化に使用するアルゴリズムには、次の 2 つのカテゴリがあります。それは、秘密鍵 (対称型) 暗号と公開鍵 (非対称型) 暗号です。ハンドシェークプロトコル
2 つのソケット同士が新しいセッションや既存のセッションの使用に同意するネゴシエーションのフェーズです。ハンドシェークプロトコルは、レコードプロトコルを介して交換される一連のメッセージです。ハンドシェークの終了時に、セッションの接続に固有の暗号化鍵や、整合性を保護するための鍵が、鍵の承認による秘密に基づいて新たに生成されます。鍵協定
鍵の承認とは、2 つ以上の当事者が同じ暗号化鍵を使用できるプロトコルで、非公開情報をクリアテキストで交換する必要がありません。たとえば、RSA や Diffie-Hellman があります。キーマネージャとトラストマネージャ
キーマネージャ (
KeyManagerFactoryを参照) およびトラストマネージャ (TrustManagerFactory) は、鍵データにキーストアを使用します。キーマネージャはキーストアを管理し、ユーザ承認時など必要に応じて公開鍵を提供します。トラストマネージャは、管理するトラストストアの情報にもとづいて、トラストの対象者を決定します。キーストアとトラストストア
キーストアは、鍵データのデータベースです。鍵データにはさまざまな用途があり、それには認証やデータ整合性も含まれます。利用できるキーストアにはさまざまな型があり、その中には「PKCS12」や Sun の「JKS」も含まれます。
一般に、キーストア情報は次の 2 つのカテゴリに分類できます。それは、鍵のエントリと、信頼される証明書のエントリです。鍵のエントリはエンティティの識別情報とその非公開鍵から構成されており、さまざまな暗号化の用途に使用できます。これとは対照的に、信頼される証明書のエントリには、公開鍵とそのエンティティの識別情報しか含まれていません。したがって、
javax.net.ssl.KeyManagerの場合など、非公開鍵が必要な場合は、信頼される証明書のエントリを使用することはできません。JKS の J2SDK 実装では、キーストアに鍵のエントリと、信頼される証明書のエントリの両方を含めることができます。トラストストアとは、トラストの対象を決めるときに使用するキーストアです。すでに信頼しているエンティティからデータを受け取る場合、およびそのエンティティが発信元を名乗るエンティティであることを検証できる場合は、データは実際にそのエンティティから届いたものであると仮定できます。
ユーザがそのエンティティを信頼すると決定した場合に限り、トラストストアにエントリが追加されます。ユーザは、鍵のペアを生成するか、証明書をインポートすることにより、そのエントリにトラストを与えます。これにより、キーストアのエントリは信頼されたエントリとみなされます。
次のような 2 つのキーストアファイルがあると便利です。1 つは鍵のエントリだけのファイル、もう 1 つは信頼された証明書のエントリを含むファイルです。これには、証明書発行局 (CA) が発行する証明書が含まれます。前者には機密性のある情報が含まれますが、後者には機密性のある情報は含まれません。単独のキーストアファイルではなく、異なる 2 つのキーストアファイルを使用すると、独自の証明書 (および対応する非公開鍵) と他の証明書を論理的に区別した明確な区分が提供されます。アクセス制限があるキーストアに非公開鍵を保存すると、非公開鍵をさらに保護することができます。一方、必要であれば、より自由にアクセスできるキーストアで信頼される証明書を提供することもできます。
メッセージ認証コード
メッセージ認証コード (MAC) は、送信された情報や、信頼できないメディアに保存されている情報の整合性を、秘密鍵にもとづいてチェックする方法を提供します。通常、MAC は秘密鍵を共有する 2 つの当事者間で、お互いが送信する情報を検証するために使用されます。暗号化ハッシュ機能に基づくMAC 機構は、HMAC と呼ばれます。HMAC は、共有する秘密鍵と組み合わせて、Message Digest 5 (MD5) や Secure Hash Algorithm (SHA) などの暗号化ハッシュ関数とともに使用できます。HMAC については、RFC 2104 で規定されています。
公開鍵暗号方式
公開鍵暗号化では、2 つの鍵を生成する暗号化アルゴリズムを使用します。一方の鍵は公開されますが、他方は非公開のままです。公開鍵と非公開鍵では、逆の暗号化処理がなされ、一方の鍵で暗号化したものを他方の鍵で復号化します。公開鍵暗号化は、非対称暗号化とも呼ばれます。レコードプロトコル
レコードプロトコルは、アプリケーションレベルのデータやハンドシェークプロセスの一部であるデータをすべて、独立したデータレコードにパッケージ化します。これは、TCP ストリームソケットでアプリケーションバイトストリームをネットワークパケットに変換する場合によく似ています。個々のレコードは、使用している暗号化鍵および整合性保護鍵によって保護されます。秘密鍵暗号方式
秘密鍵暗号方式では、データの暗号化と復号化に同じ鍵を使用する暗号化アルゴリズムを使用します。秘密鍵暗号方式は対称暗号方式とも呼ばれます。セッション
セッションとは、名前付きの状態の情報のコレクションで、認証されたピア識別情報、暗号群、鍵の承認の秘密を含みます。セッションでは、安全なソケットハンドシェークを通じてネゴシエーションが行われます。セッションは、複数の安全なソケットインスタンスで共有することができます。トラストマネージャ
「キーマネージャとトラストマネージャ」を参照してください。トラストストア
「キーストアとトラストストア」を参照してください。
Secure Sockets Layer (SSL) は、Web で暗号化を実装する場合にもっともよく使用されるプロトコルです。SSL は、ネットワークで安全な通信を行うために暗号化プロセスを組み合わせて使用します。この節では、SSL および SSL が使用する暗号化プロセスについて簡単に説明します。
SSL は、インターネットで使用される標準的な TCP/IP ソケットプロトコルの機能を安全に拡張します。次の図「SSL を使用する TCP/IP プロトコル」で示すように、Secure Sockets Layer は標準的な TCP/IP プロトコルのトランスポート層とアプリケーション層の間に追加されます。SSL とともにもっともよく使用されるアプリケーションは Hypertext Transfer Protocol (HTTP) です。これはインターネットの Web ページ用のプロトコルです。このほかにも、Net News Transfer Protocol (NNTP)、Telnet、Lightweight Directory Access Protocol (LDAP)、Interactive Message Access Protocol (IMAP)、File Transfer Protocol (FTP) などのアプリケーションがあり、やはり SSL とともに使用します。
注:現在のところ、安全な FTP の標準規格は存在しません。
SSL を使用する TCP/IP プロトコル
TCP/IP の層
プロトコル
アプリケーション層
HTTP、NNTP、Telnet、FTP など
Secure Sockets Layer
SSL
トランスポート層
TCP
インターネット層
IP
SSL は 1994 年に Netscape 社によって開発され、インターネットの世界で使用されるようになると、標準的な存在になりました。現在では、国際的な標準化機構である Internet Engineering Task Force (IETF) が管理しています。IETF は SSL の名称を Transport Layer Security (TLS) に変更し、1999 年 1 月にバージョン 1.0 を初めて発表しました。TLS 1.0 は、SSL の最新バージョン 3.0 を少しだけ変更したものです。SSL 3.0 と TLS 1.0 にはほとんど違いがありません。
SSL を使用することの利点
次の 3 つの理由から、機密情報をネットワークで送信する際に危険が伴う場合があります。
- 通信相手のエンティティが、実際には必ずしも想定する相手とは限らない
- ネットワーク上のデータは傍受されることがあり、権限のない第三者 (場合によっては攻撃者) にデータを読み取られてしまうことがある
- 攻撃者がデータを傍受できる場合、攻撃者はデータが受信者に届く前に内容を変更できる
SSL はこれらの問題に対応しています。最初の問題には、認証と呼ばれるプロセスを通じ、通信の当事者双方に互いの識別情報を任意に確認させることで対応しています。両者が認証されると、SSL は両者を暗号化接続して安全な通信を行います。両者の通信を暗号化することで 2 番目の問題に対応し、機密性が保持されます。SSL で使用する暗号化アルゴリズムには、安全なハッシュ関数が含まれています。これはチェックサムに似ています。これにより、送信中にデータが変更されていないことが保証されます。安全なハッシュ関数により、3 番目の問題に対応し、データの整合性を確保します。
認証も暗号化もオプションであり、当事者間でネゴシエーションが行われた暗号群に基づいていることに注意してください。
もっとも端的な SSL の使用例は電子商取引です。電子商取引では、通信するサーバの識別情報は保証されていると考えるべきではありません。クレジットカードの番号を入力するだけですばらしいサービスが受けられるという偽の Web サイトを作成するのは簡単なことです。SSL を使うと、クライアントがサーバの識別情報を認証することができます。また、サーバもクライアントの情報を認証できますが、インターネット上の取引では、この方法はあまり使われていません。
クライアントとサーバが互いの情報を認証すると、SSL は暗号化アルゴリズムを使って機密性とデータの整合性を提供します。これにより、クレジットカード番号のような機密情報をインターネット上で安全に送信することができます。
SSL は認証、機密性、およびデータの整合性を提供しますが、非拒否サービスは提供しません。非拒否性とは、メッセージを送信したエンティティは、後になって送信を拒否することができないということを意味します。メッセージとデジタル署名が関連付けられていると、後になって通信内容を証明することができます。SSL 単独では、非拒否性を提供しません。
SSL のしくみ
SSL が有効な理由の 1 つに、複数の暗号化プロセスを使用していることがあります。SSL は、公開鍵暗号で認証を行い、秘密鍵暗号とデジタル署名で機密性とデータの整合性を提供します。SSL について理解する前に、暗号化の処理方法を理解しておくと役立ちます。暗号化処理
暗号化の主な目的は、権限のない第三者が非公開の通信にアクセスしたり、その内容を理解するのを困難にすることです。暗号化では、データに対する権限のないすべてのアクセスを必ずしも制限できるわけではありませんが、権限のない第三者が非公開のデータを読み取れないようにすることができます。暗号化では、複雑なアルゴリズムを使用して、元のメッセージ (クリアテキスト) を符号化されたメッセージ (暗号テキスト) に変更します。通常、ネットワークで送信されるデータの暗号化および復号化に使用するアルゴリズムには 2 つのカテゴリがあります。秘密鍵暗号方式と公開鍵暗号方式です。これらの暗号方式については、以下の節で説明します。秘密鍵暗号方式も公開鍵暗号方式も、合意に基づく暗号鍵または暗号鍵のペアを使用します。鍵は、データの暗号化プロセスおよび復号化プロセスで暗号化アルゴリズムが使用するビット文字列です。暗号化鍵は錠の鍵に似ています。錠を空けることができるのは、正しい鍵だけです。
通信の当事者が互いに鍵を安全に送信するのは、些細な問題ではありませN。公開鍵証明書を使うと、公開鍵を安全に送信し、受信者に公開鍵の信頼性を保証することができます。公開鍵証明書については、後の節で説明します。
以下で説明する暗号化プロセスでは、セキュリティコミュニティで使用する名称を使います。通信の当事者をそれぞれ Alice と Bob とし、権限のない第三者を Charlie とします。Charlie は攻撃者にもなります。
秘密鍵暗号方式
秘密鍵暗号方式では、通信する Alice と Bob はメッセージの暗号化と復号化に同じ鍵を使います。暗号化されたデータをネットワークで送信する前に、Alice と Bob は鍵を持っていることが必要で、暗号化と復号化に使用する暗号化アルゴリズムに同意している必要があります。
秘密鍵暗号方式で大きな問題になるのは、攻撃者にアクセスされずに一方から他方に鍵を渡す方法です。Alice と Bob が秘密鍵暗号方式でデータを暗号化しても、Charlie がその鍵にアクセスできれば Alice と Bob の非公開メッセージを傍受することができます。Charlie は Alice と Bob のメッセージを復号化できるだけではなく、Alice になりすまして暗号化データを Bob に送信することもできるのです。Bob には、メッセージが Charlie から届いたものか Alice から届いたものかはわかりません。
秘密鍵の配布方法の問題が解決すれば、秘密鍵暗号はたいへん貴重なツールになります。そのアルゴリズムにより、優れたセキュリティと暗号化データが比較的迅速に提供できるからです。SSL セッションで送信される機密性の高いデータの多くは、秘密鍵暗号方式で送信されます。
秘密鍵暗号方式は、データの暗号化と復号化に同じ鍵を使用するので、対称暗号化方式とも呼ばれます。よく知られている秘密鍵暗号化アルゴリズムには、Data Encryption Standard (DES)、トリプル DES (3DES)、Rivest Cipher 2 (RC2)、および 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 があります。このほかにも、秘密鍵を交換するために設計された SSL を使う公開鍵暗号化アルゴリズムには、Diffie-Hellman (DH) があります。公開鍵暗号方式には膨大な計算が必要なため、速度が遅くなります。そこで、この方式は暗号化データ通信全体に使用するよりもむしろ、秘密鍵など少量のデータを暗号化する場合にだけ使用します。
秘密鍵暗号方式と公開鍵暗号方式の比較
秘密鍵暗号方式と公開鍵暗号方式のどちらにも、長所と弱点があります。 秘密鍵暗号方式では、データの暗号化や復号化に時間はかかりませんが、通信者同士が同じ秘密鍵情報を持つ必要があり、鍵の交換方法が問題になります。公開鍵暗号方式では、鍵を秘密にする必要がないので交換方法は問題になりません。しかしデータの暗号化と復号化に使用するアルゴリズムには膨大な計算が必要で、速度が遅くなります。
公開鍵証明書
公開鍵証明書を使うと、エンティティは非対称暗号方式で使用する公開鍵を安全に配布できます。公開鍵証明書は次のような状況を回避します。Charlie が自分の公開鍵と非公開鍵を作成すれば、自分は Alice だと名乗って Bob に公開鍵を送信できます。Bob は Charlie と通信できますが、データを Alice に送信していると思い込んでしまいます。
公開鍵証明書は電子的なパスポートだと考えることができます。これは、信頼できる組織によって発行され、所有者に識別情報を提供します。公開鍵証明書を発行する信頼できる組織を、証明書発行局 (CA) と呼びます。CA は公証人にたとえることができます。CA から証明書を取得するには、識別情報の証拠となるものを提供する必要があります。 CA は、申請者が申し立てる組織の代表であるとの確証が得られたら、証明書に含まれる情報の妥当性を証明する証明書に署名します。
公開鍵証明書には、次のようなフィールドがあります。
- 発行者 - 証明書を発行した CA です。証明書を発行する CA が信頼でき、証明書が有効であれば、証明書は信頼できます。
- 有効期間 - 証明書には期日があります。証明書の妥当性を検証する場合は、この日付は確認すべき情報の 1 つになります。
- サブジェクト - サブジェクトフィールドには、証明書が表すエンティティの情報が含まれます。
- サブジェクトの公開鍵 - 証明書が提供する主な情報に、サブジェクトの公開鍵があります。その他のフィールドは、この鍵の妥当性を確認するためのものです。
- 署名 - 証明書は、証明書を発行した 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 とともに使用されることが多いハッシュ関数には、Message Digest 5 (MD5) と Secure Hash Algorithm (SHA) の 2 つがあります。SHA は、US National Institute of Science and Technology (NIST) によって提案されました。
メッセージ認証コード
メッセージ認証コード (MAC) は暗号化ハッシュに似ていますが、秘密鍵をベースにしている点が異なります。秘密鍵情報が暗号化ハッシュ関数で処理したデータに含まれている場合、その結果生成されるハッシュは HMAC と呼ばれます。Alice は、Bob へのメッセージを Charlie が傍受していないことを確認したい場合、メッセージの HMAC を計算して元のメッセージに HMAC を追加できます。次に、Bob と共有している秘密鍵を使ってメッセージと HMAC を暗号化します。Bob は、メッセージを復号化して HMAC を計算すれば、送信中にメッセージが変更されたかどうかを知ることができます。SSL では、HMAC を使って安全なデータを送信します。
デジタル署名
メッセージに暗号化ハッシュが作成されると、ハッシュは送信者の非公開鍵で暗号化されます。このような暗号化ハッシュをデジタル署名と呼びます。
SSL 処理
SSL を使った通信は、クライアントとサーバ間の情報交換から始まります。この情報交換を SSL ハンドシェークと呼びます。
SSL には、主に次のような 3 つの目的があります。
- 暗号群のネゴシエーション
- 情報の認証 (オプション)
- 暗号化機構の同意による情報セキュリティの確立
暗号群のネゴシエーション
SSL セッションは、どの暗号群を使用するかについて、クライアントとサーバがネゴシエーションを行うことから始まります。暗号群とは、コンピュータがデータを暗号化するために使用する暗号化アルゴリズムと鍵のサイズです。暗号群には、利用できる公開鍵交換アルゴリズムの情報、秘密鍵暗号化アルゴリズム、および暗号化ハッシュ関数が含まれます。クライアントは利用できる暗号群をサーバに伝え、サーバは、どちらにも適用できる暗号群を選択します。
サーバの認証
SSL の認証ステップは省略できます。しかし、Web 上の電子商取引では、一般的にクライアントがサーバを認証します。サーバの認証により、サーバが表すとクライアントが信じているエンティティを、そのサーバが実際に表していることをクライアントが確認できます。
サーバは、自らが表すと唱える組織に属していることを証明するため、クライアントに公開鍵証明書を提示します。この証明書が有効であれば、クライアントはサーバの識別情報について確信できます。
クライアントとサーバは、同じ秘密鍵について同意できる情報を交換します。たとえば、RSA を使う場合、クライアントは公開鍵証明書で取得したサーバの公開鍵を使用して、秘密鍵情報を暗号化します。クライアントは暗号化された秘密鍵情報をサーバに送信します。復号化にはサーバの非公開鍵が必要なので、サーバでだけ、このメッセージを復号化できます。
暗号化されたデータの送信
クライアントとサーバは、同じ秘密鍵にアクセスします。それぞれのメッセージでは、この処理の最初の段階で選択した、秘密情報を共有する暗号化ハッシュ関数を使って、メッセージに添付される HMAC を計算します。次に、秘密鍵と、この処理の最初の段階で設定した秘密鍵アルゴリズムを使い、安全なデータと HMAC を暗号化します。その後、クライアントとサーバは、暗号化されハッシュ化されたデータを使って安全に通信することができます。
SSL プロトコル
前の節では、SSL ハンドシェークを上位レベルで説明しました。つまり、暗号化されたメッセージを送信する前にクライアントとサーバで行われる情報交換について説明しました。この節では、さらに詳しく説明します。
次の「SSL メッセージ」には、SSL ハンドシェークで交換される一連のメッセージが示されています。特定の状況下でだけ送信されるメッセージには (Optional) と記されています。SSL メッセージの説明は次のとおりです。
![]()
SSL メッセージは、次の順序で送信されます。
- Client hello - クライアントはサーバ情報を送信します。この情報には、自分がサポートする最上位バージョンの SSL と暗号群のリストが含まれます。TLS 1.0 は SSL 3.1 と表示されます。暗号群の情報には、暗号化アルゴリズムと鍵のサイズが含まれます。
- Server hello - サーバは、クライアントとサーバの両方がサポートする最上位バージョンの SSL と最適な暗号群を選択し、この情報をクライアントに送信します。
- Certificate - サーバはクライアントに証明書または証明書チェーンを送信します。証明書チェーンは通常、サーバの公開鍵証明書で始まり、認証局のルート証明書で終わります。このメッセージはオプションで、サーバ認証を求められた場合に使用します。
- Certificate request - サーバがクライアントを認証する必要がある場合、クライアントに証明書要求を送信します。インターネットアプリケーションでは、このメッセージが使われることはほとんどありません。
- Server key exchange - 上記の 3 で送信した公開鍵情報が鍵交換を行うのに不十分な場合、サーバはクライアントにサーバ鍵交換メッセージを送信します。
- Server hello done - サーバは、最初のネゴシエーションメッセージを終了したことをクライアントに伝えます。
- Certificate - メッセージ 4 でサーバがクライアントに証明書を要求すると、クライアントはメッセージ 3 でサーバが行なったようにして、証明書チェーンを送信します。
注: クライアントに証明書を要求するのは、ごく一部のインターネットサーバアプリケーションだけです。
- Client key exchange - クライアントは、対称暗号方式で使用する鍵を作成する情報を生成します。RSA では、クライアントはサーバの公開鍵でこの鍵情報を暗号化してサーバに送信します。
- Certificate verify - インターネットアプリケーションでは、このメッセージが使われることはほとんどありません。このメッセージは、サーバにクライアントの認証処理を完了させるためのものです。このメッセージが使用されると、クライアントは暗号化ハッシュ関数で電子的に署名した情報を送信します。サーバがクライアントの公開鍵でこの情報を復号化すれば、サーバはクライアントを認証できます。
- Change cipher spec - クライアントはメッセージを送信し、暗号化モードを変更するようサーバに伝えます。
- Finished - クライアントはサーバに、安全なデータ通信を開始する準備ができたことを伝えます。
- Change cipher spec - サーバはメッセージを送信し、暗号化モードを変更するようクライアントに伝えます。
- Finished - サーバはクライアントに、安全なデータ通信を開始する準備ができたことを伝えます。SSL ハンドシェークが終了します。
- Encrypted data - クライアントとサーバは、メッセージ 1 と 2 で取り決めた対称暗号化アルゴリズムと暗号化ハッシュ関数、およびメッセージ 8 でクライアントがサーバに送信した秘密鍵を使って通信します。
SSL セッションで生成したパラメータを保存しておけば、それ以降も SSL セッションで利用することができます。SSL セッションのパラメータを保存しておけば、暗号化通信をすばやく開始できます。
SSL と TLS に関する参照資料
SSL についての参考資料は、「Secure Sockets Layer の関連ドキュメント」を参照してください。
クラスの関係
安全な通信を行うには、接続の両方の側で SSL が使用できることが必要です。JSSE API では、接続のエンドポイントクラスは
SSLSocketです。次の図では、SSLSocketの作成に使用する主なクラスが論理的な順序で表示されています。
![]()
SSLSocketはSSLSocketFactoryまたはインバウンド接続を受け取るSSLServerSocketによって作成されます。SSLServerSocketはSSLServerSocketFactoryで作成されます。SSLSocketFactoryおよびSSLServerSocketFactoryオブジェクトはどちらもSSLContextで作成されます。
SSLContextを取得して初期化するには、次の 2 通りの方法があります。
- もっとも簡単な方法は、
SSLSocketFactoryまたはSSLServerSocketFactoryクラスでgetDefaultstatic メソッドを呼び出すことです。これらのメソッドは、デフォルトのKeyManager、TrustManager、および安全な乱数発生関数を使ってデフォルトのSSLContextを作成します。デフォルトのKeyManagerFactoryおよびTrustManagerFactoryを使うと、KeyManagerおよびTrustManagerがそれぞれ作成されます。使用する鍵データはデフォルトのキーストアおよびトラストストアにあり、「デフォルトの鍵とトラストストア、ストア型、およびストアパスワードのカスタマイズ」で説明するシステムプロパティで設定します。
- 作成したコンテキストの動作を呼び出し側でもっともよく管理できる方法は、
SSLContextクラスでgetInstancestatic メソッドを呼び出し、さらにそのインスタンスの適切なinitメソッドを呼び出してコンテキストを初期化することです。initメソッドの派生関数は、次の 3 つの引数を取ります。KeyManagerオブジェクトの配列、TrustManagerオブジェクトの配列、およびSecureRandom乱数発生関数です。 現時点では、SunJSSE は、initの派生関数のみを使用しています。 適切なインタフェースを実装するか、KeyManagerFactoryクラスとTrustManagerFactoryクラスを使って実装を生成することにより、KeyManagerオブジェクトとTrustManagerオブジェクトが作成されます。次に、KeyManagerFactoryおよびTrustManagerFactoryクラスを、TrustManagerFactory/KeyManagerFactoryのinitメソッドで引数として渡されたKeyStoreに含まれる鍵データで初期化します。最後に、TrustManagerFactoryのgetTrustManagersメソッドとKeyManagerFactoryのgetKeyManagersメソッドを呼び出して、トラストマネージャまたはキーマネージャの配列を取得します。どちらもトラストデータや鍵データの型の 1 つです。SSL 接続が確立されると、
SSLSessionが作成されます。これには設定した識別情報、使用する暗号群などの情報が含まれます。次に、SSLSessionを使って両方のエンティティの現在の関係と状態を表します。各 SSL 接続には、一度に 1 つのセッションが含まれますが、そのセッションがエンティティ間の接続に、同時に、または連続して何度も使用されることがあります。
コアクラスとインタフェース
コア JSSE クラスは、
java.netおよびjavax.net.sslパッケージの一部です。
SocketFactoryおよびServerSocketFactoryクラス抽象クラス
javax.net.SocketFactoryは、ソケットの作成に使われます。このクラスは、他のファクトリでサブクラス化する必要があります。ファクトリは、ソケットの特定のサブクラスを作成し、一般的なソケットレベルの機能を追加するフレームワークを提供します。たとえば、「SSLSocketFactory」を参照してください。
javax.net.ServerSocketFactoryクラスは、SocketFactoryクラスに似ていますが、サーバソケットの作成に特に使われます。ソケットファクトリを使うと、構築するソケットに関する一連のポリシーを簡単に取得し、ソケットを要求する特別なコード設定を必要としない方法でソケットを作成できます。
- ファクトリとソケットに多相性があるため、種類が異なるファクトリを渡すだけで、種類が異なるソケットに同じアプリケーションコードを使用できます。
- ソケット構築時に使用するパラメータを使って、ファクトリ自身をカスタマイズできます。たとえば、ファクトリをカスタマイズして、異なるネットワークタイムアウトのソケットや、設定済みのセキュリティパラメータを返すことができます。
- アプリケーションに返されるソケットは
java.net.Socket(またはjavax.net.ssl.SSLSocket) のサブクラスにすることができます。そうすれば、圧縮、セキュリティ、レコード宣言、統計情報収集、ファイアウォールトンネリングなどの機能の新しい API を直接公開できます。
SSLSocketおよびSSLServerSocketクラス
javax.net.ssl.SSLSocketは、標準的な Java の java.net.Socket クラスのサブクラスです。標準的なソケットメソッドをすべてサポートし、安全なソケットに固有のメソッドを追加します。このクラスのインスタンスは、その作成に使用されたSSLContextをカプセル化します。ソケットインスタンスの安全なソケットセッションの作成を管理する API もありますが、トラストマネージャおよびキーマネージャは直接公開されません。
javax.net.ssl.SSLServerSocketクラスはSSLSocketクラスに似ていますが、サーバソケットの作成に特化して使われます。実装にあたっての注意: SSL と TLS プロトコルは複雑なので、接続時の入力バイトがハンドシェークのデータとアプリケーションデータのどちらなのかを予測し、現在の接続状態にどのような影響を与えるか (処理を中断させることもある) を予測するのは困難です。Sun JSSE の実装では、
SSLSocket.getInputStream()によって取得されたオブジェクトのavailable()メソッドは、SSL 接続で正常に復号化されても、アプリケーションではまだ読み込まれていないデータのバイト数を返します。
SSLSocketの取得SSLSocketのインスタンスは、次の 2 つの方法で取得できます。1 つ目は、そのクラスの複数のcreateSocketメソッドのうちの 1 つを介して、SSLSocketFactoryのインスタンスでSSLSocketを作成する方法です。2 つ目は、SSLServerSocketクラスのacceptメソッドを介してSSLSocketを取得する方法です。
SSLSocketFactoryおよびSSLServerSocketFactoryクラス
javax.net.ssl.SSLSocketFactoryは、安全なソケットを作成するファクトリとして動作します。 このクラスは、javax.net.SocketFactoryの抽象サブクラスです。安全なソケットファクトリは、安全なソケットの作成と初期設定の詳細情報をカプセル化します。これには、認証鍵、ピア証明書の検証、使用できる暗号群などが含まれます。
javax.net.ssl.SSLServerSocketFactoryクラスはSSLSocketFactoryクラスに似ていますが、サーバソケットの作成に特化して使われます。
SSLSocketFactoryの取得
SSLSocketFactoryを取得するには、次の 3 つの方法があります。
SSLSocketFactory.getDefaultstatic メソッドを呼び出してデフォルトのファクトリを取得する。
- API パラメータとしてファクトリを受信する。つまり、ソケットを作成する必要があるものの、そのソケットの設定内容の詳細に関与しないコードには、
SSLSocketFactoryパラメータでメソッドを含めることができます。これは、クライアントによって呼び出され、ソケットの作成時に使用するSSLSocketFactoryを指定するパラメータです。(例: javax.net.ssl.HttpsURLConnection)
- 動作を指定した新規ファクトリを構築する
通常、デフォルトのファクトリはサーバ認証だけをサポートするように設定されています。このため、デフォルトのファクトリで作成されたソケットは、一般的な TCP ソケット以上にクライアントの情報を漏らすことはありません。
ソケットを作成して使用するクラスの多くは、ソケットの作成方法を詳しく知る必要はありません。パラメータとして渡されたソケットファクトリを介してソケットを作成するのは、ソケット設定の詳細を分離し、ソケットを作成して使用するクラスの再利用性を高めるよい方法です。
新しいソケットファクトリインスタンスを作成するには、独自のソケットファクトリサブクラスを実装するか、ソケットファクトリのファクトリとして動作するクラスを別に使用します。そのようなクラスの 1 つに、
SSLContextがあります。このクラスは、プロバイダベースの構成クラスとして JSSE 実装に提供されています。
SSLSessionインタフェース
javax.net.ssl.SSLSessionは、SSLSocket接続の 2 つのピアの間で取り決めたセキュリティコンテキストを表します。セッションは、いったん用意された後には、同じ 2 つのピアで接続された将来のSSLSocketによって共有できます。セッションには暗号群が含まれます。これは、リモートピアのネットワークアドレスに関する権限のないヒントと同様、安全なソケットの通信でも使用され、作成や最後の使用の時点などで、管理情報としても使用されます。セッションには、SSLSocketを通じた通信で暗号化を行い、通信の整合性を保証する暗号鍵の作成に使用される、ピア間で取り決めた共通のマスターとなる秘密も含まれます。このマスターとなる秘密の値は、基盤となるセキュリティソケット実装にだけ伝えられ、SSLSessionAPI では公開されません。
HttpsURLConnectionクラスhttps プロトコルは http プロトコルとよく似ていますが、データの要求または受信の前に SSL/TLS ソケットを利用して安全なチャネルを確立します。javax.net.ssl.HttpsURLConnectionはjava.net.HttpsURLConnectionクラスを拡張し、https 固有の機能がサポートされるようにします。 http URL の構築および使用方法の詳細については、java.net.URL,java.net.URLConnectionとjava.net.HttpURLConnectionを参照してください。
HttpsURLConnectionを取得する際、URLConnection.connectメソッドを使って実際にネットワーク接続を開始する前に、複数の http/https パラメータを構成できます。 これらについては、以下を参照してください。割り当て済みの
SSLSocketFactoryの設定状況によっては、
HttpsURLConnectionのインスタンスによって使用されるSSLSocketFactoryを指定したほうがよい場合があります。 たとえば、デフォルト実装ではサポートされないプロキシを使ってトンネリングを行う場合がこれに該当します。 新しいSSLSocketFactoryは、すでに必要なトンネリングの完了したソケットを返すことができます。このため、HttpsURLConnectionは追加のプロキシを使用することができます。
HttpsURLConnectionクラスには、ロード時に割り当てられたデフォルトのSSLSocketFactoryがあります (特にSSLSocketFactory.getDefaultによって返されたファクトリの場合)。 以降、HttpsURLConnectionのインスタンスは、static メソッドHttpsURLConnection.setDefaultSSLSocketFactoryによってクラスに新しいデフォルトのSSLSocketFactoryが割り当てられるまで、現在のデフォルトのSSLSocketFactoryを継承します。HttpsURLConnectionのインスタンスが作成されたあと、setSSLSocketFactoryメソッドへの呼び出しにより、このインスタンス上の継承されたSSLSocketFactoryを上書きできます。デフォルトの static メソッド
SSLSocketFactoryを変更しても、既存のHttpsURLConnectionsのインスタンスには何の影響もありません。既存のインスタンスを変更するには、setSSLSocketFactoryメソッドを呼び出す必要があります。
getSSLSocketFactoryメソッドまたはgetDefaultSSLSocketFactoryメソッドを呼び出すことにより、インスタンスごと、またはクラスごとにSSLSocketFactoryを取得できます。割り当て済みの
HostnameVerifierの設定URL のホスト名が SSL/TLS ハンドシェーク時に受け取ったクレデンシャルのホスト名と一致しない場合、URL Spoofing が発生している可能性があります。 ホスト名の確実性に疑いが持たれる場合、SSL 実装は、インスタンスの割り当て済みHostnameVerifierのコールバックを実行します。こうすることで、より詳しいチェックを行うことができます。 ホスト名識別子は、判定を下すために必要な処理を行います。その一環として、たとえばその他のホスト名パターンマッチングを実行したり、対話式のダイアログボックスを表示したりします。 検証に失敗した場合は、接続が切断されます。 ホスト名の検証については、RFC 2818 を参照してください。
setHostnameVerifierメソッドおよびsetDefaultHostnameVerifierメソッドは、setSSLSocketFactoryメソッドおよびsetDefaultSSLSocketFactoryメソッドとよく似ています。これらの共通点は、インスタンスごと、またはクラスごとにHostnameVerifiersが割り当てられ、現在の値がgetHostnameVerifierメソッドまたはgetDefaultHostnameVerifierメソッドによって取得されるという点です。サポートクラスとインタフェース
この節で説明するクラスとインタフェースは、
SSLContextオブジェクトの作成と初期化をサポートし、SSLSocketFactoryオブジェクトとSSLServerSocketFactoryオブジェクトを作成するために提供されます。サポートクラスとインタフェースはjavax.net.sslパッケージに含まれています。この節で説明するクラスは
SSLContext、KeyManagerFactory、およびTrustManagerFactoryの 3 つで、いずれもエンジンクラスです。エンジンクラスとは、特定のアルゴリズムの API クラス (SSLContextの場合はプロトコル) です。1 つまたは複数の暗号化サービスプロバイダ (プロバイダ) パッケージで実装が提供されることがあります。プロバイダとエンジンクラスの詳細については、「JavaTM 暗号化アーキテクチャ API 仕様&リファレンス」の「設計方針」の節と「概念」の節を参照してください。JSSE に標準で付属する
SunJSSEプロバイダは、SSLContext、KeyManagerFactory、およびTrustManagerFactory実装を提供し、標準の Java セキュリティ (java.security) API ではエンジンクラスの実装も提供します。SunJSSEが提供する実装は次のとおりです。エンジンクラス アルゴリズムまたは 実装 プロトコル KeyFactory "RSA" KeyPairGenerator "RSA" KeyStore "PKCS12" Signature "MD2withRSA" Signature "MD5withRSA" Signature "SHA1withRSA" KeyManagerFactory "SunX509" TrustManagerFactory "SunX509" SSLContext "SSL" SSLContext "SSLv3" SSLContext "TLS" SSLContext "TLSv1"
SSLContextクラス
javax.net.ssl.SSLContextは、安全なソケットプロトコルの実装のエンジンクラスです。このクラスのインスタンスは、SSL ソケットファクトリのファクトリとして動作します。SSLContextは、そのコンテキストの下で作成されたすべてのソケットで共有される状態の情報をすべて保持します。たとえば、セッションの状態は、ソケットファクトリにより作成され、コンテキストにより提供されたソケットによってハンドシェークプロトコルが取り決められると、SSLContextと関連付けられます。キャッシュに書き込まれたこれらのセッションは、同じコンテキストで作成された別のソケットで再利用したり共有することができます。各インスタンスは、認証の実行に必要な鍵、証明書チェーン、および信頼されたルート CA 証明書を使って
initメソッドで設定されます。この設定は、鍵とトラストマネージャの形で提供されます。これらのマネージャは認証をサポートし、コンテキストによってサポートされる暗号群の鍵の承認を提供します。現在は、X.509 ベースのマネージャだけがサポートされています。
SSLContextオブジェクトの作成他の JCA プロバイダベースの「エンジン」クラスと同様に、SSLContextオブジェクトは、SSLContextクラスのgetInstanceファクトリメソッドを使って作成されます。 このような static メソッドは、最低限要求された安全なソケットプロトコルを実装するインスタンスを返します。 返されるインスタンスも、その他のプロトコルを実装できます。 たとえば、getInstance("SSLv3")から返されるインスタンスは、SSLv3とTLSv1を実装します。getSupportedProtocolsメソッドは、このコンテキストから取得されたソケットファクトリによってSSLSocketまたはSSLServerSocketが作成されたとき、サポート対象のプロトコルのリストを返します。 実際の SSL 接続でどのプロトコルを有効にするかは、setEnabledProtocols(String[] protocols)メソッドを使って制御できます。 このメソッドについては、API ドキュメントのSSLSocketクラスとSSLServerSocketクラスの解説を参照してください。注:
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);プロトコル名だけを指定すると、システムは、要求されたプロトコルの実装がその環境で利用できるかどうかを判断します。複数の実装がある場合、より望ましいものがあるかどうかを判断します。
プロトコル名とプロバイダを指定すると、システムは、要求されたプロトコルの実装が要求されたプロバイダで利用できるかどうかを判断し、利用できない場合は例外をスローします。
プロトコルは、希望する安全なソケットプロトコルを記述する文字列 (「SSL」など) です。
SSLContextオブジェクトの一般的なプロトコル名は、付録 A で定義されています。次に
SSLContextの取得例を示します。SSLContext sc = SSLContext.getInstance("SSL");新しく作成された
SSLContextは、initメソッドを呼び出すことによって初期化する必要があります。public void init(KeyManager[] km, TrustManager[] tm, SecureRandom random);
KeyManager[]パラメータが NULL の場合、このコンテキストには空のKeyManagerが定義されます。TrustManager[]パラメータが NULL の場合、インストールされたセキュリティプロバイダは、TrustManagerFactoryのもっとも優先度の高い実装で検索され、適切なTrustManagerが取得されます。同様に、SecureRandom パラメータも NULL にすることができます。その場合、デフォルト実装が使用されます。内部のデフォルトコンテキストが使用される (たとえば、JSSE の内部で
SSLContextが作成される) と、デフォルトのKeyManagerとTrustManagerが作成されます。また、デフォルトのSecureRandom実装も選択されます。
TrustManagerクラスTrustManagerは、提示された認証クレデンシャルの信頼性を判定します。 信頼できないクレデンシャルの場合、接続は切断されます。 安全なソケットピアのリモート識別情報を認証するには、1 つまたは複数のTrustManagerでSSLContextオブジェクトを初期化する必要があります。サポートされる認証機構のそれぞれに対し、TrustManagerを 1 つ渡す必要があります。SSLContextの初期化中に NULL が渡されると、トラストマネージャが作成されます。通常は、X.509 公開鍵証明書に基づく認証をサポートする単一のトラストマネージャが存在しています。安全なソケット実装には、共有の秘密鍵、Kerberos、またはその他の機構に基づく認証をサポートするものもあります。
TrustManagerFactoryクラス
javax.net.ssl.TrustManagerFactoryはプロバイダベースのサービスのエンジンクラスで、1 つまたは複数の型のTrustManagerオブジェクトのファクトリとして動作します。SunJSSEプロバイダは、基本となる X.509 トラストマネージャを返すことができるファクトリを実装します。これはプロバイダベースなので、さらにファクトリを実装して設定し、より高度なサービスを提供するトラストマネージャや、インストール専用の認証ポリシーを実装するトラストマネージャを追加したり、別に提供することができます。
TrustManagerFactoryの作成このクラスのインスタンスはSSLContextと同様の方法で作成しますが、getInstanceメソッドにプロトコル名ではなくアルゴリズム名の文字列を渡す点が異なります。public static TrustManagerFactory getInstance(String algorithm); public static TrustManagerFactory getInstance(String algorithm, String provider); public static TrustManagerFactory getInstance(String algorithm, Provider provider);アルゴリズム名文字列の例を次に示します。
"SunX509"呼び出しの例を次に示します。
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");上記の呼び出しでは、
SunJSSEプロバイダのデフォルトのトラストマネージャファクトリのインスタンスが作成され、基本となる X.509 ベースの認証パスの妥当性チェックが行われます。現在は、RFC 2459 で指定された規則のサブセットを実行します。新しく作成されたファクトリは、
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 経由でローカルディレクトリサービスのトラストデータにアクセスしたり、オンラインの証明書状態チェックサーバをリモートで使用したり、または標準のローカル位置からデフォルトのトラストデータにアクセスすることもできます。
X509TrustManagerインタフェース
javax.net.ssl.X509TrustManagerインタフェースは、汎用のTrustManagerインタフェースを拡張したものです。 X. 509ベースの認証を行う際、トラストマネージャは必ずこのインタフェースを実装します。JSSE を使ったリモートソケットピアの X.509 認証をサポートするには、このインタフェースのインスタンスを
SSLContextオブジェクトのinitメソッドに渡す必要があります。
X509TrustManagerの作成このインタフェースは、自分で直接実装することも、SunJSSEプロバイダなど、プロバイダベースのTrustManagerFactoryから取得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたトラストマネージャに委譲することもできます。たとえば、結果として生じたトラストの決定をフィルタにかけ、GUI を使ってエンドユーザに問い合わせる場合に、これを実行します。注:KeyStore パラメータを
SunJSSEのデフォルトの「SunX509」TrustManagerFactoryに渡さない場合、ファクトリは次の手順でトラストデータを検索します。
- システムプロパティ
が定義されている場合、javax.net.ssl.trustStoreTrustManagerFactoryは、このシステムプロパティで指定したファイル名を使ってファイルを検索し、このファイルをキーストアで使用します。システムプロパティjavax.net.ssl.keyStorePasswordが同様に定義されている場合は、ファイルを開く前に、その値を使ってトラストストアのデータの整合性をチェックします。
javax.net.ssl.trustStoreが定義されているものの、指定したファイルが存在しない場合、空のキーストアを使用するデフォルトのTrustManagerが作成されます。
javax.net.ssl.trustStoreシステムプロパティが指定されておらず、さらにファイルが存在すれば、そのファイルを使用します。<java-home>/lib/security/jssecacerts<java-home>の詳細については、「インストールディレクトリ <java-home>」を参照してください。それ以外の場合、
- ファイル
が存在すれば、そのファイルを使用します。<java-home>/lib/security/cacertsどのファイルも存在しない場合、それは匿名の SSL 暗号群があるためと考えられます。この暗号群は認証を行わないので、トラストストアは必要ありません。
ファクトリは、セキュリティプロパティ
javax.net.ssl.trustStore経由で指定したファイル、またはjssecacertsファイルを検索してcacertsファイルをチェックし、信頼されたルート証明書の JSSE 固有のセットを、コードに署名する目的で、cacertsにあるものとは別に提供できるようにします。独自の
X509TrustManagerの作成デフォルトのX509TrustManagerの動作がニーズに合わない場合は、独自のX509TrustManagerを作成できます。方法としては、独自のTrustManagerFactoryを作成および登録する方法と、X509TrustManagerインタフェースを直接実装する方法があります。以下の
MyX509TrustManagerクラスは、デフォルトのSunJSSEX509TrustManagerが失敗したとき、その他の認証ロジックを提供することによって、デフォルトの動作を拡張します。このようなトラストマネージャを作成できたら、class MyX509TrustManager implements X509TrustManger { X509TrustManager sunX509TrustManager; MyX509TrustManager() { // create sunX509TrustManager // // for example: // Create/load a keystore // Get instance of a "SunX509" TrustManagerFactory "tmf" // init the TrustManagerFactory with the keystore sunX509TrustManager = tmf.getTrustManagers()[0] } ... // checkClientTrusted method omitted public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException) { try { sunX509TrustManager.checkServerTrusted(chain, authType); } catch (CertificateException excep) { // do any special handling, such as popping up // dialog boxes, prompting the user, etc. } } public X509Certificate[] getAcceptedIssuers() { return sunJSSETrustManager.getAcceptedIssuers(); } }initメソッドを使って、これをSSLContextに割り当てます。 以降、このSSLContextから作成されたSocketFactoriesは、ユーザ独自のTrustManagerを使用して信頼性を判定するようになります。TrustManager[] myTM = new TrustManager [] { new MyX509TrustManager() }; SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, myTM, null);
keyStoreの動的更新MyX509TrustManagerを拡張して、キーストアの動的更新処理を行うことができます。checkClientTrustedまたはcheckServerTrustedのテストに失敗し、信頼できる証明書チェーンを確立できなかった場合、キーストアに対して、要求された信頼できる証明書を追加できます。 更新されたキーストアを使って初期化されたTrustManagerFactoryから新しいsunX509TrustManagerを作成する必要があります。 以前に初期化したSSLContextを使って新しい接続を確立すると、新しく追加された証明書が呼び出され、信頼性の判定が行われます。
KeyManagerクラス
KeyManagerは、最終的にリモートホストに送信される認証クレデンシャルを選択します。 自分自身 (ローカルのセキュリティソケットピア) をリモートの安全なソケットピアに認証させるには、1 つまたは複数のKeyManagerでSSLContextオブジェクトを初期化する必要があります。サポートされる各認証機構に、KeyManagerを 1 つ渡す必要があります。SSLContextの初期化中に NULL が渡されると、空のKeyManagerが作成されます。 内部のデフォルトコンテキストが使用されている場合は、デフォルトの KeyManager が作成されます。 通常は、X.509公開鍵証明書に基づく認証をサポートするキーマネージャが 1 つあります。安全なソケット実装には、共有の秘密鍵、Kerberos、またはその他の機構に基づく認証をサポートするものもあります。
KeyManagerFactoryクラス
javax.net.ssl.KeyManagerFactoryはプロバイダベースのサービスのエンジンクラスで、1 つまたは複数の型のKeyManagerオブジェクトのファクトリとして動作します。SunJSSEプロバイダは、基本となる X.509 キーマネージャを返すことができるファクトリを実装します。これはプロバイダベースであるため、追加のファクトリを実装し、設定することにより、追加の、または代替のキーマネージャを提供できます。
KeyManagerFactoryの作成このクラスのインスタンスはSSLContextと同様の方法で作成しますが、getInstanceメソッドにプロトコル名ではなくアルゴリズム名の文字列を渡す点が異なります。public static KeyManagerFactory getInstance(String algorithm); public static KeyManagerFactory getInstance(String algorithm, String provider); public static KeyManagerFactory getInstance(String algorithm, Provider provider);アルゴリズム名文字列の例を次に示します。
"SunX509"呼び出しの例を次に示します。
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プロバイダは「SunX509」ファクトリをサポートします。ファクトリは、KeyStore パラメータで初期化する必要があります。
X509KeyManagerインタフェースjavax.net.ssl.X509KeyManagerインタフェースは、汎用のKeyManagerインタフェースを拡張したものです。X.509 ベースの認証を行うキーマネージャで実装します。JSSE を使ったリモートソケットピアの X.509 認証をサポートするには、このインタフェースのインスタンスをSSLContextオブジェクトのinitメソッドに渡す必要があります。
X509KeyManagerの作成このインタフェースは、自分で直接実装することも、SunJSSEプロバイダなど、プロバイダベースのKeyManagerFactoryから取得することもできます。また、独自のインタフェースを実装して、ファクトリで生成されたキーマネージャに委譲することもできます。たとえば、生成される鍵をフィルタにかけ、GUI を使ってエンドユーザに問い合わせる場合に、これを実行します。注:KeyStore パラメータを
SunJSSEのデフォルトの「SunX509」KeyManagerFactoryに渡さない場合、ファクトリは次のシステムプロパティに問い合わせて、鍵データを検索します。これらのプロパティが適切なパスワードを持つファイルを指定すれば、ファクトリはこのファイルを KeyStore で使用します。そのファイルが存在しない場合、空のキーストアを使用するデフォルトのjavax.net.ssl.keyStore javax.net.ssl.keyStorePasswordKeyManagerが作成されます。一般に、ハンドシェークでサーバとして動作するプロセスには、クライアントへの認証クレデンシャルを取得するため、KeyManager のキーストアが必要です。 ただし、匿名の暗号群を選択する場合、サーバの
KeyManagerキーストアは必要ありません。 また、サーバがクライアント認証を要求しない限り、クライアントとして動作するプロセスには、KeyManagerキーストアは必要ありません。したがって、このような状況では、javax.net.ssl.keyStoreのシステムプロパティ値が定義されていない場合もあります。独自の
X509KeyManagerの作成X509KeyManagerのデフォルトの動作がニーズに合わない場合は、「独自のX509TrustManagerの作成」と同様の手順で独自のX509KeyManagerを作成できます。
TrustManagerとKeyManagerの関連性TrustManagerとKeyManagerの機能は、しばしば混同されてきました。 ここでは、各マネージャ型の主な機能を簡潔にまとめます。
型 機能 TrustManagerリモート認証クレデンシャルの信頼性 (すなわち接続の信頼性) を判定します。 KeyManagerリモートホストに送信される認証クレデンシャルを決定します。
二次サポートクラスおよびインタフェース
二次サポートクラスは、安全なソケットの作成、使用、および管理をサポートする JSSE API の一部として提供されます。このクラスは、セキュリティソケットアプリケーションでは、コアクラスやサポートクラスほどには使用されません。二次サポートクラスおよびインタフェースは
javax.net.sslおよびjavax.security.certパッケージに含まれています。
SSLSessionContextインタフェース
javax.net.ssl.SSLSessionContextは、単一のエンティティに関連付けられた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.sun.com/")).openConnection(); urlc.setHostnameVerifier(new MyHostnameVerifier());HostnameVerifierをHttpsURLConnectionに割り当てる方法については、「HttpsURLConnectionクラス」を参照してください。
X509Certificateクラス安全なソケットプロトコルの多くは、X.509 証明書という公開鍵証明書を使って認証を行います。これは、SSL および TLS プロトコルのデフォルト認証機構です。
java.security.cert.X509Certificate抽象クラスは、X.509 証明書の属性にアクセスする標準的な方法を提供します。注:
javax.security.cert.X509Certificateクラスは、以前のバージョンの JSSE (1.0.x、1.1.x) との後方互換性を確保するためのものです。 新しいアプリケーションではjava.security.cert.X509Certificateを使用し、javax.security.cert.X509Certificateは使用しません。旧バージョン (JSSE 1.0.x) の実装クラスおよびインタフェース
JSSE の旧バージョン (1.0.x) にはリファレンス実装があり、その実装では、クラスおよびインタフェースが
com.sun.net.sslパッケージで提供されました。新しいバージョンの JSSE は、J2SDK v 1.4 に統合されています。従来
com.sun.net.sslパッケージにあったクラスは、javax.net.sslパッケージに移動し、現在では標準の JSSE API に含まれています。
com.sun.net.sslのクラスとインタフェースは下位互換のために存在しているので、使用しないようお勧めします。これらのクラスとインタフェースを使って書いたアプリケーションは、再コンパイルせずに J2SDK v 1.4 で実行することができます。今後のリリースでは、このクラスとインタフェースは削除される可能性があります。そのため、新しいアプリケーションはすべてjavaxのクラスとインタフェースを使って書く方がよいでしょう。現在は、
com.sun.net.sslAPI で作成したアプリケーションは、JSSE 1.0.2 プロバイダ (com.sun.net.sslを使った場合) と、J2SDK v 1.4 用に記述された JSSE プロバイダ (javaxAPI を使った場合) のどちらでも利用できます。ただし、J2SDK v 1.4 の JSSE API を使って作成したアプリケーションは、J2SDK v 1.4 用に記述された JSSE プロバイダしか利用できません。この新しいリリースには新機能が含まれており、それを提供していないプロバイダでは、機能を利用することはできません。SunJSSEは Sun Microsystems の J2SDK で提供されるプロバイダで、javaxAPI で作成されています。JSSE 1.0.2 を使用している場合のように
java.protocol.handler.pkgsSystemプロパティを設定して URL 検索パスを更新すれば、引き続きcom.sun.net.ssl.HttpsURLConnectionを取得できます。 詳細については、「トラブルシューティング」の「HttpsURLConnectionクラスを使用するコード」を参照してください。
インストールディレクトリ<java-home>
このマニュアルでは、
<java-home>は、Java 2 Runtime Environment (JRE) がインストールされているディレクトリを表します。ディレクトリは、JSSE を実行しているのが、JavaTM 2 SDK をインストールした JRE か、インストールしていない JRE かによって異なります。Java 2 SDK には JRE が含まれていますが、ファイル階層のレベルは異なります。
<java-home>が表すディレクトリの例を、次に示します。
- Solaris で、Java 2 SDK のインストール先が
/home/user1/j2sdk1.4.0の場合、<java-home>は次の場所です。/home/user1/j2sdk1.4.0/jre
- Solaris で、JRE が
/home/user1/j2re1.4.0にインストールされており Java 2 SDK がインストールされていない場合、<java-home>は次の場所です。/home/user1/j2re1.4.0
- Win32 で、Java 2 SDK のインストール先が
C:¥j2sdk1.4.0の場合、<java-home>は次の場所です。C:¥j2sdk1.4.0¥jre
- Win32 で、JRE が
C:¥j2re1.4.0にインストールされており、Java 2 SDK がインストールされていない場合、、<java-home>は次の場所です。C:¥j2re1.4.0カスタマイズ
JSSE には、すべてのユーザが使用できる実装が含まれています。必要であれば、JSSE のさまざまな機能を変更して異なる実装を追加したり、デフォルトのキーストアを指定することもできます。次の表は、カスタマイズできる機能、デフォルト設定、およびカスタマイズの提供に使用する機構をまとめたものです。表の最初の列には、指定した機能と、カスタマイズ方法の詳細が説明されているサイトへのリンクが設定してあります。
一部の機能は、システムプロパティやセキュリティプロパティの値を設定してカスタマイズできます。表に続く節では、プロパティ値の設定方法について説明します。
重要:この表に示すプロパティの多くは、現在 JSSE 実装で使用されていますが、それらの名前や型 (システムまたはセキュリティ) が今後も変更されないという保証はなく、それが将来のリリースに存在するという保証もありません。変更や廃止の可能性があるプロパティには「*」が付いています。ここでは、JSSE 実装で使用する場合の参考として、それらに言及しています。
JSSE のカスタマイズ
| カスタマイズ項目 |
デフォルト設定 |
カスタマイズ方法 |
| X509Certificate 実装 |
Sun Microsystems の X509Certificate 実装 |
cert.provider.x509v1 セキュリティプロパティ |
| HTTPS プロトコル実装 |
Sun Microsystems の実装 |
java.protocol.handler.pkgs システムプロパティ |
| プロバイダ実装 |
SunJSSE |
セキュリティプロパティファイルの security.provider.n= 行。説明を参照 |
| デフォルトの SSLSocketFactory 実装 |
Sun Microsystems の SSLSocketFactory 実装 |
** ssl.SocketFactory.provider セキュリティプロパティ |
| デフォルトの SSLServerSocketFactory 実装 |
Sun Microsystems の SSLServerSocketFactory 実装 |
** ssl.ServerSocketFactory.provider セキュリティプロパティ |
| デフォルトのキーストア |
なし |
* javax.net.ssl.keyStore システムプロパティ |
| デフォルトのキーストア型 | KeyStore.getDefaultType() |
* javax.net.ssl.keyStoreType システムプロパティ |
| デフォルトのキーストアパスワード |
なし |
* javax.net.ssl.keyStorePassword システムプロパティ |
| デフォルトのトラストストア |
ある場合は jssecacerts。ない場合は cacerts |
* javax.net.ssl.trustStore システムプロパティ |
| デフォルトのトラストストア型 | KeyStore.getDefaultType() |
* javax.net.ssl.trustStoreType システムプロパティ |
| デフォルトのトラストストアパスワード |
なし |
* javax.net.ssl.trustStorePassword システムプロパティ |
| デフォルトのキーマネージャファクトリのアルゴリズム名 |
"SunX509" |
ssl.KeyManagerFactory.algorithm セキュリティプロパティ |
| デフォルトのトラストマネージャファクトリのアルゴリズム名 |
"SunX509" |
ssl.TrustManagerFactory.algorithm セキュリティプロパティ |
| デフォルトのプロキシホスト |
なし |
* https.proxyHost システムプロパティ |
| デフォルトのプロキシポート |
80 |
* https.proxyPort システムプロパティ |
| デフォルトの暗号群 |
ソケットファクトリによって決定 |
* https.cipherSuites システムプロパティ。 HttpsURLConnection で使用できる暗号群を指定する暗号群名リスト (コンマ区切り形式) を含む。 SSLSocket setEnabledCipherSuites(String[]) メソッドを参照 |
| デフォルトのハンドシェークプロトコル |
ソケットファクトリによって決定 |
* https.protocols システムプロパティ。 HttpsURLConnection で使用できるプロトコル群を指定するプロトコル群名リスト (コンマ区切り形式) を含む。 SSLSocket setEnabledProtocols(String[]) メソッドを参照 |
| デフォルトの https ポート |
443 |
* https URL 内の port フィールドをカスタマイズ |
| SunJSSE プロバイダが使用する暗号化アルゴリズム |
内部の SunJSSE 実装 |
SunJSSE プロバイダより JCE アルゴリズムプロバイダを優先 |
* このプロパティは現在、JSSE 実装で使用されています。他の実装での検証および使用は保証されていません。他の実装で検証する場合は、JSSE 実装と同じ方法で処理されます。プロパティが今後も存在すること、またはシステム型やセキュリティ型が将来のリリースでも変更されないことの保証はされません。
** 米国輸出規制により、Sun Microsystems の Java 2 SDK, v 1.4 の JSSE 実装に含まれるデフォルトの
SSLSocketFactory実装およびSSLServerSocketFactory実装の交換は許可されていません。 「はじめに」の接続性に関する注記を参照してください。 その他の SSL/TLS 実装を許容する 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.security.Securityプロパティの設定JSSE の機能には、セキュリティプロパティを設定してカスタマイズするものがあります。セキュリティプロパティは静的または動的に設定します。
- セキュリティプロパティを静的に設定するには、セキュリティプロパティファイルに 1 行追加します。セキュリティプロパティファイルは次のディレクトリにあります。
ここで、<java-home> は、JRE ランタイムソフトウェアのインストールディレクトリです。インストールディレクトリ <java-home> を参照してください。<java-home>/lib/security/java.securityセキュリティプロパティファイルでセキュリティプロパティ値を指定するには、次の行を追加します。
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 サーバで安全に通信できます。J2SDK では、https の URL 実装をデフォルトで提供します。別の https プロトコル実装を使用する場合は、
java.protocol.handler.pkgsのシステムプロパティに新しいクラス名を追加します。その結果、J2SDK のデフォルトクラスより前に、指定したクラスが検索され、ロードされます。詳細については、java.net.URLクラスを参照してください。旧バージョンの JSSE ユーザへの注記: 旧バージョンの JSSE では、JSSE のインストール中に
java.protocol.handler.pkgsシステムプロパティを設定する必要がありました。 このステップは、com.sun.net.ssl.HttpsURLConnectionのインスタンスを取得する場合以外は不要になりました。 詳細については、「トラブルシューティング」の「HttpsURLConnectionクラスを使用するコード」を参照してください。プロバイダ実装のカスタマイズ
J2SDK v 1.4 には、「
SunJSSE」という JSSE 暗号化サービスプロバイダ (プロバイダ) が標準で付属しています。基本的に、プロバイダは特定の暗号化アルゴリズムのエンジンクラスを実装するパッケージです。JSSE のエンジンクラスはSSLContext、KeyManagerFactory、およびTrustManagerFactoryです。プロバイダとエンジンクラスの詳細については、「JavaTM 暗号化アーキテクチャ API 仕様&リファレンス」の「設計方針」の節と「概念」の節を参照してください。プロバイダを使用するには、そのプロバイダを静的または動的に登録する必要があります。「SunJSSE」プロバイダは登録済みなので、新しく登録する必要はありません。他のプロバイダを使用する場合は、後述の節でプロバイダの登録方法を確認してください。
暗号化サービスプロバイダを静的に登録する
プロバイダを静的に登録するには、セキュリティプロパティファイルに次の行を追加します。security.provider.n=providerClassNameこれはプロバイダを宣言し、優先順位「n」を指定するものです。優先順位とは、特定プロバイダの指定がない場合に、要求されたサービスに関して検索されるプロバイダの順位です。順位は 1 から始まり、1 が最優先で次に 2、3 ...と続きます。
providerClassName は、プロバイダクラスの完全修飾名です。この名前は、プロバイダベンダーから取得します。
プロバイダを登録するには、セキュリティプロパティに上記の行を追加して、providerClassName をプロバイダクラスの完全な修飾名、n をプロバイダに割り当てる優先順位にします。
標準のセキュリティプロバイダ、および Java 2 プラットフォームに付属する SunJSSE が自動的に登録されます。
java.securityセキュリティプロパティファイルに次の行が追加され、標準のセキュリティプロバイダの優先順位が 1、SunJSSE プロバイダの優先順位が 2 として登録されます。security.provider.1=sun.security.provider.Sun security.provider.2=com.sun.net.ssl.internal.ssl.Provider他の JSSE プロバイダを使う場合は、行を追加してプロバイダを登録し、優先順位を設定します。
複数の JSSE プロバイダを同時に登録できます。プロバイダには、異なるエンジンクラスの、異なるアルゴリズムの異なる実装が含まれる場合があり、同じ型のアルゴリズムおよびエンジンクラスの一部または全部をサポートする場合もあります。特定のアルゴリズムの特定のエンジンクラス実装を検索するとき、その条件に該当する特定のプロバイダが指定されていない場合、プロバイダは優先順位付きで検索され、指定したアルゴリズムを実装する最初のプロバイダの実装が使用されます。
暗号化サービスプロバイダを動的に登録する
プロバイダを静的に登録する代わりに、プログラム開始時に
Security.addProviderメソッドを呼び出して、実行時に動的に追加することができます。たとえば、プロバイダのクラス名がMyProviderで、com.ABCパッケージにMyProviderクラスがある場合、次のようなメソッドを呼び出してプロバイダを動的に追加します。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システムプロパティでキーストアを指定すると、デフォルトのSSLContextで作成したKeyManagerは、指定したキーストアを管理するKeyManager実装になります。実際には「デフォルト鍵とトラストマネージャ」で説明したとおりに実装されます。システムプロパティが指定されない場合は、KeyManagerが管理するキーストアは新しい空のキーストアです。同様に、トラストストアを
javax.net.ssl.trustStoreシステムプロパティで指定すると、デフォルトのSSLContextで作成したTrustManagerが、指定したトラストストアを管理するTrustManager実装になります。この場合、プロパティが存在しても指定するファイルが存在しなければ、トラストストアは使用されません。javax.net.ssl.trustStoreプロパティが存在しない場合は、デフォルトのトラストストアを検索します。<java-home>/lib/security/jssecacertsというトラストストアが見つかった場合、これを使用します。このトラストストアが見つからない場合、<java-home>/lib/security/jssecacertsというトラストストアを検索し、見つかればこれを使用します。<java-home>については「インストールディレクトリ <java-home>」を参照してください。トラストストアが見つからない場合、TrustManagerは新しい空のトラストストアを管理します。
重要: J2SDK には、少数の信頼されたルート証明書を含む<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またはTrustManagerの実装になります。これについては、後の節で説明します。選択される
KeyManager実装は、まずセキュリティプロパティを確認して決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのssl.KeyManagerFactory.algorithmKeyManagerFactory実装が検索されます。実装を提供する最初のプロバイダの実装が使用されます。実装のgetKeyManagersメソッドが呼び出され、デフォルトのSSLContextに提供するKeyManagerが決定されます。技術的には、getKeyManagersはKeyManagerの配列を返します。これは鍵データの型ごとのKeyManagerです。そのようなセキュリティプロパティ値が指定されていない場合、「SunX509」のデフォルト値を使って検索します。注:「SunX509」アルゴリズムのKeyManagerFactory実装はSunJSSEプロバイダが提供します。プロバイダが指定するKeyManagerはjavax.net.ssl.X509KeyManager実装です。同様に、選択される
TrustManager実装は、まずセキュリティプロパティを確認して決定されます。そのようなプロパティ値が指定されていると、指定したアルゴリズムのssl.TrustManagerFactory.algorithmTrustManagerFactory実装が検索されます。実装を提供する最初のプロバイダの実装が使用されます。実装のgetTrustManagersメソッドが呼び出され、デフォルトのSSLContextに提供するTrustManagerが決定されます。技術的には、getTrustManagersはTrustManagerの配列を返します。これは鍵データの型ごとのTrustManagerです。そのようなセキュリティプロパティ値が指定されていない場合、「SunX509」のデフォルト値を使って検索します。注:「SunX509」アルゴリズムのTrustManagerFactory実装はSunJSSEプロバイダが提供します。プロバイダが指定するTrustManagerはjavax.net.ssl.X509TrustManager実装です。重要: この節では、現在の JSSE リファレンス実装の動作を説明します。この節で説明するシステムプロパティの名前と型 (システムかセキュリティか) が今後も使用されるという保証はありません。また、今後のリリースで存在するという保証もありせん。また、他の JSSE 実装での検証や使用も保証されていません。実装で検証された場合、個々で説明した JSSE リファレンス実装と同じ方法で処理してください。
暗号化アルゴリズムプロバイダのカスタマイズ
SunJSSE プロバイダは、暗号化アルゴリズム (RSA、RC4、DES、Triple DES) として JCE プロバイダを利用できます。 以前は、暗号化アルゴリズムとして、もっぱら内部実装が利用されていました。
現在では、SunJSSE よりも優先順位の高いプロバイダの実装を利用できます。 プロバイダの優先順位が低い場合、このプロバイダは無視され、SunJSSE 内部実装のほうが選択されます。 プロバイダの構成には、標準 JCA 機構を使用できます。まず、以下のセキュリティプロパティファイルを利用して静的に行う方法があります。
次に、<java-home>/lib/security/java.securityjava.security.SecurityクラスのaddProviderメソッドまたはinsertProviderAtメソッドを利用して動的に行う方法があります。<java-home>の詳細については、「インストールディレクトリ <java-home>」を参照してください。 たとえば、次のような文があるとします。この文は、SunJSSE プロバイダが二次プロバイダとして構成されているものと想定して、Security.insertProviderAt(new MyProvider(), 2);MyProviderで SunJSSE 以前の関連暗号化アルゴリズムを検索することを指定します。 ただし、これは、デフォルト構成が使用されていて、Sun が一次プロバイダとして指定されている場合です。 Sun プロバイダを一次プロバイダのままにしておくことを強くお勧めします。プロバイダの実装を行うユーザへの注記
SunJSSE が
Cipher.getInstance()を呼び出すとき、使用される変換文字列は "RSA/ECB/PKCS1Padding"、"RC4"、"DES/CBC/NoPadding"、"DESede/CBC/NoPadding" になります。 Cipher クラスと変換文字列の詳細については、「JCE リファレンスガイド」を参照してください。
JSSE の
SunJSSEプロバイダは、PKCS12java.security.KeyStore形式の実装を提供します。この形式も他のツールキットやアプリケーションでサポートされ、鍵と証明書をインポートおよびエクスポートします。たとえば、Netscape 4.x (バージョン 4.04 以降) はクライアントの証明書と鍵を、PKCS12 形式 (ファイル拡張子は「.p12」) でファイルにエクスポートできます。
SunJSSEプロバイダでは、キーストア型「pkcs12」(または PKCS12、大文字と小文字は区別されません) を使って、KeyStore API を介して PKCS12 にアクセスできます。さらに keytool コマンドと、pkcs12に設定された-storetypeオプションを使って、インストールされた鍵を表示できます。keytool については「セキュリティツール」を参照してください。J2SDK v 1.4 の JSSE には実装上の限界がありますが、Netscape Navigator でエクスポートされた PKCS12 キーストアファイルを読み取り、使用することができます。今後のリリースでは、Internet Explorer や他のアプリケーションでのサポートもテストする予定です。PKCS12 の扱いについては、使用するリリースの README ファイルを参照してください。
構成上の問題点
CertificateException: (ハンドシェーク時)
問題: SSL 接続のネゴシエーション中に、クライアントまたはサーバが CertificateException をスローします。
原因 1:多くの場合、リモートサイドがローカルサイドにとって不明な証明書を送信することが原因です。
解決法 1:このような問題を解決するには、デバッグをオンにして、証明書のロード時、およびネットワーク接続からの受信時を観察します。デバッグについては、「デバッグユーティリティ」を参照してください。多くの場合、間違ったトラストファイルをロードしたため、受信した証明書がトラスト機構にとって不明です。 詳細については、以下の節を参照してください。
原因 2:システムクロックが正しく設定されていません。
解決法 2:クロックが正しく設定されていない場合、認識された時間が証明書の有効期間外になっている可能性があります。トラストストアの有効な証明書と置き換えない限り、システムはこの証明書を無効とみなし、例外をスローします。
実行時例外:SSL Service Not Available
問題:JSSE を使うプログラムを実行すると、SSL サービスが利用できないという例外が発生します。たとえば、次のような例外が発生します。
Exception in thread "main" java.net.SocketException: no SSL Server Sockets Exception in thread "main": SSL implementation not available原因:
SSLContextの初期化時に問題が発生しています。たとえば、キーストアに正しいパスワードが入力されなかったか、キーストアが破損している可能性があります。なお、 この種のエラーが発生するのは、以前に未知の形式のキーストアを提供する J2SDK ベンダーがあったためです。解決法:初期化パラメータを確認します。指定したキーストアが有効であり、指定したパスワードが正しいことを確認します。keytool を使うと、キーストアとその内容を調べることができます。
例外 "No available certificate corresponding to the SSL cipher suites which are enabled"
問題: 単純な SSL Server プログラムを実行しようとすると、以下の例外がスローされます。
Exception in thread "main" javax.net.ssl.SSLException: No available certificate corresponding to the SSL cipher suites which are enabled...原因: 必要な鍵データの型は暗号群によって異なります。 たとえば、RSA 暗号群が有効になっている場合、キーストアで RSA の
keyEntryを有効にする必要があります。 該当する鍵を使用できない場合、その暗号群を使用することはできません。 有効になっているすべての暗号群の鍵のエントリが使用できない場合、この例外がスローされます。解決法: 暗号群の型にあった鍵エントリを作成します。または匿名の暗号群を使用します。 匿名の暗号群には、"man-in-the-middle" 攻撃に対して脆弱であるという潜在的な危険性があります。詳細については RFC 2246 を参照してください。 正しいキーストアおよび証明書を渡す方法については、以下の節を参照してください。
実行時例外:No Cipher Suites in Common
問題 1: ハンドシェーク時にクライアントやサーバがこの例外をスローします。
原因 1: SSL 接続の両側が共通の暗号群について合意している必要があります。 クライアントの暗号群セットとサーバの暗号群セットの共通点がない場合、この例外がスローされます。
解決法 1: 有効な暗号群セットを構成し、共通の暗号群を追加します。さらに、非対称の暗号群に適切な
keyEntryが提供されるようにします。 この節の「例外、"No available certificate..."」を参照してください。問題 2:DSA ベースの証明書しかないサーバのファイルに Netscape Navigator や Microsoft Internet Explorer (IE) で アクセスすると、共通の暗号群がないという実行時例外が発生します。
原因 2: デフォルトでは、keytool で作成された
keyEntriesは DSA 公開鍵を使用します。 キーストア内に DSA のkeyEntriesが存在する場合、使用できるのは DSA ベースの暗号群のみです。 デフォルトでは、Navigator と IE は RSA ベースの暗号群のみを送信します。 クライアントとサーバの暗号群セットの共通点がないため、この例外がスローされます。解決法 2:Navigator や IE を使う場合は、RSA ベースの鍵を使う証明書を作成します。そのためには、keytool 使用時に
-keyalgRSA オプションを指定する必要があります。例を示します。keytool -genkey -alias duke -keystore testkeys -keyalg rsaJSSE の最初のアクセスが遅い
問題: 最初のアクセスで JSSE が停止したように見えます。
原因:JSSE には乱数の安全なソースが必要です。初期化には時間がかかります。
解決法:別の乱数発生関数を使用するか、オーバーヘッドが通知されない場合は次の方法で先に初期化します。
SecureRandom sr = new SecureRandom(); sr.nextInt(); SSLContext.init(..., ..., sr);
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://foo.com/").openConnection();javax.net.ssl.HttpsURLConnectionを返し、ClassCastExceptionをスローします。原因: デフォルトでは、"https" URL を開くと
javax.net.ssl.HttpsURLConnectionが作成されます。解決法: 以前のリリースの JDK (Java 2 SDK 以前) には、"https" URL の実装が付属していません。 JSSE 1.0.x 実装は、"https" URL ハンドラを提供します。インストールガイドにも、URL ハンドラの検索パスを設定して JSSE 1.0.x の
com.sun.net.ssl.HttpsURLConnection実装を取得する方法が記載されています。現在のリリースでは、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 YourClassSystem.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
ClientHelloメッセージの送信後ソケットが切断される問題: 接続するために
ClientHelloメッセージを送信したあと、ただちにソケットが切断されます。原因: SSL/TLS サーバの中には、受信した
ClientHelloメッセージの形式を判断できない場合や、このメッセージのプロトコルのバージョンがサポート対象外である場合、接続を切断するものがあります。解決法:
SSLSocket.setEnabledProtocolsでプロトコルの調整を試みてください。たとえば、従来のサーバ実装には、SSLv3 のみに対応し、TLS に対応していないものがあります。 理論的に言えば、こうした実装は SSLv3 でネゴシエーションを行うはずですが、実際にはハングアップするだけです。 後方互換性のため、一部のサーバ実装 (SunJSSE など) は SSLv3 /TLS のClientHelloを SSLv2 のClientHelloパケットにカプセル化して送信します。 しかし、この形式をサポートしないサーバもあります。この場合は、setEnabledProtocolsを使って、送信時の SSLv2 のClientHelloパケットへのカプセル化を無効にします。デバッグユーティリティ
JSSE には、動的デバッグのトレースをサポートする機能があります。これは、Java 2 プラットフォームでデバッグのアクセス制御に失敗した場合に使用するサポート機能に似ています。汎用の Java 動的デバッグトレースサポートにはシステムプロパティ
java.security.debugでアクセスしますが、JSSE 固有の動的デバッグトレースサポートにはシステムプロパティjavax.net.debugでアクセスします。注:デバッグユーティリティは、公式にサポートされている JSSE 機能ではありません。
JSSE 動的デバッグユーティリティのオプションを表示するには、
javaコマンドで次のコマンド行オプションを使用します。-Djavax.net.debug=help注:デバッグ用に設計されたユーティリティでクラスを使用しないプログラムを実行しているとき、どちらの動的デバッグユーティリティで
helpを指定しても、デバッグオプションは使用できません。デバッグオプションのリストを表示させる方法の例を、次に示します。
java -Djavax.net.debug=help MyAppMyApp は、JSSE クラスを使用するアプリケーションです。MyApp は、デバッグのヘルプ情報が表示されると動作しなくなります。ヘルプコードによりアプリケーションが終了するためです。
現在のオプションは次のとおりです。
all turn on all debugging ssl turn on ssl debugging The following can be used with ssl: record enable per-record tracing handshake print each handshake message keygen print key generation data session print session activity defaultctx print default SSL initialization sslctx print SSLContext tracing sessioncache print session cache tracing keymanager print key manager tracing trustmanager print trust manager tracing handshake debugging can be widened with: data hex dump of each handshake message verbose verbose handshake message printing record debugging can be widened with: plaintext hex dump of record plaintext
javax.net.debugプロパティ値は、allまたはsslを指定する必要があり、デバッグ指定子がその後に続く場合もあります。1 つまたは複数のオプションが使用できます。オプションをセパレータで区切る必要はありませんが、「:」や「,」を使用すると読みやすくなります。どのセパレータも使用でき、オプションキーワードの順序も重要ではありません。例
- デバッグメッセージをすべて表示する場合は、次のように入力します。
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
以下の節では、次のコード例について説明します。
- 安全でないソケットから安全なソケットへの変換
- JSSE サンプルコードの実行
- JSSE で使用するキーストアの作成
安全でないソケットから安全なソケットへの変換
この節では、JSSE を使って、安全でないソケット接続を安全なソケット接続に変換するソースコードの例を説明します。この節のコードは『Java 2 Network Security』(Marco Pistoia ほか著) から引用したものです。
まず、「SSL を使用しないソケットの例」で、安全でないソケットを使ってクライアントとサーバ間の通信を設定するサンプルコードを示します。次に、「SSL を使用するソケットの例」ではこのコードを変更し、JSSE を使用して安全なソケット通信を設定します。
SSL を使用しないソケットの例
安全でないソケット通信のサーバコード
サーバとして動作し、ソケットを使ってクライアントと通信する Java プログラムを作成する場合、次のようなコードでソケット通信を設定します。
import java.io.*; import java.net.*; . . . int port = availablePortNumber; ServerSocket s; try { s = new ServerSocket(port); Socket c = s.accept(); OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); // Send messages to the client through // the OutputStream // Receive messages from the client // through the InputStream } catch (IOException e) { }安全でないソケット通信のクライアントコード
ソケットを使ってサーバとの通信を設定するクライアントコードの例を、次に示します。
import java.io.*; import java.net.*; . . . int port = availablePortNumber; String host = "hostname"; try { s = new Socket(host, port); OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream(); // Send messages to the server through // the OutputStream // Receive messages from the server // through the InputStream } catch (IOException e) { }SSL を使用するソケットの例
安全なソケット通信のサーバコード
サーバとして動作し、安全なソケットでクライアントと通信する Java プログラムを作成する場合、次のようなコードでソケット通信を設定します。安全でないソケットを使った通信のプログラムとこのプログラムとの違いは、太字で示されています。
import java.io.*; import javax.net.ssl.*; . . . int port = availablePortNumber; SSLServerSocket s; try { SSLServerSocketFactory sslSrvFact = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); s =(SSLServerSocket)sslSrvFact.createServerSocket(port); SSLSocket c = (SSLSocket)s.accept(); OutputStream out = c.getOutputStream(); InputStream in = c.getInputStream(); // Send messages to the client through // the OutputStream // Receive messages from the client // through the InputStream } catch (IOException e) { }安全なソケット通信のクライアントコード
安全なソケットを使ってサーバとの通信を設定するクライアントコードの例を、次に示します。安全でないソケットとの違いは、太字で示されています。
import java.io.*; import javax.net.ssl.*; . . . int port = availablePortNumber; String host = "hostname"; try { SSLSocketFactory sslFact = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket s = (SSLSocket)sslFact.createSocket(host, port); OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream(); // Send messages to the server through // the OutputStream // Receive messages from the server // through the InputStream } catch (IOException e) { }JSSE サンプルコードの実行
JSSE サンプルプログラムでは、JSSE を使って次の処理を行う方法を示します。
サンプルコードを使用する場合、サンプルプログラムは JSSE の使い方を示すためのものである点に注意してください。堅牢なアプリケーションを開発するためのものではありません。
注:安全な通信を設定すると、アルゴリズムが複雑になります。サンプルプログラムでは、設定プロセス中のフィードバックがありません。プログラム実行時には、一定時間待っても結果が表示されない場合があります。システムプロパティ
javax.net.debugの設定をallにして、プログラムを実行すると、フィードバックが表示されます。サンプルコードの場所
サンプルコードは、このドキュメントと同じディレクトリの samples サブディレクトリに格納されています。 以下のリンクから、すべてのサンプルファイルのリストとテキストファイルを表示できます。 このページから、すべてのサンプルファイルが含まれた zip ファイルもダウンロードできます。zip ファイルは、このドキュメントを Web 経由で表示している場合に便利です。
以下の節では、サンプルについて説明します。詳細については、README を参照してください。
クライアントとサーバの安全なソケット接続を表すサンプルコード
samples/socketsディレクトリにあるサンプルプログラムは、クライアントとサーバとの間で安全なソケット接続を設定する方法を示しています。サンプルのクライアントプログラムを実行中に、商用 Web サーバなどの既存のサーバと通信できます。また、サンプルのプログラムサーバ
ClassFileServerと通信することもできます。サンプルのクライアントプログラムとサーバプログラムは、同じネットワークに接続された別個のマシンで実行することも、別々のターミナルウィンドウから同一マシン上で実行することもできます。
samples/sockets/clientディレクトリのサンプルSSLSocketClient* プログラム (および HTTPS 接続のサンプルコードで説明する URLReader* プログラム) は、すべてClassFileServerサンプルサーバプログラムで実行できます。この例は、「ClassFileServerを使ったSSLSocketClientWithClientAuthの実行」に示されています。URLReader、SSLSocketClient、またはSSLSocketClientWithTunnelingをClassFileServerで実行する場合も、同様の変更ができます。クライアントとサーバとの間でメッセージを送信しようとすると認証エラーが発生する場合、Web サーバと
ClassFileServerのどちらを使用しているとしても、必要な鍵がトラストストア (トラスト鍵データベース) にない可能性があります。たとえば、ClassFileServerは「testkeys」というキーストアを使用します。これには、SSL ハンドシェーク中に必要な「duke」の公開鍵が含まれています。「testkeys」はClassFileServerソースと同じディレクトリsamples/sockets/serverにあります。参照するトラストストアで、「duke」の公開鍵に対応する証明書をクライアントが検索できない場合、認証エラーが発生します。次の節で説明するように、samplecacertsトラストストア (「duke」公開鍵がある) の扱いには注意してください。設定要件
クライアントとサーバとの間の安全なソケット接続を作成するサンプルプログラムを実行する場合は、適切な証明書ファイル (トラストストア) を利用できるようにしておく必要があります。クライアントプログラムとサーバプログラムの両方で、
samplesディレクトリのsamplecacerts証明書ファイルを使用します。この証明書ファイルを使うと、クライアントがサーバを認証できるようになります。このファイルには、J2SDK (cacertsファイルにある) に付属する、一般的な証明書発行局の発行した証明書がすべて含まれており、また、サンプルサーバClassFileServerとの通信時にクライアントが「duke」を証明するのに必要な「duke」の証明書も含まれています。(ClassFileServerは、「duke」の公開鍵を含むキーストアを使用します。これは、samplecacertsの公開鍵に対応しています。 )クライアントとサーバの両方で
samplecacertsファイルを使用するには、ファイルを<java-home>/lib/security/jssecacertsファイルにコピーして名前をcacertsに変更し、<java-home>/lib/security/cacertsファイルと置き換えるか、クライアントとサーバのjavaコマンドを実行中に、次のオプションをコマンド行に追加します。-Djavax.net.ssl.trustStore=path_to_samplecacerts_file
<java-home>の詳細については、「インストールディレクトリ <java-home>」を参照してください。
samplecacertsトラストストアのパスワードはchangeitです。keytool を使って、サンプルに独自の証明書を置き換えることができます。Netscape Navigator や Internet Explorer などのブラウザを使用して
ClassFileServerにあるサンプルの SSL サーバにアクセスすると、ダイアログボックスが開いて、証明書が認識されないというメッセージが表示されます。これは、サンプルプログラムで使用する証明書は自己署名付きのもので、テスト用にすぎないためです。現在のセッションで証明書に同意できます。SSL サーバのテストが終了した後、ブラウザを終了し、ブラウザの名前空間からテスト用証明書を削除します。注:
samplesディレクトリの「duke」証明書は、http://java.sun.com/security/signExample12/のセキュリティサンプルで使用する「duke」証明書とは異なります。両方の「duke」証明書をインストールすると、サンプルコードは正しく動作しません。証明書ファイルで利用できる証明書を表示するには、keytool コマンドを使用します。
SSLSocketClientの実行SSLSocketClient.java プログラムは、
SSLSocketを使うクライアントを作成し、HTTP 要求を送信して HTTP サーバから応答を受け取る方法を実際に示します。 このプログラムの出力が、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/を設定します。 これらのパラメータを使用したときの出力が、https://www.verisign.com/の HTML ソースです。
SSLSocketClientWithClientAuthを実行してクライアント認証を行うには、クライアント認証を要求するサーバにアクセスする必要があります。このサーバには、サンプルプログラムClassFileServerを使用できます。これについては、次の節で説明します。
ClassFileServerの実行ここで
ClassFileServerと呼ばれているプログラムは、ClassFileServer.java と ClassServer.java の 2 つのファイルで構成されています。これらを実行するには、
ClassFileServer.classを実行します。その際は次のパラメータが必要です。
port- ポートのパラメータは、利用できる未使用のポート番号です。たとえば、2001 のような数字を使うことができます。
docroot- このパラメータは、検索するファイルを含むサーバのディレクトリを表します。たとえば、Solaris では/home/userid/(useridは特定のユーザ ID)、Win32 ではc:¥となります。
TLS- オプションのパラメータです。サーバが SSL または TLS を使用することを表します。
true- オプションのパラメータです。クライアント認証が必要なことを表します。このパラメータは、TLS パラメータが設定されているかどうかだけを参照します。注意 1:
TLSおよびtrueパラメータはオプションです。使用しない場合は、TLS ではない通常のファイルサーバだけが認証なしで使用され、何も起こりません。これは、片方の側 (クライアント) が TLS とネゴシエーションを行おうとしても、もう一方の側 (サーバ) はネゴシエーションを行おうとしないため、通信ができないからです。注意 2:サーバは "GET /..." の形式で GET 要求を期待します。"..." はファイルへのパスを表します。
ClassFileServerを使ったSSLSocketClientWithClientAuthの実行サンプルプログラム SSLSocketClientWithClientAuth および
ClassFileServerを使って、認証済みの通信を設定できます。この通信では、クライアントとサーバが相互に認証します。両方のサンプルプログラムを同じネットワークに接続された別個のマシン上で実行することも、同じマシン上の別のターミナルウィンドウまたはコマンドプロンプトウィンドウから実行することもできます。クライアントとサーバを設定するには、次の操作を実行します。注:他の SSLCient* アプリケーションの "GET" コマンドを変更すると、
ClassFileServerプログラムを、1 台のマシンやターミナルウィンドウから実行します。「ClassFileServerの実行」を参照してください。
SSLSocketClientWithClientAuthプログラムを別のマシンやターミナルウィンドウで実行します。SSLSocketClientWithClientAuthには、次のパラメータが必要です。
host-ClassFileServerを実行するマシンのホスト名です。
port-ClassFileServerに指定したのと同じポートです。
requestedfilepath- サーバから検索するファイルのパスです。このパラメータには、/filepathを使用します。GET 文の一部として使用されるので、ファイルパスにはフォワードスラッシュが必要です。GET 文には、稼動中のオペレーティングシステムの種類にかかわらず、フォワードスラッシュが必要です。文の構成は次のようになります。"GET " + requestedfilepath + " HTTP/1.1"ClassFileServerが動作しているローカルマシンに接続できます。HTTPS 接続を表すサンプルコード
JSSE を介して安全な通信にアクセスするための主要な API は 2 つあります。1 つは任意の安全な通信に使用できるソケットレベルの APIで、
SSLSocketClient、SSLSocketClientWithTunneling、およびSSLSocketClientWithClientAuth(ClassFileServerを使用する場合と使用しない場合がある) のサンプルプログラムに示されています。もう 1 つはもっと簡単な方法で、標準の 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 つ含まれています。どちらのサンプルプログラムも urls ディレクトリにあります。
URLReader の実行
URLReader.java プログラムは、安全なサイトにアクセスする URL クラスの使い方を示します。 このプログラムの出力は、
https://www.verisign.com/の HTML ソースです。デフォルトで、J2SDK v 1.4 の 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");注:Windows 95 または Windows 98 で実行している場合、コマンド行オプションをすべて含めるには、MS-DOS プロンプトで使用できる文字数では足りない場合があります。その場合、entire コマンドを使用して .bat ファイルを作成するか、ソースコードにシステムプロパティを追加して、ソースコードを再コンパイルします。
URLReaderWithOptions の実行
URLReaderWithOptions.java プログラムは基本的には URLReader と同じですが、実行時にプログラムの引数として次のシステムプロパティのどれか、または全部をオプションで入力できる点が異なります。
- java.protocol.handler.pkgs
- https.proxyHost
- https.proxyPort
- https.cipherSuites
URLReaderWithOptions を実行するには、次のコマンドを 1 行で入力します。
java URLReaderWithOptions [-h proxyhost -p proxyport] [-k protocolhandlerpkgs] [-c ciphersarray] myApp注:複数のプロトコルハンドラを、縦線で区切った項目のリストで
protocolhandlerpkgsに含めることができます。複数の SSL 暗号群名を、カンマで区切った項目のリストでciphersarrayに含めることができます。可能な暗号群名はSSLSocket.getSupportedCipherSuites()呼び出しで返されたものと同じです。暗号群は SSL および TLS プロトコルの仕様から命名されています。米国 Sun Microsystems, Inc. が提供するデフォルトのプロトコルハンドラ実装以外の HTTPS プロトコルハンドラ実装を使う場合は、
protocolhandlerpkgs引数だけが必要です。ファイアウォールの外側で実行している場合は、プロキシホストおよびプロキシポートの引数を含める必要があります。また、使用できる暗号群のリストを含めることもできます。
次に、URLReaderWithOptions の実行例と、ポート 8080 にプロキシポート "webproxy" を指定する場合の例を示します。
java URLReaderWithOptions -h webproxy -p 8080安全な RMI 接続を表すサンプルコード
samples/rmiディレクトリのサンプルコードは、安全な RMI 接続の作成方法を示しています。サンプルコードは、RMI のサンプルに基づいています。基本的には "Hello World" のサンプルを変更し、カスタム RMI ソケットファクトリをインストールして使用します。RMI については、Java RMI ドキュメントを参照してください。この Web ページは、RMI のチュートリアルと RMI に関する他の情報を記載した Web ページです。
JSSE で使用するキーストアの作成
単純なキーストアとトラストストアの作成
この節では、keytoolを使って、JSSE での使用に適した単純な JKS キーストアを作成します。 キーストア内に (公開/非公開鍵を持つ)keyEntryを作成し、トラストストア内に対応するtrustedCertEntry(公開鍵のみ) を作成します。 クライアント認証の場合、クライアントの証明書に対して同じ処理を行う必要があります。注: ここでは、各ステップに関する詳しい解説は省略します。 詳細については、Solaris または Win32 の keytool に関するドキュメントを参照してください。ユーザ入力は太字で示します。
- 対応する公開/非公開鍵とともに、新しいキーストアと自己署名付き証明書を作成します。
これが、サーバの使用するキーストアです。% keytool -genkey -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]: Sun Microsystems, 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="Sun Microsystems, 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="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, 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="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, 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="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, 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:74X509KeyManagerおよびX509TrustManagerを使用するものとします。したがって、「カスタマイズ」で説明したシステムプロパティを使用してキーストアを選択します。% java -Djavax.net.ssl.keyStore=keystore ¥ -Djavax.net.ssl.keyStorePassword=password Server % java -Djavax.net.ssl.trustStore=truststore ¥ -Djavax.net.ssl.trustStorePassword=trustword Client
注: この例では、サーバの認証のみを行なっています。 クライアントの認証が必要な場合は、クライアントの鍵に対して同様のキーストアを用意し、サーバに対して適切なトラストストアを提供する必要があります。
SSLContextのgetInstanceメソッドに渡されるプロトコル名のパラメータprotocolは、名前付きの安全なソケットプロトコルをサポートし、「/」でプロトコル名から区切られた名前付きの目的もオプションでサポートします。次の表は、一般的な標準プロトコル名を示しています。
プロトコル 備考 SSL SSL の一部のバージョンをサポートする。他のバージョンをサポートする場合もある SSLv2 SSL バージョン 2 以降をサポートする SSLv3 SSL バージョン 3 をサポートする。他のバージョンをサポートする場合もある TLS TLS の一部のバージョンをサポートする。他のバージョンをサポートする場合もある TLSv1 TLS バージョン 1 をサポートする。他のバージョンをサポートする場合もある
X509KeyManagerのchooseClientAliasメソッド、chooseServerAliasメソッド、getClientAliasesメソッド、getServerAliasesメソッドに渡されるkeyTypeパラメータは、公開鍵の型を指定します。 以下の表には、指定された証明書のタイプ別に、keyTypeで使用される標準名を一覧表示します。
名前 証明書のタイプ 対応 (RFC 2246) RSA RSA rsa_sign(1) DSA DSA dss_sign(2) DH_RSA Diffie-Hellman (RSA 署名を使用) rsa_fixed_dh(3) DH_DSA Diffie-Hellman (DSA 署名を使用) dss_fixed_dh(4)
SSLSocketのsetEnabledProtocolsメソッドに渡されるprotocolsパラメータは、接続で使用できるプロトコルのバージョンを指定します。 以下の表には、setEnabledProtocolsに渡される標準名、またはSSLSocket getSupportedProtocolsメソッドとgetEnabledProtocolsメソッドから返される標準名を一覧表示します。
名前 プロトコル SSLv2 SSL バージョン 2 プロトコル SSLv3 SSL バージョン 3 プロトコル TLSv1 TLS バージョン 1 プロトコル (RFC 2246 に定義) SSLv2Hello SSLv2 hello の送信を有効にする。 互換性のため、SSLv3、TLSv1 などの一部のプロトコルは、SSLv3/TLSv1 hello を SSLv2 形式の hello にカプセル化して送信できる
X509TrustManagerのcheckClientTrustedメソッドとcheckServerTrustedメソッドに渡されるauthTypeパラメータは、認証のタイプを示します。 以下の表には、クライアントまたはサーバの証明書チェーンで使用される標準名を示します。
クライアントまたはサーバの証明書チェーン 認証の標準名 クライアント 実際に使用する証明書によって異なる。 たとえば、RSAPublicKey を使用する場合、 authTypeは "RSA" になるサーバ 暗号群の鍵交換アルゴリズム部分が、"RSA"、"DHE_DSS" のような文字列で表される。注: エクスポート可能な暗号群では、実行時、ハンドシェーク中に鍵交換アルゴリズムが決定される場合がある。 たとえば、TLS_RSA_EXPORT_WITH_RC4_40_MD5 の authTypeは、一時的な RSA 鍵を使って鍵交換を行う場合は "RSA_EXPORT"、サーバ証明書の鍵を使用する場合は "RSA" になる。 それ以外の場合は "UNKNOWN"