The primary responsibility of the KeyManager is to select the authentication credentials that will eventually be sent to the remote host. To authenticate yourself (a local secure socket peer) to a remote peer, you need to initialize an SSLContext object with one or moreKeyManagers. You need to pass one KeyManager for each different authentication mechanism that will be supported. If null is passed into theSSLContext initialization, an empty KeyManager will be created. If the internal default context is used (e.g. a SSLContext created bySSLSocketFactory.getDefault() or SSLServerSocketFactory.getDefault()), a default KeyManager is created. Typically, there is a single key manager that supports authentication based on X.509 public key certificates. Some secure socket implementations may also support authentication based on shared secret keys, Kerberos, or other mechanisms.
KeyManager接口
KeyManager接口的主要职责是选择一个最终会发送到远端服务器的认证证书。为了向一个远端认证自身(安全套接字本地端),需要初始化一个包含一个到多个KeyManager的SSLContext对象;需要为每一种支持的认证机制提供一个KeyManager。
一般的,仅会有一个支持基于X.509(数字证书标准)公钥认证的KeyManager。
比较:
TrustManager:决定对端的认证证书是否被信任
KeyManager:决定将哪一个认证证书发送给对端服务器
二.结合实际应用:
SSLContext ctx = SSLContext.getInstance("SSL");
//Implementation of a trust manager for X509 certificates
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType)
throws java.security.cert.CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(ctx);
httpclient = HttpClients.custom()
.setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.setSSLSocketFactory(ssf).build();
// 自定义获取TrustManager
String password = "123456";
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
KeyStore tsstore = KeyStore.getInstance("JKS");
tsstore.load(new FileInputStream(new File("server.jks")), password.toCharArray());
trustFactory.init(tsstore);
TrustManager[] trustManagers = trustFactory.getTrustManagers();
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(new File("client.p12")), null);
keyFactory.init(keystore, null);
java.security.UnrecoverableKeyException: Get Key failed: / by zero
也试过设置密码为空字符串 但是在load这一步就报异常了。
所以使用openssl命令重新生成了一份.p12文件,然后加载成功了。
openssl pkcs12 -export -out client.p12 -in clent.pem -inkey client.key.pem
还有另外一种方式
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream(new File("client.jks")), null);
keyFactory.init(keystore, null);
//自定义获取KeyMananger
String password = "123456";
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream(new File("client.jks"))), password.toCharArray());
keyFactory.init(keystore, password.toCharArray());
KeyManager[] keyManagers = keyFactory.getKeyManagers();
ctx.init(keyManagers, new TrustManager[]{tm}, null);
SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(ctx);
httpclient = new DefaultHttpClient();
SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
socketFactory.setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
//通过SchemeRegistry将SSLSocketFactory注册到我们的HttpClient上
httpclient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", socketFactory, Integer.parseInt(DiamondUtil.getOperatorConfigData(sellerCode, "PORT"))));
到此为止 核心的部分就已经完成。