Java keytool Tomcat https 双向认证 支持android bks
此方法是在一个地方找的,具体是哪个地方有点就远了,我自己经过验证,发现没有问题,正常使用。就贴出来方法的总结和相关问题记录。
基于java的https双向认证,android上亦可用
概述:
客户端,浏览器或者使用http协议和服务器通信的程序。
如:
客户端通过浏览器访问某一网站时,如果该网站为HTTPS网站,浏览器会自动检测系统中是否存在该网站的信任证书,
如果没有信任证书,浏览器一般会拒绝访问,IE会有一个继续访问的链接,但地址栏是红色,给予用户警示作用,
即客户端验证服务端并不是强制性的,可以没有服务端的信任证书,当然是否继续访问完全取决于用户自己。
如果要去除地址栏的红色警告,需要导入服务端提供的证书到浏览器中。
服务器端,使用http协议提供服务的程序。
服务端需要获取到客户端通过浏览器发送过来的认证证书,
如:
该证书在服务端的证书库中已存在,仅仅是个匹配过程,匹配成功即通过认证,可继续访问网站资源,反之则无法显示网页。
基本逻辑:
1、生成服务端密钥库并导出证书.
2、生成客户端密钥库并导出证书.
3、根据服务端密钥库生成客户端信任的证书.
4、将客户端证书导入服务端密钥库.
5、将服务端证书导入浏览器.
生成密钥库和证书:
因使用java环境,下面使用jdk下面的keytool工具来生成相应的密钥库和证书
下面的命令是在windows 7 下面测试通过的,可以直接复制使用
1、创建目录,如d:\zmj\
2、使用资源管理进入d:\zmj\,按住shift+右键,弹出菜单,选择"在此处打开命令行".
3、服务器端相关操作
3.1、生成服务器证书库
keytool -validity 36500 -genkey -v -alias server -keyalg RSA -keystore server.keystore -dname "CN=jj.com,OU=mm,O=jj.com,L=ShenZhen,ST=GuangDong,c=cn" -storepass testpassword -keypass testpassword
注: 服务器证书库参数“CN”必须与服务端的IP地址相同,或者使用域名,否则会报错,客户端的任意。
3.2、从服务器证书库中导出服务器证书
keytool -export -v -alias server -keystore server.keystore -storepass testpassword -rfc -file server.cer
3.3、生成客户端信任证书库(由服务端证书生成的证书库,客户端使用此证书验证服务端来源可靠)
keytool -import -v -alias server -file server.cer -keystore client.truststore -storepass testpassword -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
注:-storetype BKS 是生成android上面可以识别的格式,如果不指定jdk默认生成的格式是JKS.
-provider org.bouncycastle.jce.provider.BouncyCastleProvider,需要下载jar包bcprov-jdk16-1.46.jar放到jdk1.7.0_65\jre\lib\ext\目录下.
注意需要jdk16,其他的版本android下面有版本不匹配的问题.
4、客户端相关操作
4.1、生成客户端证书库
keytool -validity 36500 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore client.p12 -dname "CN=jjclient,OU=jj,O=jj,L=ShenZhen,ST=GuangDong,c=cn" -storepass testpassword -keypass testpassword
4.2、从客户端证书库中导出客户端证书
keytool -export -v -alias client -keystore client.p12 -storetype PKCS12 -storepass testpassword -rfc -file client.cer
4.3、将客户端证书导入到服务器证书库(使得服务器信任客户端证书,服务器端用此验证客户端的合法性)
keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass testpassword
4.4、查看服务端证书中信任的客户端证书
keytool -list -keystore server.keystore -storepass testpassword
//*******可忽略*********
5、电脑浏览器客户端相关操作
5.1、生成客户端证书库
keytool -genkey -v -alias ubuntu14 -keyalg RSA -storetype PKCS12 -keystore E:\ubuntu14.p12 -validity 36500
5.2、从客户端证书库中导出客户端证书
keytool -export -alias ubuntu14 -keystore E:\ubuntu14.p12 -storetype PKCS12 -storepass testpassword -rfc -file E:\ubuntu14.cer
5.3、将客户端证书导入服务器证书库
keytool -import -v -alias ubuntu14client -file E:\ubuntu14.cer -keystore d:\zmj\server.keystore
5.4、查看服务器中信任的客户端证书
keytool -list -keystore D:\zmj\server.keystore
5.5、导出服务器端证书 由于是双向SSL认证,客户端也要验证服务器证书,因此,必须把服务器证书添加到浏览的“受信任的根证书颁发机构”。由于不能直接将keystore格式的证书库导入,必须先把服务器证书导出为一个单独的CER文件
keytool -keystore d:\zmj\server.keystore -export -alias server -file E:\ubuntu14server.cer
6、服务器端配置
由于使用tomcat,下面使用tomcat做为实例配置.
6.1、在tomcat安装目录下新建key目录,将上面生成的server.keystore复制过去.
6.2、编辑tomcat安装目录下的conf目录下的server.xml,如:d:\sslDemo\apache-tomcat-7.0.55\conf\server.xml
找到Connector,修改如下:
maxThreads="150"
SSLEnabled="true" scheme="https" secure="true"
keystoreFile="${catalina.base}/key/server.keystore" keystorePass="testpassword"
clientAuth="true" sslProtocol="TLS"
truststoreFile="${catalina.base}/key/server.keystore" truststorePass="testpassword"/>
注:
port配置https访问的端口
SSLEnabled="true" 开启https服务
scheme="https"
secure="true"开启服务端安全通信,客户端获取服务器端证书
keystoreFile="${catalina.base}/key/server.keystore" keystorePass="testpassword" 服务器证书库
clientAuth="true" 开启验证客户端
sslProtocol="TLS" 使用的协议
truststoreFile="${catalina.base}/key/server.keystore" truststorePass="testpassword" 服务器证书库(已导入客户端证书)
7、对于chrome和fireforx的“ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY”错误的解决方法
port="9443" minSpareThreads="5" maxSpareThreads="75"
enableLookups="true" disableUploadTimeout="true"
acceptCount="100" maxThreads="200"
scheme="https"
secure="true" SSLEnabled="true"
keystoreFile="/home/tomc/apache-tomcat-7.0.33/conf/server.keystore"
keystorePass="111111"
clientAuth="true"
sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"
URIEncoding="UTF-8"/>
为了方便测试android下双向认证可以用,生成证书的时候把域名换成服务器的ip地址,验证才可以通过
1、android app 代码实现
AsyncTask testTask = new AsyncTask() {
@Override
protected Object doInBackground(Object... params) {
try {
HttpClient httpsClient = AppSslApplication.getHttpsClient(MainActivity.this.getBaseContext());
HttpGet httpget = new HttpGet(HTTPS_URL);
HttpResponse response = httpsClient.execute(httpget);
HttpEntity entity = response.getEntity();
Log.e("Response status", response.getStatusLine().toString());
if (entity != null) {
Log.e("Response", "Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
String text;
while ((text = bufferedReader.readLine()) != null) {
Log.e("Response status", text);
}
bufferedReader.close();
}
httpsClient.getConnectionManager().shutdown();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
testTask.execute();
public class HttpClientSslHelper {
private static final String KEY_STORE_TYPE_BKS = "bks";
private static final String KEY_STORE_TYPE_P12 = "PKCS12";
private static final String SCHEME_HTTPS = "https";
private static final int HTTPS_PORT = 8444;
private static final String KEY_STORE_CLIENT_PATH = "client.p12";
private static final String KEY_STORE_TRUST_PATH = "client.truststore";
private static final String KEY_STORE_PASSWORD = "testpassword";
private static final String KEY_STORE_TRUST_PASSWORD = "testpassword";
private static KeyStore keyStore;
private static KeyStore trustStore;
public static HttpClient getSslHttpClient(Context pContext) {
HttpClient httpsClient = new DefaultHttpClient();
try {
// 服务器端需要验证的客户端证书
keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
// 客户端信任的服务器端证书
trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
InputStream ksIn = pContext.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
InputStream tsIn = pContext.getResources().getAssets().open(KEY_STORE_TRUST_PATH);
try {
keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ksIn.close();
} catch (Exception ignore) {
}
try {
tsIn.close();
} catch (Exception ignore) {
}
}
SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
Scheme sch = new Scheme(SCHEME_HTTPS, socketFactory, HTTPS_PORT);
httpsClient.getConnectionManager().getSchemeRegistry().register(sch);
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return httpsClient;
}
}
2、android浏览器实现
1.先把你的CA证书拷贝到你的SD卡里面
2.进入手机的"设置"->"位置和安全",最下面有个"从SD卡安装",就是安装证书的。
---------暂时没有实现
来源: http://lib.csdn.net/article/java/39137