【Java】Java で、SSL通信を行うには

準備

 * 証明書作成は、以下の関連記事を参照のこと
http://blogs.yahoo.co.jp/dk521123/33788938.html

サンプル

http://blogs.yahoo.co.jp/dk521123/33075148.html
をベースに修正した。

サーバ側

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;

public class SampleSslSoketServer {
     public static void main(String[] args) throws IOException {
          SSLServerSocket serverSocket = null;
          Socket clientSocket = null;
          BufferedReader bufferedReader = null;
          PrintStream printStream = null;

          try {
               System.out.println("Running");

               System.setProperty("javax.net.ssl.keyStore", "keys/serverKeystore.jks");
               System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
               System.setProperty("javax.net.ssl.trustStore", "keys/clientTruststore.jks");
               System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

               SSLServerSocketFactory factory =
                         (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
               System.out.println("factory created");
               
               // ポート7443番を開く
               serverSocket = (SSLServerSocket) factory.createServerSocket(7443);
               System.out.println("server socket created");

               serverSocket.setNeedClientAuth(true);

               System.out.println("ServerSocket accepting");

               while (true) {
                    clientSocket = serverSocket.accept();
                    System.out.println("ServerSocket accepted");

                    bufferedReader =
                              new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    System.out.println("Processing.");
                    printStream = new PrintStream(clientSocket.getOutputStream());
                    System.out.println("Processing..");

                    String result;
                    result = bufferedReader.readLine();
                    System.out.println("Processing...");
                    if (result != null) {
                         // とりあえず、コンソール画面に吐き出してみる
                         System.out.println("Received " + result);
                         printStream.println("Hellow World " + result + "!!");
                    }
               }
          } catch (IOException ex) {
               ex.printStackTrace();
          } finally {
               if (clientSocket != null) {
                    clientSocket.close();
               }
               if (printStream != null) {
                    printStream.close();
               }
               if (bufferedReader != null) {
                    bufferedReader.close();
               }
               if (serverSocket != null) {
                    serverSocket.close();
               }
          }
     }
}

クライアント側

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class SampleSslSoketClient implements HandshakeCompletedListener {
     public static void main(String[] args) throws IOException {
          Socket socket = null;
          DataOutputStream dataOutputStream = null;
          BufferedReader bufferedReader = null;

          try {
               System.setProperty("javax.net.ssl.keyStore", "keys/clientKeystore.jks");
               System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
               System.setProperty("javax.net.ssl.trustStore", "keys/serverTruststore.jks");
               System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

               SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
               System.out.println("factory created");

               // ポート7443番を開く
               socket = factory.createSocket("localhost", 7443);
               ((SSLSocket) socket).addHandshakeCompletedListener(new SampleSslSoketClient());
               System.out.println("socket created");

               dataOutputStream = new DataOutputStream(socket.getOutputStream());
               bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

               if (socket != null && dataOutputStream != null && bufferedReader != null) {
                    String inputData = null;
                    if (args != null && args.length > 0) {
                         inputData = args[0] + "\n";
                    } else {
                         inputData = "Mike\n";
                    }
                    dataOutputStream.writeBytes(inputData);

                    // サーバーからのメッセージを受け取り画面に表示します
                    String responseLine;
                    if ((responseLine = bufferedReader.readLine()) != null) {
                         System.out.println("From Server: " + responseLine);
                    }
               }
          } catch (UnknownHostException ex) {
               ex.printStackTrace();
          } catch (IOException ex) {
               ex.printStackTrace();
          } finally {
               if (dataOutputStream != null) {
                    dataOutputStream.close();
               }
               if (bufferedReader != null) {
                    bufferedReader.close();
               }
               if (socket != null) {
                    socket.close();
               }
          }
     }

     @Override
     public void handshakeCompleted(HandshakeCompletedEvent event) {
          System.out.println("handshake completed");

          try {
               System.out.println("getCipherSuite: " + event.getCipherSuite());

               SSLSession session = event.getSession();
               System.out.println("getProtocol: " + session.getProtocol());
               System.out.println("getPeerHost: " + session.getPeerHost());

               java.security.cert.Certificate[] certs = event.getPeerCertificates();
               for (int i = 0; i < certs.length; i++) {
                    if (!(certs[i] instanceof java.security.cert.X509Certificate))
                         continue;
                    java.security.cert.X509Certificate cert =
                              (java.security.cert.X509Certificate) certs[i];
                    System.out.println("Cert #" + i + ": " + cert.getSubjectDN().getName());
               }
          } catch (Exception ex) {
               ex.printStackTrace();
          }
     }
}

出力結果

サーバ側の実行結果

Running
factory created
server socket created
ServerSocket accepting

・・・クライアント実行後・・・

Processing.
Processing..
Processing...
Received Mike

クライアント側の実行結果

factory created
socket created
handshake completed
getCipherSuite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA
From Server: Hellow World Mike!!
getProtocol: TLSv1
getPeerHost: localhost
Cert #0: CN=Sample echo server, OU=Tech, O=Kobu.Com, L=Unknown, ST=Unknown, C=Unknown

参考文献

 * 以下のサンプルは、証明書を含めて、非常に役立った
 * 鍵が上手く作れないかなっと思ったら、以下のサイトからダウンロードして一度組み込んでみるのも手。
http://www.kobu.com/java/ssl/index.htm
 * その他のサンプル
http://mezasefi.com/d/ja/blogs/nobu/2010-06-23-108.html
http://omiya6048.hatenablog.com/entry/2013/05/31/210000
http://d.hatena.ne.jp/hydrocul/20120128/1327754329
 * 図付きで分かりやすい
http://maplesystems.co.jp/blog/all/programming/7056.html

関連記事

JavaSSLのトラストストア / キーストアのパスを変更するには...

https://blogs.yahoo.co.jp/dk521123/37239270.html

Javaアプリにおける SSL通信時のデバッグ方法

http://blogs.yahoo.co.jp/dk521123/35261371.html

SSL通信について

http://blogs.yahoo.co.jp/dk521123/33100623.html

Java で、SSL通信を行うには

http://blogs.yahoo.co.jp/dk521123/33122920.html

ノンブロッキングチャネル ~SocketChannel / ServerSocketChannel~

http://blogs.yahoo.co.jp/dk521123/35067257.html

自前認証局(オレオレ証明書) のSSLサーバに接続するには...

http://blogs.yahoo.co.jp/dk521123/35032522.html

「AxisFault: Connection has been shutdown: javax.net.ssl.SSLHandshakeException」が表示

http://blogs.yahoo.co.jp/dk521123/33014445.html

System.getProperty("javax.net.ssl.trustStore" ) など で null が返ってくる

http://blogs.yahoo.co.jp/dk521123/33978118.html

Webサービス / Metro [8] ~ SSL通信を行う (2) / クライアントサイド ~

http://blogs.yahoo.co.jp/dk521123/36528991.html