tmb*_*gmn 212 java ssl https client-certificates
我很新HTTPS/SSL/TLS,我对使用证书进行身份验证时客户端应该提供的内容有点困惑.
我正在编写一个Java客户端,需要为POST特定的数据执行简单的数据URL.那部分工作正常,唯一的问题是应该完成它HTTPS.该HTTPS部分相当容易处理(使用HTTPclient或使用Java的内置HTTPS支持),但我仍然坚持使用客户端证书进行身份验证.我注意到这里已经有一个非常类似的问题,我还没有用我的代码试过(很快就会这么做).我当前的问题是 - 无论我做什么 - Java客户端永远不会发送证书(我可以使用PCAP转储检查).
我想知道客户端在使用证书进行身份验证时应该向服务器提供什么内容(特别是对于Java - 如果这一点很重要)?这是一个JKS文件,还是PKCS#12?什么应该在他们身上; 只是客户端证书,还是密钥?如果是这样,哪个关键?对于所有不同类型的文件,证书类型等存在相当多的混淆.
正如我之前所说,我是新手,HTTPS/SSL/TLS所以我也会欣赏一些背景信息(不必是一篇文章;我会接受好文章的链接).
tmb*_*gmn 226
最后设法解决了所有问题,所以我会回答我自己的问题.这些是我用来设置的文件/文件,以解决我的特定问题;
该客户端的密钥库是一个PKCS#12格式文件包含
为了生成它,我使用了OpenSSL的pkcs12命令,例如;
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"
Run Code Online (Sandbox Code Playgroud)
提示:确保您获得最新的OpenSSL,而不是版本0.9.8h,因为它似乎遇到了一个错误,它不允许您正确生成PKCS#12文件.
当客户端明确请求客户端进行身份验证时,Java客户端将使用此PKCS#12文件向服务器提供客户端证书.有关客户端证书身份验证协议实际工作原理的概述,请参阅维基百科有关TLS的文章(也解释了为什么我们需要客户端的私钥).
所述客户机的信任是直向前JKS格式包含该文件的根或中间CA证书.这些CA证书将确定允许您与哪些端点通信,在这种情况下,它将允许您的客户端连接到任何服务器提供由其中一个信任库CA签署的证书.
例如,要生成它,您可以使用标准的Java keytool;
keytool -genkey -dname "cn=CLIENT" -alias truststorekey -keyalg RSA -keystore ./client-truststore.jks -keypass whatever -storepass whatever
keytool -import -keystore ./client-truststore.jks -file myca.crt -alias myca
Run Code Online (Sandbox Code Playgroud)
使用此信任库,您的客户端将尝试与提供由CA标识的CA签名的证书的所有服务器进行完整的SSL握手myca.crt.
以上文件仅供客户使用.如果要设置服务器,服务器还需要自己的密钥和信任库文件.可以在本网站上找到为Java客户端和服务器(使用Tomcat)设置完整工作示例的一个很好的演练.
问题/备注/提示
-Djavax.net.debug=ssl如果您对Java SSL调试输出感到不舒服,它类似于但更结构化(可以说)更容易理解.完全可以使用Apache httpclient库.如果要使用httpclient,只需使用HTTPS等效项替换目标URL,并添加以下JVM参数(对于任何其他客户端都是相同的,无论您要使用哪个库通过HTTP/HTTPS发送/接收数据) :
-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.keyStore=client.p12
-Djavax.net.ssl.keyStorePassword=whatever
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.trustStore=client-truststore.jks
-Djavax.net.ssl.trustStorePassword=whateverRun Code Online (Sandbox Code Playgroud)Mag*_*nus 56
其他答案显示了如何全局配置客户端证书.但是,如果要以编程方式为一个特定连接定义客户端密钥,而不是在JVM上运行的每个应用程序上全局定义它,那么您可以配置自己的SSLContext,如下所示:
String keyPassphrase = "";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("cert-key-pair.pfx"), keyPassphrase.toCharArray());
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, null)
.build();
HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
HttpResponse response = httpClient.execute(new HttpGet("https://example.com"));
Run Code Online (Sandbox Code Playgroud)
mha*_*ler 30
它们JKS文件只是证书和密钥对的容器.在客户端身份验证方案中,密钥的各个部分将位于此处:
信任库和密钥库的分离不是强制性的,但建议使用.它们可以是相同的物理文件.
要设置两个存储的文件系统位置,请使用以下系统属性:
-Djavax.net.ssl.keyStore=clientsidestore.jks
Run Code Online (Sandbox Code Playgroud)
并在服务器上:
-Djavax.net.ssl.trustStore=serversidestore.jks
Run Code Online (Sandbox Code Playgroud)
要将客户端的证书(公钥)导出到文件,以便将其复制到服务器,请使用
keytool -export -alias MYKEY -file publicclientkey.cer -store clientsidestore.jks
Run Code Online (Sandbox Code Playgroud)
要将客户端的公钥导入服务器的密钥库,请使用(如提到的海报,这已由服务器管理员完成)
keytool -import -file publicclientkey.cer -store serversidestore.jks
Run Code Online (Sandbox Code Playgroud)
wil*_*oop 10
Maven pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>some.examples</groupId>
<artifactId>sslcliauth</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sslcliauth</name>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4</version>
</dependency>
</dependencies>
</project>
Run Code Online (Sandbox Code Playgroud)
Java代码:
package some.examples;
import java.io.FileInputStream;
import java.io.IOException;
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 java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.entity.InputStreamEntity;
public class SSLCliAuthExample {
private static final Logger LOG = Logger.getLogger(SSLCliAuthExample.class.getName());
private static final String CA_KEYSTORE_TYPE = KeyStore.getDefaultType(); //"JKS";
private static final String CA_KEYSTORE_PATH = "./cacert.jks";
private static final String CA_KEYSTORE_PASS = "changeit";
private static final String CLIENT_KEYSTORE_TYPE = "PKCS12";
private static final String CLIENT_KEYSTORE_PATH = "./client.p12";
private static final String CLIENT_KEYSTORE_PASS = "changeit";
public static void main(String[] args) throws Exception {
requestTimestamp();
}
public final static void requestTimestamp() throws Exception {
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(
createSslCustomContext(),
new String[]{"TLSv1"}, // Allow TLSv1 protocol only
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(csf).build()) {
HttpPost req = new HttpPost("https://changeit.com/changeit");
req.setConfig(configureRequest());
HttpEntity ent = new InputStreamEntity(new FileInputStream("./bytes.bin"));
req.setEntity(ent);
try (CloseableHttpResponse response = httpclient.execute(req)) {
HttpEntity entity = response.getEntity();
LOG.log(Level.INFO, "*** Reponse status: {0}", response.getStatusLine());
EntityUtils.consume(entity);
LOG.log(Level.INFO, "*** Response entity: {0}", entity.toString());
}
}
}
public static RequestConfig configureRequest() {
HttpHost proxy = new HttpHost("changeit.local", 8080, "http");
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
return config;
}
public static SSLContext createSslCustomContext() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
// Trusted CA keystore
KeyStore tks = KeyStore.getInstance(CA_KEYSTORE_TYPE);
tks.load(new FileInputStream(CA_KEYSTORE_PATH), CA_KEYSTORE_PASS.toCharArray());
// Client keystore
KeyStore cks = KeyStore.getInstance(CLIENT_KEYSTORE_TYPE);
cks.load(new FileInputStream(CLIENT_KEYSTORE_PATH), CLIENT_KEYSTORE_PASS.toCharArray());
SSLContext sslcontext = SSLContexts.custom()
//.loadTrustMaterial(tks, new TrustSelfSignedStrategy()) // use it to customize
.loadKeyMaterial(cks, CLIENT_KEYSTORE_PASS.toCharArray()) // load client certificate
.build();
return sslcontext;
}
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*all 10
给定一个包含证书和私钥的 p12 文件(例如,由 openssl 生成),以下代码将将该文件用于特定的 HttpsURLConnection:
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(new FileInputStream(keyStorePath), keystorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keystorePassword.toCharArray());
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), null, null);
SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslSocketFactory);
Run Code Online (Sandbox Code Playgroud)
初始化需要SSLContext一些时间,因此您可能需要缓存它。
对于那些只想设置双向身份验证(服务器和客户端证书)的人来说,这两个链接的组合可以帮助您:
双向身份验证设置:
https://linuxconfig.org/apache-web-server-ssl-authentication
您不需要使用他们提到的openssl配置文件; 只是用
$ openssl genrsa -des3 -out ca.key 4096
$ openssl req -new -x509 -days 365 -key ca.key -out ca.crt
生成您自己的CA证书,然后通过以下方式生成并签署服务器和客户端密钥:
$ openssl genrsa -des3 -out server.key 4096
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 100 -out server.crt
和
$ openssl genrsa -des3 -out client.key 4096
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 101 -out client.crt
其余部分请按照链接中的步骤操作.管理Chrome的证书与上面提到的firefox示例相同.
接下来,通过以下方式设置服
请注意,您已经创建了服务器.crt和.key,因此您不必再执行该步骤.
| 归档时间: |
|
| 查看次数: |
323442 次 |
| 最近记录: |