ava SSL 證書細節
阿新 • • 發佈:2018-12-14
關於SSL這塊,網上很多,但很多都是講原理或怎麼生成證書實現簡單通訊,沒有講到實踐時的諸多細節。 SSL, 即Secure Sockets Layer 安全套接層。本文介紹SSL的一些常見問題,用的語言主要是Java。
問題1:證書生成和格式
網上搜索SSL,有很多生成證書的教程。可是會發現有的是用Java的Keytool生成的cer,有的是用openssl來生成的pem。這是為什麼呢?其實這些證書本質是一樣的,只是檔案格式不一樣。所以如果想在Java裡使用pem格式的證書,就要轉化。轉化的方式在這個問題裡已有回答:Convert a PEM-formatted String to a java.security.cert.X509Certificate
問題2:既然是加密,那麼可不可以脫離Socket存在?
可以。可以直接使用公鑰來加密資料,再用私鑰解密資料。具體方法參考:Java加密技術(八)——數字證書
問題3:單向認證,即只確認服務端是否真實可靠的話,要做什麼?以SSLSocket舉例。
如果只需要信任自己生成的證書
public class TestSSLSocketClient { private static String path = "e:\\keytool\\sslclient.keystore"; private static char[] password = "aaaaaaa".toCharArray(); /** * @param args */ public static void main(String[] args) { SSLContext context = null; try { KeyStore ts = KeyStore.getInstance("JKS"); ts.load(new FileInputStream(path), password); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ts); TrustManager [] tm = tmf.getTrustManagers(); context = SSLContext.getInstance("SSL"); context.init(null, tm, null); } catch (...... e) { //省略捕獲的異常資訊 e.printStackTrace(); } SSLSocketFactory ssf = context.getSocketFactory(); try { SSLSocket ss = (SSLSocket) ssf.createSocket("localhost", 8000); System.out.println("客戶端就緒。"); ObjectInputStream br = new ObjectInputStream(ss.getInputStream()); try { System.out.println(br.readObject()); } catch (ClassNotFoundException e) { e.printStackTrace(); } br.close(); ss.close(); System.out.println("客戶端測試ok"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
可以從程式碼看到,對於SSLContext,在做單向認證時,只需要TrustManagerFactory即可, context.init(null, tm, null); TrustManagerFactory是使用了服務端的證書的,即只使用了公鑰來加密資料。
如果只需要信任系統自帶的證書
SSLContext sslContext = SSLContext.getDefault();
- 1
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Using null here initialises the TMF with the default trust store.
tmf.init((KeyStore) null);
// Get hold of the default trust manager
X509TrustManager defaultTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTm = (X509TrustManager) tm;
break;
}
}
FileInputStream myKeys = new FileInputStream("truststore.jks");
// Do the same with your trust store this time
// Adapt how you load the keystore to your needs
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "password".toCharArray());
myKeys.close();
tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(myTrustStore);
// Get hold of the default trust manager
X509TrustManager myTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
myTm = (X509TrustManager) tm;
break;
}
}
// Wrap it in your own class.
final X509TrustManager finalDefaultTm = defaultTm;
final X509TrustManager finalMyTm = myTm;
X509TrustManager customTm = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// If you're planning to use client-cert auth,
// merge results from "defaultTm" and "myTm".
return finalDefaultTm.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
finalMyTm.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
// This will throw another CertificateException if this fails too.
finalDefaultTm.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// If you're planning to use client-cert auth,
// do the same as checking the server.
finalDefaultTm.checkClientTrusted(chain, authType);
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
問題4:可以看到SSLContext.init()的引數有KeyManager和TrustManager,它倆的差異是?
問題5:伺服器端會在連線時向客戶端傳送證書,那麼如何從程式碼上獲取?
import java.io.InputStream;
import java.io.OutputStream;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class RetrieveSSLCert {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Usage: java RetrieveSSLCert <host> <port>");
return;
}
String host = args[0];
int port = Integer.parseInt(args[1]);
// create custom trust manager to ignore trust paths
TrustManager trm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { trm }, null);
SSLSocketFactory factory =sc.getSocketFactory();
SSLSocket socket =(SSLSocket)factory.createSocket(host, port);
socket.startHandshake();
SSLSession session = socket.getSession();
java.security.cert.Certificate[] servercerts = session.getPeerCertificates();
for (int i = 0; i < servercerts.length; i++) {
System.out.print("-----BEGIN CERTIFICATE-----\n");
System.out.print(new sun.misc.BASE64Encoder().encode(servercerts[i].getEncoded()));
System.out.print("\n-----END CERTIFICATE-----\n");
}
socket.close();
}
}
--------------------- 本文來自 光子質量 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/fzl562410663/article/details/71775530?utm_source=copy