您的位置:首页 > 理论基础 > 计算机网络

tomcat https 配置 双向认证(无OpenSSL)

2014-04-09 09:20 411 查看
1. 生成证书

这里用到的文件,我们存放在D:/SSL/文件夹内,其中D:/SSL/server/内的文件是要交给服务器用的,D:/SSL/client/内的文件是要交给客户端用的。

1.1生成服务端证书

dos状态下执行命令:

keytool -genkey -v -alias tomcat -keyalg RSA -keystore C:/key_store/tomcat.keystore -dname "CN=127.0.0.1,OU=pde,O=pde,L=Peking,ST=Peking,C=CN" -validity 3650 -storepass 123456 -keypass 123456

说明:

keytool 是JDK提供的证书生成工具,所有参数的用法参见keytool –help

-genkey 创建新证书

-v 详细信息

-alias tomcat 以”tomcat”作为该证书的别名。这里可以根据需要修改

-keyalg RSA 指定算法

-keystore D:/SSL/server/tomcat.keystore 保存路径及文件名

-dname "CN=127.0.0.1,OU=pde,O=pde,L=Peking,ST=Peking,C=CN" 证书发行者身份,这里的CN要与发布后的访问域名一致。但由于我们是自己发行的证书,如果在浏览器访问,仍然会有警告提示

-validity 3650证书有效期,单位为天

-storepass pdepde 证书的存取密码

-keypass pdepde 证书的私钥

1.2 生成客户端证书

执行命令:

keytool -genkey -v -alias client -keyalg RSA -storetype PKCS12 -keystore
C:/key_store/client.p12 -dname "CN=client,OU=pde,O=pde,L=bj,ST=bj,C=CN" -validity 3650 -storepass 123456 -keypass 123456

说明:

参数说明同上。这里的-dname 证书发行者身份可以和前面不同

1.3 导出客户端证书

执行命令:

keytool -export -alias client -keystore
C:/key_store/client.p12 -storetype PKCS12 -storepass 123456 -rfc -file C:/key_store/client.cer


说明:

-export 执行导出

-file 导出文件的文件路径

1.4 把客户端证书加入服务端证书信任列表

执行命令:

keytool -import -alias client -v -file C:/key_store/client.cer -keystore
C:/key_store/tomcat.keystore -storepass 123456

说明:

参数说明同前。这里提供的密码是服务端 证书的密码。

1.5 导出服务端证书

执行命令:

keytool -export -alias tomcat -keystore
C:/key_store/tomcat.keystore -storepass 123456 -rfc -file C:/key_store/tomcat.cer

说明:

把服务端证书导出。这里提供的密码也是服务端证书的密码。

1.6 生成客户端信任列表

执行命令:

keytool -import -file C:/key_store/tomcat.cer -storepass 123456 -keystore
C:/key_store/client.truststore -alias tomcat -noprompt


说明:

让客户端信任服务端证书

因为Android能识别的keystore只能是BKS格式的,所以如果是在android中使用,需要下载BC库,如是JDK1.6则下载bcprov-jdk16-141.jar(网盘中下载),且将该文件放到%JAVA_HOME%\jre\lib\ext目录下。再将%JAVA_HOME%\jre\security\java.security中的List of providers and their preference orders,加上security.provider.8=org.bouncycastle.jce.provider.BouncyCastleProvider(注意security.provider.后面的8可以改成已有列表数字中的最大值加1)然后运行以下命令即可以生成BKS的证书库和相应的证书。

执行命令:

keytool -import -file C:/key_store/tomcat.cer -storepass 123456 -keystore C:/key_store/client.truststore
-alias tomcat -noprompt
-storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

这样,生成的keystore就是BKS格式的了。

Tomcat 5.5.34
在server.xml中,添加如下内容

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="C:/key_store/tomcat.keystore"
keystorePass="123456"
truststoreFile="C:/key_store/tomcat.keystore"
truststorePass="123456"/>

在IE中,添加证书信任:
tools-->internet options-->content-->Certificates-->Personal,选择Import,添加client.p12
tools-->internet options-->content-->Certificates-->Trusted Root Certification Authorities,选择Import,添加client.p12和tomcat.cer。

然后在浏览器中,输入https://127.0.0.1:8433就可以访问了。

在Android中访问
Android API Level 10,Platform 2.3.3

代码如下:

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;

import javax.net.ssl.SSLPeerUnverifiedException;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class HttpsTestActivity extends Activity {
private static String Tag = "https";
private static String keyPass = "123456";
private static String trustPass = "123456";
private static String protocol = "https";
private static int port = 8443;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.v(Tag, "-----------start----------------");
String s = connect("https://10.69.2.39:8443/jqplot/index.jsp");
//Log.v(Tag, "s="+s);
Log.v(Tag, "-----------end----------------");
}

