已将证书导入Java密钥库,JVM将忽略新证书
我试图让一个运行在Tomcat6之上的应用程序通过SSL连接到LDAP服务器 我使用以下方法将服务器的证书导入密钥库:已将证书导入Java密钥库,JVM将忽略新证书,java,security,tomcat,ssl-certificate,keytool,Java,Security,Tomcat,Ssl Certificate,Keytool,我试图让一个运行在Tomcat6之上的应用程序通过SSL连接到LDAP服务器 我使用以下方法将服务器的证书导入密钥库: C:\Program Files\Java\jdk1.6.0_32\jre\lib\security>keytool -importcert -trustcacerts -file mycert -alias ca_alias -keystore "c:\Program Files\Java\jdk1.6.0_32\jre\lib\security\cacerts" 当
C:\Program Files\Java\jdk1.6.0_32\jre\lib\security>keytool -importcert -trustcacerts -file mycert -alias ca_alias -keystore "c:\Program Files\Java\jdk1.6.0_32\jre\lib\security\cacerts"
当我在启用SSL调试的情况下启动Tomcat时,根据日志,Tomcat正在使用正确的证书文件:
trustStore is: C:\Program Files\Java\jdk1.6.0_32\jre\lib\security\cacerts
但是,Tomcat没有添加我刚刚导入的证书-cacerts文件中的所有其他证书都打印到日志中-并且连接失败:
handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
重新启动Tomcat没有帮助。我已经用keytool-list命令验证了文件中确实存在新的证书
为什么Tomcat一直无视我的新证书
编辑:
问题似乎是由Windows 7 VirtualStore引起的。Keytool创建了cacert文件的新副本,Tomcat使用了原始文件。检查是否存在具有相同CN信息但别名不同的密钥 我以前也遇到过类似的问题,当时我尝试导入证书的较新版本,但将较旧版本保留在密钥库中。我的Java程序只需在密钥库中找到第一个匹配的CN密钥(即旧的过期密钥),并尝试使用该密钥,即使有一个更新的密钥也与CN匹配
还要确保密钥库中存在身份验证根证书(以及中间证书,如果适用)。若您针对主要安全提供商之一(如Verisign或Globalsign)进行身份验证,他们通常会向您提供根证书和中间证书。如果密钥库中已经存在这些证书,请确保它们仍然有效。您需要拥有从您的个人证书到根证书的所有证书,这些证书存在于您的密钥库中,这样它就能理解如何验证您的凭据。您所描述的正是我在使用
cmd.exe
和普通用户(尽管是Windows服务器上管理组的成员)时得到的。您必须在管理模式下启动cmd.exe
,才能将中的更改应用于cacerts文件。至少在Win2k8操作系统上
如果您不这样做,插入符号将在keytool.exe-列表中显示您查看新添加的证书,但Tomcat不会看到它们。不知道为什么。但是,当您使用以管理员身份启动的cmd.exe添加它时,Tomcat可以使用新添加的证书
您还可以使用Djavax.net.debug=“ssl,handshake”
查看Tomcat从cacerts文件中读取的内容。将证书导入密钥库后,JVM需要重新启动。在我的例子中,我查看了很多东西,然后才发现问题所在。。。我将证书添加到不同的密钥库中,添加了链中的所有证书(顺便说一句,这是毫无意义的),我再次下载了证书,检查了序列号,甚至检查了下载的证书以确保其包含所有正确的信息
为了调试这个问题,我最终编写了一个TLS验证客户端应用程序。我连接的远程服务器不仅只支持TLS 1.2(在我的Java 7版本中默认禁用),而且服务器也不支持在我的客户端中启用的任何密码。事实证明,Java7启用的受支持密码不到其支持密码的一半,其中许多密码确实不安全,一些最安全的密码被禁用
经过反复检查,我得出了以下支持TLS 1.2的安全密码的有序列表:
new String[] {
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
"TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_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_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CCM",
"TLS_DHE_RSA_WITH_AES_128_CCM",
"TLS_DHE_PSK_WITH_AES_256_CCM",
"TLS_DHE_PSK_WITH_AES_128_CCM",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_AES_128_GCM_SHA256",
"TLS_AES_128_CCM_SHA256"
}
如果周围有加密专家,请随时更新此列表。我使用和作为我的来源
对于那些想要我使用的源代码示例的人,请参见下文。我使用的是Apache Commons HttpClient 3.0,因此您可能需要下载以下二进制文件:
TLS12SocketFactory.java
import java.io.*;
导入java.net。*;
导入java.util.*;
导入org.apache.commons.httpclient.params.HttpConnectionParams;
导入org.apache.commons.httpclient.protocol.*;
导入org.apache.commons.lang.StringUtils;
公共类TLS12SocketFactory实现SecureProtocolSocketFactory{
私人最终安全协议插座工厂基地;
公共TLS12SocketFactory()
{
this.base=(SecureProtocolSocketFactory)Protocol.getProtocol(“https”).getSocketFactory();
}
专用套接字仅接受TLS12(套接字)
{
if(javax.net.ssl.SSLSocket的套接字实例){
最终的javax.net.ssl.sslsockets=(javax.net.ssl.SSLSocket)套接字;
//设置TLS 1.2
s、 setEnabledProtocols(新字符串[]{“TLSv1.2”});
//使用来自https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#table-tls-4参数
推荐列表建议=新ArrayList(Arra数组。asList(新字符串[]6 6“TLS”10 10十十十十十十十十十十十十十十十十十点建议列表建议=新Arrayl列表(Arrarayl列表)建议=新ArrayList(Arra数组。asList(新字符串)6 6六个建议(新字符串[]6 6)建议建议:新Arrarayl列表(推荐)建议=新Arrarayl列表(建议建议=新Arrayl列表(推荐)列表(建议=新Arrarayl列表(Arrarayl列表)6)6(Arrayl列表(Arrayl列表(Arrarayl列表)6)6)6 6 6 6)6 6 6(Arrarayl列表(Arrarararayl列表(ArArrayl列表。AS列表。asList。asList。asList。asList(新字符串)AS列表(新字符串(新字符串(新字符串(新字符串[名单)6)6)6)6,“TLS是一个有着128个字符的GCM-SHA256 256个字符的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教宗教信仰的宗教信仰的宗教宗教信仰的宗教信仰的宗教宗教信仰的宗教宗教信仰的宗教宗教信仰的宗教信仰的宗教宗教宗教信仰的宗教信仰的宗教信仰的宗教宗教宗教信仰的宗教宗教信仰的宗教宗教信仰的宗教宗教宗教宗教信仰的宗教信仰的宗教宗教宗教宗教宗教宗教宗教宗教宗教宗教宗教宗教宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教宗教信仰的宗教信仰的宗教信仰的宗教的宗教信仰的宗教宗教信仰的宗教信仰的宗教信仰的宗教信仰的宗教宗教信仰的宗教宗教宗教宗教信仰的宗教信仰的宗教宗教宗教宗教信仰的宗教宗教信仰的宗教宗教U 128_GCM_SHA256”,“TLS_DHE_PSK_带AES_256_GCM_SHA384”我们的研究结果是一个字母,它是一个字母,有128个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有256个字母,有128个字母,有128个字母,有128个字母,有256个字母,有128个字母,有256个字母,有256个字母,有256个字母,有128个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有一个字母,有256_CBC_SHA”,“TLS_ECDHE_RSA_带AES_128_CBC_SHA256”TLS_ECDHE_RSA_与_AES_128_CBC_SHA”,“TLS_DHE_RSA_与_AES_256_CBC_SHA256”,“TLS_DHE_RSA_与_AES_256_CBC_SHA”,“TLS_DHE_RSA_与_AES_128_CBC_SHA256”,“TL
import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.*;
import org.apache.commons.lang.StringUtils;
public class TLS12SocketFactory implements SecureProtocolSocketFactory {
private final SecureProtocolSocketFactory base;
public TLS12SocketFactory()
{
this.base = (SecureProtocolSocketFactory)Protocol.getProtocol("https").getSocketFactory();
}
private Socket acceptOnlyTLS12(Socket socket)
{
if(socket instanceof javax.net.ssl.SSLSocket) {
final javax.net.ssl.SSLSocket s = (javax.net.ssl.SSLSocket)socket;
// Set TLS 1.2
s.setEnabledProtocols(new String[]{ "TLSv1.2" });
// Using recommended ciphers from https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#table-tls-parameters-4
List<String> recommended = new ArrayList(Arrays.asList(new String[]{ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_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_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_CCM", "TLS_DHE_RSA_WITH_AES_128_CCM", "TLS_DHE_PSK_WITH_AES_256_CCM", "TLS_DHE_PSK_WITH_AES_128_CCM", "TLS_CHACHA20_POLY1305_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_AES_128_CCM_SHA256" }));
recommended.retainAll(Arrays.asList(s.getSupportedCipherSuites()));
if(recommended.size() == 0) {
System.err.println("No supported modern ciphers. Update crypto policy or install JCE Unlimited Strength Jurisdiction Policy files." + System.lineSeparator());
} else if(recommended.size() < 3) {
System.out.println("Few supported modern ciphers. It's recommended to update crypto policy or install JCE Unlimited Strength Jurisdiction Policy files." + System.lineSeparator());
}
s.setEnabledCipherSuites(recommended.toArray(new String[0]));
// Log matched cipher and cert
s.addHandshakeCompletedListener(new javax.net.ssl.HandshakeCompletedListener() {
@Override
public void handshakeCompleted(javax.net.ssl.HandshakeCompletedEvent hce) {
String print = s.getInetAddress().getHostName() + System.lineSeparator() + hce.getCipherSuite() + System.lineSeparator();
try {
for(java.security.cert.Certificate cert : hce.getPeerCertificates()) {
List<String> certStrings = Arrays.asList(cert.toString().split("\r?\n"));
for(int line = 0; line < certStrings.size(); line++) {
if(certStrings.get(line).startsWith("Certificate Extensions:")) {
print += System.lineSeparator() + StringUtils.join(certStrings.subList(2, line-1), System.lineSeparator()) + System.lineSeparator();
break;
}
}
}
} catch (javax.net.ssl.SSLPeerUnverifiedException ex) {
print += "Non-certificate based cipher used" + System.lineSeparator();
}
System.out.println(print);
}
});
}
return socket;
}
@Override
public Socket createSocket(String host, int port) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort));
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort, params));
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException
{
return acceptOnlyTLS12(base.createSocket(socket, host, port, autoClose));
}
}
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.params.HttpClientParams;
public class Main {
public static void main(String[] args) {
List<java.net.URI> locations = new ArrayList<>();
for(String arg : args) {
java.net.URI location = java.net.URI.create(arg);
if(location.isAbsolute() && location.getScheme().equals("https")) {
locations.add(location);
} else {
System.out.println("Skipping invalid URL: " + arg);
}
}
System.out.println("Connecting to URL's");
System.out.println();
System.out.println("-------------------------");
TLS12SocketFactory tls12factory = new TLS12SocketFactory();
Protocol.registerProtocol("httpss", new Protocol("httpss", tls12factory, 443));
for(java.net.URI location : locations) {
System.out.println();
try {
// Form request
String tls12url = location.toString().replaceFirst("^https:", "httpss:");
HttpMethod method = new HeadMethod(tls12url);
// Send request
HttpClientParams params = new HttpClientParams();
params.setParameter(HttpClientParams.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
new HttpClient(params).executeMethod(method);
method.setFollowRedirects(true);
// Print response
System.out.println(location.toString());
System.out.println(method.getStatusLine().toString());
} catch (javax.net.ssl.SSLHandshakeException ex) {
System.out.println("There was an error making a secure connection to " + location.getHost());
ex.printStackTrace(System.out);
} catch (HttpException ex) {
System.out.println("There was an error with the external webpage");
ex.printStackTrace(System.out);
} catch (Exception ex) {
System.out.println("Could not complete request");
ex.printStackTrace(System.out);
}
}
System.out.println();
System.out.println("-------------------------");
System.out.println();
try {
// Load supported SSL Ciphers
System.out.println("Supported ciphers");
System.out.println();
System.out.println("-------------------------");
System.out.println();
javax.net.ssl.SSLSocket socket = (javax.net.ssl.SSLSocket)tls12factory.createSocket("www.google.com", 443);
for(String cipher : socket.getSupportedCipherSuites()) {
System.out.println(cipher);
}
System.out.println();
System.out.println("-------------------------");
System.out.println();
// Load enabled SSL Ciphers
System.out.println("Enabled ciphers");
System.out.println();
System.out.println("-------------------------");
System.out.println();
for(String cipher : socket.getEnabledCipherSuites()) {
System.out.println(cipher);
}
System.out.println();
System.out.println("-------------------------");
System.out.println();
// Load the JDK's cacerts keystore file
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
System.out.println("Loading keystore");
System.out.println(filename);
System.out.println();
System.out.println("-------------------------");
System.out.println();
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
// This class retrieves the most-trusted CAs from the keystore
PKIXParameters params = new PKIXParameters(keystore);
// Get the set of trust anchors, which contain the most-trusted CA certificates
for (TrustAnchor ta : params.getTrustAnchors()) {
// Print certificate
System.out.println(ta.getTrustedCert());
}
} catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | IOException ex) {
System.out.println("Could not load keystore");
ex.printStackTrace(System.out);
}
}
}