JAVAのプログラムから、信頼できないサーバに接続すると、java 1.4(10年前)のころに比べるとやけに厳しくなっているのか、以下のようなエラーが発生する。


javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed\
: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to \
requested target

これは、javaのランタイムが、PKI(Public Key Infrastructure)に基づいて「私である」という証明書の検査を厳しくするようになっているからである。年額10万円程度で公式のSSL証明書を申請することができるけれども、これはユーザが直接利用するソケットではないので仲間内だけが通信できたほうがいい場合や、テスト時には、いちいちこういうものを購入するわけにはいかない。テスト用の仮想マシーンなどはたくさん作成するわけだし。

これはjsseに対して、この相手を信用してね、ということを設定すればいいだけである。ブラウザでhttpsサイトに行って、例外を認めるという操作をするようなものである。JAVAの場合、人間がそこにいないこともあるので、あらかじめ信用してね、ということが設定できるのである。

どこに、というと、一般的には、${JAVA_HOME}/jre/lib/security/jssecacertsである。

$ keytool -list -keystore jssecacerts 
キーストアのパスワードを入力してください:  

キーストアのタイプ: JKS
キーストアのプロバイダ: SUN

キーストアには 2 エントリが含まれます。

melangeca, 2011/04/22, trustedCertEntry,
証明書のフィンガープリント (MD5): 5B:15:D9:49:56:0F:E3:6D:3C:E7:35:6C:39:12:C1:FC
miles, 2011/04/22, trustedCertEntry,
証明書のフィンガープリント (MD5): 63:81:36:1B:C0:B2:02:31:A2:14:31:D2:A8:2F:99:E2

のようなものが入っている。

手動でここいらへんのファイルを強化していけばいいのであるが、sunのおすすめの手抜き方式は、
InstallCert.javaなるファイルをコンパイルして、これの引数として、SSLのサーバのホストを与え、
そのうまくいかなかった証明書をカレントディレクトリのjssecacertsファイルとして書いてしまおうというものである。相手はどの証明書を使っていますかなどのフォーマルの電話連絡やメールはいっさいなしにプロトコル上その証明書は流れているはずだから、取得できるはずという、横着な方法である。

そのInstallCertはここにあり’、これをコンパイルすること。

初めに動かすとエラーになるが、どの証明書を信用するかという質問がくる。

java InstallCert jazz.ocn2.melange.co.jp
Loading KeyStore jssecacerts...
Opening connection to jazz.ocn2.melange.co.jp:443...
Starting SSL handshake...

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1665)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:258)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:252)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1165)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:610)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:546)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:913)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1185)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1169)
	at InstallCert.main(InstallCert.java:87)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
	at sun.security.validator.Validator.validate(Validator.java:235)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
	at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:182)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1157)
	... 8 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
	... 14 more

Server sent 1 certificate(s):

 1 Subject CN=miles.ocn2.melange.co.jp, L=melange, O=co, C=JP
   Issuer  OU=MelangeSoft CA, OU=PC-Club, O=Melange Corporation, C=JP
   sha1    49 8d 57 56 ba 0b 75 0a 95 79 e4 df 07 0e 9f a8 ee ec e5 35 
   md5     63 81 36 1b c0 b2 02 31 a2 14 31 d2 a8 2f 99 e2 

Enter certificate to add to trusted keystore or 'q' to quit: [1]


<strong>そこで1番を選択する。

1</strong>

[
[
  Version: V1
  Subject: CN=miles.ocn2.melange.co.jp, L=melange, O=co, C=JP
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 143812769959076782104656775176880626902697441467038489410703681447414398727243209697477277552696548113569603594913472682710976515557635147675336938514594644654026339319258371678929020041055685946902302929321414831335104951318384630872234367960536397182195912662815535698148621063310287992669082797076320280453
  public exponent: 65537
  Validity: [From: Thu Nov 19 16:03:46 JST 2009,
               To: Sun Nov 17 16:03:46 JST 2019]
  Issuer: OU=MelangeSoft CA, OU=PC-Club, O=Melange Corporation, C=JP
  SerialNumber: [    82]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 18 41 F2 08 69 B3 90 F1   EA 39 95 75 BA BC 57 7C  .A..i....9.u..W.
0010: 66 85 D2 AB 23 28 8E A1   C0 38 2D 7D 72 43 B6 19  f...#(...8-.rC..
0020: 9C 5F 5C B3 78 22 57 35   E1 FD 7F 68 CA 5E 2D B6  ._\.x"W5...h.^-.
0030: 6D 78 01 D9 52 97 3A 9A   FB 87 6A 3A 90 FB 0F AD  mx..R.:...j:....
0040: F3 E2 02 B3 F7 F4 27 53   5B E7 94 8D B1 84 F1 39  ......'S[......9
0050: EB AE 76 DE C9 11 AB 09   BF 1B DC 1B CA B4 47 23  ..v...........G#
0060: D7 C7 AE 63 97 BB 83 7E   10 6A BA 14 E8 94 CA 71  ...c.....j.....q
0070: DC 76 6A 34 43 B1 67 FE   C7 CC B4 3E 1E 9A 38 53  .vj4C.g....>..8S

]

Added certificate to keystore 'jssecacerts' using alias 'jazz.ocn2.melange.co.jp-1'

そして、これで作成されたjssecacertsというファイルを${JAVA_HOME}/jre/lib/securityというディレクトリにコピーする。(今回のプロジェクトはローカルにjava環境を持っているのである)。

これでOKのはず。
しかーし、これはセルフサインの場合(これが多いだろうが)にしか役にたたないものであった。くやしい。

したがって、CAにあたるファイルをroot.caとすると、

$ keytool -importcert -v -trustcacerts -file rootca.cer -keystore ~/java/jre/lib/security/jssecacerts
キーストアのパスワードを入力してください:  changeit

所有者: OU=MelangeSoft CA, OU=PC-Club, O=Melange Corporation, C=JP
発行者: OU=MelangeSoft CA, OU=PC-Club, O=Melange Corporation, C=JP
シリアル番号: 0
有効期間の開始日: Thu Aug 07 17:28:43 JST 2003 終了日: Sun Aug 04 17:28:43 JST 2013
証明書のフィンガープリント:
         MD5:  40:4C:D9:8C:2D:03:E5:AB:5D:AE:53:42:AE:76:E3:5A
         SHA1: 6D:28:00:B6:DD:2E:6D:B6:C1:54:14:59:1B:FF:85:AB:49:37:9F:A3
         署名アルゴリズム名: SHA1withRSA
         バージョン: 3

拡張: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: AC D9 DD CD F9 EF 64 0C   A3 02 2D 7F 7D 1E DF 7F  ......d...-.....
0010: FD F4 CB 6E                                        ...n
]
]

#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

#3: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: AC D9 DD CD F9 EF 64 0C   A3 02 2D 7F 7D 1E DF 7F  ......d...-.....
0010: FD F4 CB 6E                                        ...n
]

[OU=MelangeSoft CA, OU=PC-Club, O=Melange Corporation, C=JP]
SerialNumber: [    00]
]

この証明書を信頼しますか? [no]:  yes
yes
証明書がキーストアに追加されました。
[/home/ferry/java/jre/lib/security/jssecacerts を格納中]


としてOKになったのであった、
最初から,-importcertでいけばよかった!!
sun microさん(現在はOracleさん)、それでもいいプログラムだと思いますよ。