1. กำหนดผ่าน SystemProperty โดย ทาง commandline
-Djavax.net.ssl.keyStore=keystoreSrv
หรือ set ใน program
System.setProperty("javax.net.ssl.keyStore", "keystoreSrv");
2. กำหนดใน JAVA_HOME/lib/security/jssecacerts หรือ JAVA_HOME/lib/security/cacerts
สร้าง SSLSocket ได้ดังนี้
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
หากโชคดี connect ได้พอดีกับ ตอนที่ GetDefault ของ SSLContext ที่อ่านข้อมูลจาก SystemProperty ได้ทัน ก็ Run ได้ผ่านไม่มีปัญหา ซึ่งกรณีที่ทำ 1 connection จะไม่เจอปัญหานี้ (เหมือนกับตัวอย่าง code ที่เคยเขียนไว้)
แต่วิธีที่กล่าวมานั้น ไม่สามารถใช้ได้ในกรณีที่ทำ multiple TLS/SSL connections รวมกับ การ create Multi-Thread ไว้รอรับ connections เพราะเวลาสั่ง getDefault() ของ SSLContext เพื่อสร้าง SSLSocket หรือ SSLServerSocket แล้ว มักจะเจอ error เช่น
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
หรืออาจจะเป็น error อื่น ๆ เช่น certificate error, หา certificate ไม่เจอ ฯลฯ
ทั้ง ๆ ที่เราก็ set ค่า keyStore กับ trustStore ผ่าน SystemProperty ไปแล้ว
วิธีแก้ไขคือ
ให้สร้าง SSLContext ขึ้นมาเอง ดังนี้
public SSLContext createSSLContext(int type) {
//------------
char[] password;
SSLContext ctx = null;
InputStream in = null;
KeyStore ks = null;
KeyManagerFactory kmf = null;
TrustManagerFactory tmf = null;
try {
kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
if (type == KEYSTORE) { // for authen incoming connection
ks = KeyStore.getInstance(KeyStore.getDefaultType());
password = "123456".toCharArray();
in = (new FileInputStream("keystoreSrv"));
ks.load(in, password);
kmf.init(ks, password);
} else { // for connect another to authen
ks = KeyStore.getInstance(KeyStore.getDefaultType());
//password = "123456".toCharArray();
in = (new FileInputStream("truststoreCli"));
ks.load(in, null);
kmf.init(ks, null);
}
in.close();
tmf.init(ks);
ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
e.printStackTrace();
}
return ctx;
}
จากนั้นเราก็นำ ctx นี่แหละไปสร้าง SSLSocket หรือ SSLServerSocket ดังนี้
SSLServerSocketFactory sslserversocketfactory = ctx.getServerSocketFactory();
SSLSocketFactory sslsocketfactory = ctx.getSocketFactory();
เท่านี้ก็จะไม่เจอ Error ดังกล่าวแล้วครับ