public String connect(String queryUrl) {
BufferedReader in = null;
String result = null;

try {
HttpClient httpclient = new DefaultHttpClient();

KeyStore ts = KeyStore.getInstance("BKS");
KeyStore ks = KeyStore.getInstance("PKCS12");

InputStream tsStream = this.getApplicationContext().getResources().openRawResource(R.raw.client);
InputStream ksStream = this.getApplicationContext().getResources().openRawResource(R.raw.clientp12);
Log.v(Tag, "1");

try {
ts.load(tsStream, trustPass.toCharArray());
Log.v(Tag, "3");
ks.load(ksStream, keyPass.toCharArray());
}catch(Exception e){
Log.v(Tag, "6 "+e.getMessage());
}finally {
tsStream.close();
ksStream.close();
}
Log.v(Tag, "2");
// SSLSocketFactory socketFactory = new SSLSocketFactory(ts);//single way
SSLSocketFactory socketFactory = new SSLSocketFactory(ks, keyPass, ts);
Scheme sch = new Scheme(protocol, socketFactory, port);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost httpPost = null;

httpPost = new HttpPost(queryUrl);
/*
* List<NameValuePair> parameters = new ArrayList<NameValuePair>();
* parameters.add(new BasicNameValuePair("Name", "zhangsan"));
* parameters.add(new BasicNameValuePair("passWord", "123456"));
*
* UrlEncodedFormEntity formEntiry = new UrlEncodedFormEntity(
* parameters);
*
* httpPost.setEntity(formEntiry);
*/
HttpResponse httpResponse = httpclient.execute(httpPost);
in = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
result = sb.toString();

} catch (HttpHostConnectException e) {
Log.v(Tag, "Connection refused, this may cause by server is shut down");
} catch (SSLPeerUnverifiedException e) {
Log.v(Tag, "Not authenticated or wrong certificate");
} catch (Exception e) {
Log.v(Tag, "IOException or ClientProtocolException");
Log.v(Tag, "e=" + e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;

}
}


纯Java程序访问
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.KeyManagerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import javax.net.ssl.X509TrustManager;

public class Test2 {
private static String keyStore = "C:\\key_store\\ip\\client.p12"; //证书的路径
private static String trustStore = "C:\\key_store\\ip\\client.truststore";//密钥库文件,jks格式
private static String keyPass = "123456"; //证书的密码
private static String trustPass = "123456"; //密钥库的密码
private static String protocol = "https";
private static int port = 8443;

public static void main(String[] args) throws Exception {
Test2 t = new Test2();
String s = t.connect("https://10.69.2.39:8443/jqplot/index.jsp");
System.out.println(s);

System.exit(0);
}

public String connect(String queryUrl){
BufferedReader in = null;
SSLContext sslContext = null;
String result = null;

try{
sslContext = getContext();
}catch(Exception e){
System.out.println("get SSL context failed");
return null;
}

try {

HttpClient httpclient = new DefaultHttpClient();

SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext);
Scheme sch = new Scheme(protocol, port, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost httpPost = null;

httpPost = new HttpPost(queryUrl);
/*
// 创建名/值组列表
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("Name", "zhangsan"));
parameters.add(new BasicNameValuePair("passWord", "123456"));

// 创建UrlEncodedFormEntity对象
UrlEncodedFormEntity formEntiry = new UrlEncodedFormEntity(
parameters);

httpPost.setEntity(formEntiry);
*/
HttpResponse httpResponse = httpclient.execute(httpPost);
in = new BufferedReader(new InputStreamReader(httpResponse
.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
result = sb.toString();

}catch(HttpHostConnectException e){
System.out.println("Connection refused, this may cause by server is shut down");
}
catch(SSLPeerUnverifiedException e){
System.out.println("Not authenticated or wrong certificate");
}catch(Exception e){
System.out.println("IOException or ClientProtocolException");
}finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;

}

private SSLContext getContext() throws Exception{
SSLContext sslContext = null;

KeyStore ks = KeyStore.getInstance("PKCS12");
// 加载pfx文件
ks.load(new FileInputStream(keyStore), keyPass.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPass.toCharArray());

KeyStore ts = KeyStore.getInstance("JKS");
// 加载jks文件
ts.load(new FileInputStream(trustStore), trustPass.toCharArray());
TrustManager[] tm;
//System.out.println(TrustManagerFactory.getDefaultAlgorithm());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
tm = tmf.getTrustManagers();

for (int i = 0; i < tm.length; i++) {
if (tm[i] instanceof X509TrustManager) {
tm[i] = new SSLTrustManager((X509TrustManager) tm[i]);
}
}

sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), tm, null);

return sslContext;
}

}

Android无证书Https访问代码:

package ygomi.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;

public class HttpsUtils {
private X509TrustManager xtm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}

public void checkServerTrusted(X509Certificate[] chain, String authType) {
/*
System.out.println("cert: " + chain[0].toString() + ", authType: "
+ authType);
*/
}

public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
private HostnameVerifier hnv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
//System.out.println("hostname: " + hostname);
return true;
}
};

public HttpsUtils() {
SSLContext sslContext = null;

try {
sslContext = SSLContext.getInstance("TLS");
X509TrustManager[] xtmArray = new X509TrustManager[] { xtm };
sslContext.init(null, xtmArray, new java.security.SecureRandom());
} catch (GeneralSecurityException gse) {
}
if (sslContext != null) {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
}

HttpsURLConnection.setDefaultHostnameVerifier(hnv);
}

public String run(String urlPath) throws Exception{
StringBuffer sb = new StringBuffer();
URL url = null;
HttpsURLConnection urlCon = null;
BufferedReader in = null;
try {

url = new URL(urlPath);
urlCon = (HttpsURLConnection) url.openConnection();
urlCon.setReadTimeout(2000);
urlCon.setConnectTimeout(5000);
urlCon.setDoOutput(true);
urlCon.setDoInput(true);
in = new BufferedReader(new InputStreamReader(
urlCon.getInputStream()));
String line = null;
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line+NL);
}
} catch (Exception e) {
throw(e);
} finally {
if (null != in) {
try {
in.close();
in = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != urlCon) {
urlCon.disconnect();
urlCon = null;
}
}
return sb.toString();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: