原理:
个人理解:双向认证就是客户端和服务器之间互相认证,客户端拿着自己的证书和服务器的公钥证书去服务器认证,服务器拿着自己的证书和客服端公钥认证客户端。服务器私钥解密客户端拿服务器公钥加密的数据。客户端拿自己的私钥解密服务器拿客户端公钥加密的数据。
操作 :
本地需要有jdk环境和配置
1:通过jdktools生成服务器证书
创建服务器密钥,其密钥库为 d:/mykeys/server.ks,注意keypass和storepass保持一致, ?它们分别代表 密钥密码和密钥库密码,注意 CN=localhost 中,localhost表示要配置SSL的主机名,不能任意指定? 也可以不写。 ?
keytool -genkey -v -alias serverKey -dname "CN=localhost" -keyalg RSA -keypass rwm258 -keystore server.ks -storepass rwm258
生成服务器证书后tomcat或者nginx配置后就可以实现单项认证
2;导出服务器公钥证书
keytool -export -alias serverKey -file server.cer -keystore server.ks -storepass rwm258
3:创建客户端密钥,其密钥库为 d:/mykeys/client.p12,注意这个密钥库的后缀名,注意密钥库类型PKCS12
keytool -genkey -v -alias clientKey -dname "CN=SomeOne" -keyalg RSA -keypass lyl147 -keystore client.p12 -storepass lyl147 -storetype PKCS12
4:客户端密钥导出为证书文件公钥文件
keytool -export -alias clientKey -file clientKey.cer -keystore client.p12 -storepass lyl147 -storetype PKCS12
5:将上述客户端密钥文件导入服务器证书库,并设置为信任证书;注意会问你是否信任该证书,回答 y 即可
keytool -import -v -alias clientKey -file clientKey.cer -keystore server.ks -storepass rwm258
目前为止证书生成结束。。。
开始配置环境操作。。。
6:编辑tomcat配置文件server.xml
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="D:/mykeys/server.ks" keystorePass="rwm258"
truststoreFile="D:/mykeys/server.ks " truststorePass=" rwm258" />
服务器只需要配置服务器证书就行了。。。然后启动tomcat
?为了在本机浏览器中进行SSL访问,请:双击 d:/mykeys/client.p12 ,将启动证书向导
导入的文件,为私钥键入密码lyl147 ,将所有的证书放入下列存储区,然后,浏览-个人
保存证书,打开chrome浏览器设置?搜索SSL ,安全设置,管理证书中就可以看到sameone证书。
然后输入https://localhost:8443/
弹出选择证书的操作点击确定?即可
这样PC端的双向认证就完成了。。。
Android移动端认证:之前导出了服务器的公钥,,现在就用到了。。
首先Android?需要bks格式的证书这需要工具转换下,,,下载portecle
https://jaist.dl.sourceforge.net/project/portecle/v1.11/portecle-1.11.zip
然后打开工具
打开本地的客户端证书?client.p12?输入密码?lyl147
然后选择tools? --change? keystoretype --BKS? 然后保存。。输入client.bks。这样就有了生成了客户端的bks证书文件
把客户端证书client.bks?和服务器的公钥证书放入本地assets下
Android Webview?配置双向认证:
package com.collect.baselib.myUtils;
import android.annotation.TargetApi;
import android.net.Uri;
import android.os.Build;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.collect.baselib.BaseApplication;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class SslWebViewClient extends WebViewClient {
private SSLContext sslContext;
public SslWebViewClient() {
try {
TrustManager[] trustManagers = prepareTrustManager(BaseApplication.getAppContext().getResources().getAssets().open("server.cer"));
KeyManager[] keyManagers = prepareKeyManager(BaseApplication.getAppContext().getResources().getAssets().open("client.bks"), "lyl147");
sslContext = SSLContext.getInstance("TLS");
X509TrustManager trustManager = null;
if (null != trustManagers){
trustManager = new MyTrustManager(chooseTrustManager(trustManagers));
}else {
trustManager = new UnSafeTrustManager();
}
sslContext.init(keyManagers, new TrustManager[]{trustManager}, new SecureRandom());
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return processRequest(Uri.parse(url));
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return processRequest(request.getUrl());
}
private WebResourceResponse processRequest(Uri uri) {
try {
//设置连接
URL url = new URL(uri.toString());
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
//为request设置SSL Socket Factory
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
//获取请求的内容、contentType、encoding
InputStream inputStream = urlConnection.getInputStream();
String contentType = urlConnection.getContentType();
String encoding = urlConnection.getContentEncoding();
if (null != contentType){
String mimeType = contentType;
if (contentType.contains(";")){
mimeType = contentType.split(";")[0].trim();
}
//返回新的response
return new WebResourceResponse(mimeType, encoding, inputStream);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0){
return null;
}
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e){
}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null){
return null;
}
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
public static class MyTrustManager implements X509TrustManager{
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
public static class UnSafeTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
}
webview使用
his.setWebViewClient(new SslWebViewClient());
接口请求okhttp和webview需要单独设置,,很多类似代码可以参考:这里客户端和服务器的都是bks格式的,,也可以加载cer的。修改下就行了
package com.collect.baselib.myUtils;
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
/**
* @author: created by whq
* date: 2021/9/17
*/
public class SSLHelper {
private final static String CLIENT_PRI_KEY = "geren.bks";
private final static String TRUSTSTORE_PUB_KEY = "service.bks";
private final static String CLIENT_BKS_PASSWORD = "";
private final static String TRUSTSTORE_BKS_PASSWORD = "";
private final static String KEYSTORE_TYPE = "BKS";
private final static String PROTOCOL_TYPE = "TLS";
private final static String CERTIFICATE_STANDARD = "X509";
public static SSLSocketFactory getSSLCertifcation(Context context) {
SSLSocketFactory sslSocketFactory = null;
try {
// 服务器端需要验证的客户端证书,其实就是客户端的keystore
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
// 客户端信任的服务器端证书
KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);
//读取证书
InputStream ksIn = context.getAssets().open(CLIENT_PRI_KEY);
InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);
//加载证书
keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
ksIn.close();
tsIn.close();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_STANDARD);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_STANDARD);
trustManagerFactory.init(trustStore);
keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
//初始化SSLContext
SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());
sslSocketFactory = sslContext.getSocketFactory();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslSocketFactory;
}
}
然后okhttp设置:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// builder.sslSocketFactory(sslSocketFactory);
builder.sslSocketFactory(SSLHelper.getSSLCertifcation(BaseApplication.getAppContext()), new SSLHttpsUtil.UnSafeTrustManager());
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
这样接口调用也就认证成功了。。。
IOS认证可以参考??IOS之https请求认证及双向认证_gb_wxzqq的博客-CSDN博客_ios 双向认证
本文参考:
Android webview在https下实现ssl的双向认证_张zx的博客-CSDN博客
TOMCAT-SSL双向认证-配置实例_nimmy的博客-CSDN博客
tomcat实现https双向认证配置_a18792721831的博客-CSDN博客_tomcat双向认证
|