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

实现https双向认证,并去除commonName的校验

2015-12-03 15:59 1116 查看
最近在做一个https双向认证的工作,领导先让我实现,我之前写了一篇文章,把tomcat的生成证书和配置的实现写了出来。

现在领导给了我服务器的CA证书的客户端证书和私钥,服务端信任证书,分别是crt和pem格式的文件,

试了很多方法,才把这个搞通,由于不同的平台,证书格式和版本差异很大,包括文本证书和二进制证书文件。

通过openSSL 很容易把证书转换出来,现有Linux主机,安装了openssl,

证书文件:client.crt ,server.crt ,client.pem

openssl pkcs12 -export -in client.crt -out client.pfx -inkey client.pem -passin pass:123456

生成的pfx格式的证书,可以安装在windows系统中,可以通过浏览器访问,

程序中由于双向认证,需要信任服务端证书,

把server.crt转换为keystore格式

keytool -importkeystore -v -srckeystore client.pfx -srcstoretype pkcs12 -srcstorepass 123456 -destkeystore client.keystore -deststoretype jks -deststorepass 123456

keytool -import -alias ca -trustcacerts -file server.crt -keystore client.keystore

把keystore设成客户端信任证书即可实现双向认证。

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
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.SSLException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.security.cert.X509Certificate;

import junit.framework.TestCase;

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.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.junit.Before;
import org.junit.Test;
@SuppressWarnings("deprecation")
public class HttpsClient extends TestCase {
private String httpUrl = "https://127.0.0.1:443/TESTl/startupServlet";
// 客户端密钥库
private String sslKeyStorePath;
private String sslKeyStorePassword;
private String sslKeyStoreType;
// 客户端信任的证书
private String sslTrustStore;
private String sslTrustStorePassword;

@Before
public void setUp() {
sslKeyStorePath = "client.pfx";
sslKeyStorePassword = "123456";
sslKeyStoreType = "PKCS12"; // 密钥库类型,有JKS PKCS12等
sslTrustStore = "client.keystore";
sslTrustStorePassword = "123456";
System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword",
sslKeyStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
// 设置系统参数
System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
System.setProperty("javax.net.ssl.trustStorePassword",
sslTrustStorePassword);
}

@Test
public void testHttpsClient() {
SSLContext sslContext = null;
try {
KeyStore kstore = KeyStore.getInstance("PKCS12");
kstore.load(new FileInputStream(sslKeyStorePath),
sslKeyStorePassword.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance("sunx509");
keyFactory.init(kstore, sslKeyStorePassword.toCharArray());
KeyStore tstore = KeyStore.getInstance("jks");
tstore.load(new FileInputStream(sslTrustStore),
sslTrustStorePassword.toCharArray());
TrustManager[] tm;
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("sunx509");
tmf.init(tstore);
tm = tmf.getTrustManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyFactory.getKeyManagers(), tm, null);

} catch (Exception e) {
e.printStackTrace();
}
try {
X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String arg0, SSLSocket arg1) throws IOException {}
@Override
public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {}
@Override
public void verify(String arg0, X509Certificate arg1) throws SSLException {}
};
HttpClient httpClient = new DefaultHttpClient();
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext);
socketFactory.setHostnameVerifier(hostnameVerifier);
Scheme sch = new Scheme("https", 443, socketFactory);
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost httpPost = new HttpPost(httpUrl);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
//			nvps.add(new BasicNameValuePair("pageSize", "1"));
//			nvps.add(new BasicNameValuePair("name", null));
httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
String spt = System.getProperty("line.separator");
BufferedReader buffer = new BufferedReader(new InputStreamReader(
httpResponse.getEntity().getContent()));
StringBuffer stb = new StringBuffer();
String line = null;
while ((line = buffer.readLine()) != null) {
stb.append(line);
}
buffer.close();
String result = stb.toString();
System.out.println("result=" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}


中间的重写方法是由于证书中的主机名IP与实际访问的不符合,这里是去除commonName的校验。

声明:本文为原创,转载请注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: