HTTPS通信にはまる

HTTPS通信で、サーバーに接続するクライアントアプリケーションを開発しているのですが、久々にはまりました。(というか、ただの勉強不足でした。)

当初、HTTP通信に毛が生えた程度だろうと思っていて、以下のコードを実装しましたが、全く受け付けず・・・。
 ①keytoolを用いて、テスト用証明書をクライアントにストア
 ②以下のソースを実装 → Connectionが取得できない。

  	PrintWriter out = null;
	HttpsURLConnection con = null;
	Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
	System.getProperties().put("java.protocol.handler.pkgs",
			"com.sun.net.ssl.internal.www.protocol");
	try {
		// URLオブジェクト生成
		URL server = new URL("https://localhost:3000");
		// コネクション生成
		con = (HttpsURLConnection) server.openConnection();
		// 出力を行うように設定します
		con.setDoOutput(true);
		// 出力ストリームを取得
		out = new PrintWriter(con.getOutputStream());
		out.print(aData);
		out.close();
	} catch (Exception e) {
		throw e;
	} finally {
		if (out != null){
		out.close();
	}
   ・・・(取得部分は省略)・・・

↑こんなんではだめだったみたいで、ソケット通信しないと駄目っぽいです。
(↓改良版 かなり荒れてますが笑)

SSLSocket socket = null;
try {
	SocketFactory factory = javax.net.ssl.SSLSocketFactory.getDefault();
	socket = (SSLSocket)factory.createSocket("localhost",3000);
} catch (Exception e) {
	e.printStackTrace();
}
//ハンドシェイク
try {
	socket.startHandshake();
} catch (Exception e) {
	e.printStackTrace();
}
PrintWriter socketOut = null;
if (socket.isConnected()) {
	socket.setSoTimeout(300000);
	socketOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
	socketOut.print("POST " + aUrl + " HTTP/1.0\r\n");
	socketOut.print("Content-Length:" + aData.length() + "\r\n");
	socketOut.print("\r\n");
	socketOut.print("\r\n");
	socketOut.print(aData);
	socketOut.print("\r\n");
	socketOut.print("\r\n");
	socketOut.flush();
	if (socketOut.checkError()) {
		throw new IOException();
	} else {
		 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		 String inputLine;
		 StringBuffer buf = new StringBuffer();
		 while*1 != null) {
		 	System.out.println(inputLine);
		 }
	}
}

サーバー証明書をkeytoolを用いて、クライアント側にインストールすることがめんどくさいんで、強制的に認証するように組みました。さらに、ソケット通信でなくて、HttpsURLConnectionクラスを使いました。

	PrintWriter out = null;
	// URLオブジェクト生成
	URL server = new URL(aUrl);
	// コネクション生成
	SSLSocketFactory sslsf = null;
	KeyManager km = null;
	//	サーバーの証明書を強制的に認証させる
	TrustManager tm = { new X509TrustManager() {
		public X509Certificate getAcceptedIssuers() {
			return null;
		}

		public void checkClientTrusted(X509Certificate chain,
				String authType) {
		}

		public void checkServerTrusted(X509Certificate[] chain,
				String authType) {
		}
		} };
		// ソケットプロトコルを実装するSSLContextを作成

	try {
		SSLContext sslContext = SSLContext.getInstance("SSL");
		// SSLContextを初期化
		sslContext.init(km, tm, new SecureRandom());
		//	SSLContextのSocketFactoryを取得
		sslsf = sslContext.getSocketFactory();
	} catch (KeyManagementException e2) {
		// TODO 自動生成された catch ブロック
		e2.printStackTrace();
		throw e2;
	} catch (NoSuchAlgorithmException e2) {
		// TODO 自動生成された catch ブロック
		e2.printStackTrace();
		throw e2;
	}

	//	URLConnectionにSocketFactoryをセット
	HttpsURLConnection hCon = (HttpsURLConnection) server
				.openConnection();
	*2;
	hCon.setDoOutput(true);
	//	ホスト名を無視させる
	HostnameVerifier hv = new HostnameVerifier() {
		public boolean verify(String hostName, SSLSession session) {
			return true;
		}
	};
	*3;
		out.print(aData);
		out.close();
	} catch (MalformedURLException e) {
		throw e;
	} catch (IOException e1) {
		throw e1;
	} finally {
		if (out != null) {
			out.close();
		}
	}
	// 受信処理は省略

*1:inputLine =in.readLine(

*2:HttpsURLConnection) hCon).setSSLSocketFactory(sslsf); //hCon.setSSLSocketFactory((SSLSocketFactory)javax.net.ssl.SSLSocketFactory.getDefault(

*3:HttpsURLConnection) hCon).setHostnameVerifier(hv); try { // 出力ストリームを取得 out = new PrintWriter(hCon.getOutputStream(