JavaでSSL/TLS通信をしたい時に通常はJSSE(Java Secure Socket Extension)という仕組み使うんですが、これ使えば、実装色々切り替えたり、追加したりなんてことができます。Apache Tomcat(+Sun Java JSSE)だとCamellia系のCipherSuitesに対応してないそうで、何か対応してるもの、追加で対応できそうなものを調べてみました。

Sun Javaで使えるJSSEってあんまり選択肢がないのね

下の例のようにJSSEプロバイダ名を指定することによりJSSEを切り替えればいろんなSSLエンジンを試せるわけですが、

SSLContext ctx = SSLContext.getInstance(アルゴリズム名, プロバイダ名);
SSLContext ctx = SSLContext.getInstance("SSL", "SunJSSE");
SSLContext ctx = SSLContext.getInstance("TLS", "HarmonyJSSE");
Sun Javaで使えそうなJSSEの選択肢って少ないんだなぁってことが調査してみるとわかりました。Sun Javaで使えそうなのは標準品を含めて以下の3つぐらいしかなさそう。 暗号アルゴリズム系のためのJCE対応のライブラリは潤沢にある中、JSSEの方は選択肢がすくないですね。

なんか調べてみるとJSSEはJava VMに依存している方が多いんじゃないかって 感じがします。

新しいCipher Suitesを追加したいと思ったら、Sun Java用にJSSEを書き起こすっていう 手もありですが、コード署名しないと何かと面倒なのでおススメではありません。 JESSIEでやろうとするとGNU classpathなんでちょっとなぁ、、、と。JESSIE自体、 あんまりメンテナンスしてないみたいだし。 で、最終的にApache Harmonyを調べてみるのがいいのかな、、と思ったわけです。 Apache HarmonyはオープンソースでフリーなJavaの実装だそうです。

Apache HarmonyとTomcatを試してみる

Apahce HarmonyのSSL/TLSの機能というか、JSSEの機能は暗号ライブラリとしてBouncyCastle JCE Libraryを使用しており、SunJCEは使えません。 従ってHTTPSのためのSSLサーバー証明書と鍵はJKS形式はSun独自の形式なので使えなくてBouncyCastle JCEがサポートしている PKCS#12かBKS(BouncyCastle Key Store)形式を使う必要があります。 ただ、OpenSSLで生成したPKCS#12でやってみたところMacエラーだったりで読み込めず BKSを使うのがよいのかもしれません。 JKSからBKSへの変換ツールは「ここ」に置いてみたので使ってみてください。

conf/server.xmlファイルにはこんな感じでkeystoreFile、keystorePass 、keystoreTypeを設定します。

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
 maxThreads="150" scheme="https" secure="true"
 clientAuth="false" sslProtocol="TLS"
 keystoreFile="conf/zzz.bks"
 keystorePass="changeit"
 keystoreType="BKS" />

あとはbin/catalina.batに以下のようなパス設定をしとけばApache Tomcat + Apache Harmonyは動くと思います。
set CATALINA_HOME=C:\Java\apache-tomcat-6.0.30-wharmony
set JAVA_HOME=C:\harmony-6.0-jdk-991881
set JRE_HOME=C:\harmony-6.0-jdk-991881\jre
ウェブブラウザ等でHTTPSでつなぐことはできたでしょうか?

で、OpenSSLで繋いでみる

openssl s_client機能を使ってApache Tomcat + Harmonyのサーバーに接続してみましょう。

% openssl s_client -host zzz.com -port 8443
CONNECTED(00000003)
depth=1 /C=JP/O=HOGE
verify error:num=19:self signed certificate in certificate chain
verify return:0
14052:error:04077068:rsa routines:RSA_verify:bad signature:rsa_sign.c:209:
14052:error:1408D07B:SSL routines:SSL3_GET_KEY_EXCHANGE:bad signature:s3_clnt.c:1447:
とJava実装やブラウザだと出てこないエラーが出てきてしまいました。ググってみるに-cipherを設定しないことが 原因のようで-cipher 'ALL:!kEDH'を指定してちょっと絞り込みをしないといけないそうです。
% openssl s_client -host zzz.com -port 8443 -cipher 'ALL:!kEDH'
CONNECTED(00000003)
中略
depth=1 /C=JP/O=HOGE
verify error:num=19:self signed certificate in certificate chain
verify return:0
read R BLOCK
DONE
これでApache Tomcat + HarmonyにOpenSSL s_clientで繋ぐことができるようになりました。

Apache HarmonyのJSSEのコード

Apache HarmonyのJSSEはjre/lib/boot/x-net{.jar,-src.jar}にある org.apache.harmony.xnet.provider.jsse パッケージがそれに当たります。 x-net.jar自体はコード署名されてないようなので、 CipherSuiteを追加し放題で x-net.jarに入れ替えても動きそうな雰囲気です。

JSSEプロバイダの定義はJSSEProvider.javaにあります。 コメントのところに割と詳しい説明があって以下のようなものが書かれています。

  • サポートしているCipherSuites:別表
  • 使用する共通鍵暗号アルゴリズム:IDEA,RC2,RC4,DES,3DES
  • 使用するMacアルゴリズム:MD5, SHA-1
  • 使用する鍵交換アルゴリズム: RSA, DH, DHE
Apache Harmony 6.0 build 991881のHarmonyJSSEプロバイダーで提供されているアルゴリズムとその値の一覧は以下の通りのようです。
SSLContext = TLS(=TLSv1)
KeyManagementFactory = X509
TrustManagementFactory = X509
HarmonyJSSEがサポートしているCipherSuiteの一覧は以下の通りです。
TLS_NULL_WITH_NULL_NULL
TLS_RSA_WITH_NULL_MD5
TLS_RSA_WITH_NULL_SHA
TLS_RSA_EXPORT_WITH_RC4_40_MD5
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
TLS_RSA_WITH_IDEA_CBC_SHA
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_DH_DSS_WITH_DES_CBC_SHA
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_DH_RSA_WITH_DES_CBC_SHA
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_DHE_RSA_WITH_DES_CBC_SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5
TLS_DH_anon_WITH_RC4_128_MD5
TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA
TLS_DH_anon_WITH_DES_CBC_SHA
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA
そして、そのうちデフォルトの設定で提供するCipherSuiteは以下の通りです。
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
TLS_DHE_RSA_WITH_DES_CBC_SHA
TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_RSA_EXPORT_WITH_RC4_40_MD5
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
今晩はこんなところで、、、
ではでは