はじめに
http://blogs.yahoo.co.jp/dk521123/36516080.htmlで自前認証局(オレオレ証明書)でも何でも気にせず通すような処理をを実装したが もう少しマシな実装を考える
サンプル
* 今回は、決められた証明書以外は、エラーにするような実装を行う
準備
キーストアの作成http://blogs.yahoo.co.jp/dk521123/36518468.html
より [1] サーバ側のキーストアを作成する ~~~~ "%JAVA_HOME%\bin\keytool" -genkey -alias tomcat -keyalg RSA -keypass changeit -storepass changeit -keystore server.keystore -validity 3650 ~~~~ [2] サーバ側のキーストアに証明書署名要求(CSR)を生成 ~~~~ "%JAVA_HOME%\bin\keytool" -certreq -alias tomcat -keystore server.keystore -storepass changeit -file server.csr ~~~~ [3] サーバ側のキーストアから 証明書署名要求をエクスポートする ~~~~ "%JAVA_HOME%\bin\keytool" -export -alias tomcat -keystore server.keystore -storepass changeit -file server.cer ~~~~ [4] クライアント側のキーストアに、サーバ側の証明書署名要求をインポートする ~~~~ "%JAVA_HOME%\bin\keytool" -import -trustcacerts -alias tomcat -storepass changeit -file server.cer -keystore client.keystore ~~~~
Tomcatの設定
http://blogs.yahoo.co.jp/dk521123/36513426.html
がベース
http://blogs.yahoo.co.jp/dk521123/36513426.html
より、【server.xml】 <!-- ★ここから★ --> <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" defaultSSLHostConfigName="localhost"> <SSLHostConfig hostName="localhost"> <Certificate certificateKeystoreFile="conf/server.keystore" certificateKeystorePassword="changeit" certificateKeyAlias="tomcat" certificateKeystoreProvider="SUN" certificateKeystoreType="JKS" type="RSA" /> </SSLHostConfig> </Connector> <!-- ★ここまで★ -->
サーバ側
* 以下の関連記事を参照のことhttp://blogs.yahoo.co.jp/dk521123/36139336.html
クライアント側
http://blogs.yahoo.co.jp/dk521123/36516080.htmlがベース
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.CertificateException; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; public class Main { /** 自己署名証明書のサーバへのSSL通信かどうか. * true:自己署名証明書(オレオレ証明書)へのSSL通信、false:信頼できる認証局の証明書へのSSL通信 */ private static final boolean isSslConnectionWithSelfSignedCertificate = true; public static void main(String[] args) { System.out.println("Start!"); try { // ★SSL通信用の処理★ if (isSslConnectionWithSelfSignedCertificate) { // オレオレ証明書用処理(正規の証明書は不要) SSLContext sslContext = SSLContext.getInstance("TLS"); char[] keyPass = "changeit".toCharArray(); try (FileInputStream fileInputStream = new FileInputStream("./etc/client.keystore")) { KeyStore keyStore = creatKeyStore(fileInputStream, keyPass); KeyManager[] keyManagers = creatKeyManagers(keyStore, keyPass); TrustManager[] trustManager = creatTrustManagers(keyStore); SecureRandom secureRandom = SecureRandom.getInstanceStrong(); System.out.println("Algorithm : " + secureRandom.getAlgorithm()); sslContext.init(keyManagers, trustManager, secureRandom); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); HostnameVerifier hostnameVerifier = creatHostnameVerifier(); HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); } } URL url = new URL("https://localhost:8443/SampleWebService/services/SampleWebService.ws?wsdl"); SampleWebServiceService service = new SampleWebServiceService(url); SampleWebService proxy = service.getSampleWebServicePort(); long start = System.currentTimeMillis(); String result = proxy.sayYourAge("Ken", 11L); long end = System.currentTimeMillis(); System.out.println((end - start) + "ms"); System.out.println("Result : " + result); } catch (Exception ex) { ex.printStackTrace(); } System.out.println("Done"); } private static KeyStore creatKeyStore(InputStream inputStream, char[] trustpass) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException { KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(inputStream, trustpass); return keyStore; } private static KeyManager[] creatKeyManagers(KeyStore keyStore, char[] keyPass) throws GeneralSecurityException, IOException { String algorithm = KeyManagerFactory.getDefaultAlgorithm(); KeyManagerFactory factory = KeyManagerFactory.getInstance(algorithm); factory.init(keyStore, keyPass); return factory.getKeyManagers(); } private static TrustManager[] creatTrustManagers(KeyStore trustStore) throws NoSuchAlgorithmException, KeyStoreException { String algorithm = KeyManagerFactory.getDefaultAlgorithm(); TrustManagerFactory factory = TrustManagerFactory.getInstance(algorithm); factory.init(trustStore); return factory.getTrustManagers(); } private static HostnameVerifier creatHostnameVerifier() { return new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { System.out.println("verify " + hostname + " " + session.getPeerHost()); // "localhost"は期待するホスト名を指定 return "localhost".equals(hostname); } }; } }
出力結果
Start! Algorithm : Windows-PRNG 74ms Result : Ken's age is 11. Done参考:クライアント側のキーストアに別の証明書署名要求(CSR)をインポートした場合→例外が発生する
Start! Algorithm : Windows-PRNG javax.xml.ws.WebServiceException: 次の場所でWSDLへのアクセスに失敗しました: https://localhost:8443/SampleWebService/services/SampleWebService.ws?wsdl。次のメッセージにより失敗しました: sun.security.validator.ValidatorException: No trusted certificate found。 at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:250) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:231) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:194) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:163) at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:348) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:306) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:215) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:196) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:192) at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:99) at javax.xml.ws.Service.<init>(Service.java:77) at com.sample.webservice.client.stub.SampleWebServiceService.<init>(SampleWebServiceService.java:50) at com.sample.webservice.client.stub.Main.main(Main.java:45) ・・・略・・・ Caused by: sun.security.validator.ValidatorException: No trusted certificate found at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:384) at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:133) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351) ... 27 more
参考文献
Webサービス
http://community.giga-works.com/java/jax-ws-client-https.htmlSSL通信
http://web.plus-idea.net/2012/10/java-ssl-keystore/https://developer.android.com/training/articles/security-ssl.html
http://a4dosanddos.hatenablog.com/entry/2015/03/29/125111
https://codezine.jp/article/detail/105
TrustManager
https://kinjouj.github.io/2014/10/httpsurlconnection-trustmanager.html
JavaTM Secure Socket Extension (JSSE)
http://e-class.center.yuge.ac.jp/jdk_docs/ja/technotes/guides/security/jsse/JSSERefGuide.html
後で役に立ちそうなサイト
https://kevinlocke.name/bits/2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/関連記事
Webサービス
Webサービス / Metro [1] ~入門編 / サーバサイドの構築 ~http://blogs.yahoo.co.jp/dk521123/36139336.html
Webサービス / Metro [2] ~入門編 / クライアントサイドの構築 ~
http://blogs.yahoo.co.jp/dk521123/36140561.html
Webサービス / Metro [6] ~ 証明書未チェックでSSL通信を行う (1) / クライアントサイド ~
http://blogs.yahoo.co.jp/dk521123/36516080.html
SSL通信
Java で、SSL通信を行うにはhttp://blogs.yahoo.co.jp/dk521123/33122920.html
自前認証局(オレオレ証明書) のSSLサーバに接続するには...
http://blogs.yahoo.co.jp/dk521123/35032522.html
Javaアプリにおける SSL通信時のデバッグ方法
http://blogs.yahoo.co.jp/dk521123/35261371.html
キーストア
Javaで、キーストアファイルをロードし、一覧表示するhttps://blogs.yahoo.co.jp/dk521123/37020660.html
Keytool コマンド
http://blogs.yahoo.co.jp/dk521123/36518468.html
Ant で、Keystore ファイルを作成するには ~GenKeyタスク~
http://blogs.yahoo.co.jp/dk521123/35066497.html
SSLサイトの証明書をキーストアにインポートする
http://blogs.yahoo.co.jp/dk521123/36535856.html
SSL通信トラブル
* WebサービスにアクセスするJavaクライアントで、Exception: Broken pipeが発生するhttp://blogs.yahoo.co.jp/dk521123/36643583.html