数字证书及安全加密(三)tomcat双向SSL验证及服务调用

阅读更多
本篇博文内容包括:tomcat双向SSL验证配置及使用java程序访问https服务。

系统环境:
windows+jdk1.6.0_31+tomcat6.0+httpclient4.3.1

双向SSL配置
上一篇博文中生成了客户端证书来搭建单项SSL验证,双向SSL就是服务器端也要求客户端使用受信任的证书来访问。

1.生成证书
需要生成客户端证书(含私钥)并将客户端公钥证书导入至服务端信任证书库。

    生成客户端证书
cd %JAVA_HOME%/bin
keytool -genkey -v -alias client -keyalg RSA -storetype PKCS12 -keystore D:/lib/client.p12 -storepass client

创建了别名为server的证书(pcks12类型,含密钥的用户证书交换类型),文件名为client.p12,密码为client,密钥算法为RSA。
生成时需要输入多项证书信息,因不影响本次时间测试,不在此展示。

    导出客户端证书
jdk keytool无法直接导入pcks12类型证书,需要从pcks12证书中导出cer格式证书(公钥证书,才能导入至证书库中
javakeytool -export -v -alias client -keystore D:/lib/client.p12 -storetype PKCS12 -rfc -file D:/lib/client.cer -storepass client

导出了名为client.cer的公钥证书,证书库密码为client

    导入客户端证书至服务端信任库
keytool -import -v -file D:/lib/client.cer -keystore D:/lib/servertrust.keystore -alias client -keypass client -storepass servertrust

客户端公钥证书被导入到了名为servertrust.keystore的证书库中,别名为client,证书密码为client,证书库密码为servertrust。

    查看服务端信任库
keytool -list -v -keystore D:/lib/servertrust.keystore -storepass servertrust

可以看到服务端信任库中包含客户端公钥证书
  • 您的 keystore 包含 1 输入
  • 别名名称: client
  • 创建日期: 2014-1-2
  • 输入类型: trustedCertEntry
  • 所有者:CN=client, OU=client, O=client, L=client, ST=client, C=US

2.配置tomcat
配置conf/server.xml,找到上一篇中配置的
标签,将
clientAuth="false"
修改为
clientAuth="true"
使服务端要求验证客户端证书。
在标签中加入服务端信任库属性
truststoreFile="D:/lib/servertrust.keystore" truststorePass="servertrust"

使tomcat信任servertrust.keysto中的公钥证书。

重启tomcat后,访问 https://server:8443/发现无法访问,报ssl错误,因为服务端要求客户端证书,而客户端没有对应的证书(含私钥)。

3.导入客户端证书
首先使用浏览器测试客户端证书。

    浏览器客户端导入客户端证书
双击客户端(私钥)证书D:/lib/client.p12,按提示进行操作,即可将客户端证书导入浏览器。
或:打开IE》选项》内容》证书》导入》选择证书类型p12、选择证书》输入客户端证书密码》确认,也可导入客户端证书。
导入客户端证书成功后,可以通过浏览器访问 https://server:8443/。

    java客户端导入客户端证书
通过jdk访问时报java.net.SocketException: Software caused connection abort: recv failed,也是因为客户端没有受信任的证书。java程序不会导入浏览器中的客户端证书,需要我们手工指定客户端证书。
在上一篇已将服务端公钥证书导入至jdk信任证书库中(客户端信任服务端证书)后,只需要在jvm参数中加入
-Djavax.net.ssl.keyStore=D:/lib/client.p12 -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStorePassword=client
即在java程序中使用客户端自身的证书,程序即可访问 https://server:8443/。

4.指定客户端信任库
这里配置中使用的是jdk系统默认的证书库文件,程序中也可以指定使用其他信任证书库文件。

    导入服务端证书至客户端信任库
keytool -import -v -alias server -file D:/lib/server.cer -keystore D:/lib/clienttrust.keystore -keypass server -storepass clienttrust

    查看客户端信任库
keytool -list -v -keystore D:/lib/clienttrust.keystore -storepass clienttrust

    配置客户端信任库
删除jdk默认信任证书库文件"%JAVA_HOME%\jre\lib\security\cacerts",再在jvm参数中加入
-Djavax.net.ssl.trustStore=D:/lib/clienttrust.keystore -Djavax.net.ssl.trustStorePassword=clienttrust -Djavax.net.ssl.trustStoreType=JKS
程序即可使用该jvm访问https。

web应用在服务器启动时,会自动读取jdk默认的证书库来访问https服务。

使用spring security oauth2框架,通过https协议来访问rest服务时,通过上述配置步骤可以验证通过。

5.使用HttpClient访问双向SSL服务
Test类代码如下:
		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			System.out.println("---keyStore---");
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			FileInputStream keyinstream = new FileInputStream(new File(
					"D:/lib/client.p12"));
			try {
				keyStore.load(keyinstream, "client".toCharArray());
			} finally {
				keyinstream.close();
			}
			Enumeration e = keyStore.aliases();
			while (e.hasMoreElements()) {
				System.out.println(e.nextElement());
			}
			System.out.println("---trustStore---");
			KeyStore trustStore = KeyStore.getInstance(KeyStore
					.getDefaultType());
			FileInputStream instream = new FileInputStream(new File(
					"D:/lib/clienttrust.keystore"));
			try {
				trustStore.load(instream, "clienttrust".toCharArray());
			} finally {
				instream.close();
			}
			e = trustStore.aliases();
			while (e.hasMoreElements()) {
				System.out.println(e.nextElement());
			}
			// 可以不指定trustStore,直接使用系统默认位置%JAVA_HOME%\jre\lib\security\cacerts与new
			// SSLSocketFactory(keyStore,"client")
			SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore,
					"client", trustStore);
			Scheme sch = new Scheme("https", socketFactory, 8443);
			httpclient.getConnectionManager().getSchemeRegistry().register(sch);
			HttpGet httpget = new HttpGet(
					"https://server:8443/api/rest/test?access_token=86cb4392-425a-4b30-8e31-7250661a15c4");
			System.out.println("executing request" + httpget.getRequestLine());
			HttpResponse response = httpclient.execute(httpget);
			System.out.println("-------------response-------------");
			System.out.println(response.getStatusLine());
			HttpEntity entity = response.getEntity();
			System.out.println(EntityUtils.toString(response.getEntity()));			if (entity != null) {
				entity.consumeContent();
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		httpclient.getConnectionManager().shutdown();

程序中使用client.p12作为客户端证书(含私钥,公钥证书client.cer已导入服务端信任证书库servertrust.jks),clienttrust.keystore作为客户端信任证书库(含服务端公钥证书server.cer),c/s两端服务器校验都成功后,SSL通道建立完成,即可直接发送信息。

你可能感兴趣的:(CA,SSL,spring,security,oauth,https,httpclient)