Certificat importé à Java keystore, JVM ignore le nouveau cert
j'essaie de faire tourner une application sur Tomcat 6 pour me connecter à un serveur LDAP sur SSL.
j'ai importé le certificat du serveur à keystore en utilisant:
C:Program FilesJavajdk1.6.0_32jrelibsecurity>keytool -importcert -trustcacerts -file mycert -alias ca_alias -keystore "c:Program FilesJavajdk1.6.0_32jrelibsecuritycacerts"
quand je démarre Tomcat avec le débogage SSL activé, selon les journaux, Tomcat utilise le bon fichier de certificats:
trustStore is: C:Program FilesJavajdk1.6.0_32jrelibsecuritycacerts
cependant, Tomcat n'ajoute pas le certificat que je viens d'importer - tous les autres certificats du fichier cacerts sont imprimés sur le log - and connection échoue:
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
Redémarrer Tomcat n'aide pas. J'ai vérifié avec la commande keytool-list que le nouveau cert existe bien sur le fichier.
pourquoi Tomcat continue d'ignorer mon nouveau cert?
EDIT:
semble que le problème a été causé par Windows 7 VirtualStore. Keytool a créé une nouvelle copie du fichier cacert, et Tomcat a utilisé le fichier original.
4 réponses
JVM doit être redémarré après l'importation des certs dans le keystore.
Vérifiez s'il y a une clé avec les mêmes informations CN mais un alias différent.
j'ai déjà eu des problèmes similaires lorsque j'ai essayé d'importer une nouvelle version d'un certificat, mais j'ai laissé l'ancienne version dans le keystore. Mes programmes Java trouveraient simplement la première clé CN correspondante dans le keystore (qui était l'ancienne clé expirée) et essayeraient de l'utiliser, même s'il y en avait une plus récente qui correspondait aussi au CN.
s'assurer également que la racine d'authentification le certificat (et le certificat intermédiaire s'il y a lieu) existe dans le keystore. Si vous vous authentifiez contre L'un des principaux fournisseurs de sécurité tels que Verisign ou Globalsign, ils vous fourniront généralement les certificats racine et intermédiaire. Si ces certificats existent déjà dans le keystore, assurez-vous qu'ils sont toujours valides. Vous devez avoir tous les certificats de votre certificat personnel tout au long de la chaîne d'authentification à la racine, existant dans votre fichier de clés, de sorte qu'il comprend comment valider vos informations d'identification.
ce que vous avez décrit est exactement ce que J'ai obtenu en utilisant cmd.exe
et un utilisateur régulier bien que membre du groupe administratif sur un serveur Windows. Vous devez commencer cmd.exe
en mode administration pour appliquer les modifications aux fichiers cacerts. Au moins sur L'OSs Win2k8.
si vous ne faites pas ce carets vous montrera dans le keytool.exe -list
voir les certs nouvellement ajoutés mais Tomcat ne les verra pas. Je ne sais pas pourquoi. Mais quand vous l'ajoutez avec cmd.exe a commencé en tant Qu'administrateur Tomcat est d'accord avec les nouveaux certs ajoutés.
vous pouvez aussi utiliser Djavax.net.debug="ssl,handshake"
pour voir ce que Tomcat lit dans le fichier cacerts.
dans mon cas, j'ai examiné tellement de choses avant de comprendre ce qui n'allait pas... J'ai ajouté le certificat à différentes keystores, j'ai ajouté tous les certificats dans la chaîne (ce qui est inutile btw), j'ai téléchargé le cert à nouveau pour ma propre santé mentale et vérifié le numéro de série, et même inspecté le cert téléchargé pour s'assurer qu'il avait toutes les informations correctes.
j'ai fini par écrire un TLS vérifiant l'application client afin de déboguer le problème. Non seulement le serveur distant que j'étais se connectant au support TLS 1.2 (désactivé par défaut dans ma version de Java 7), le serveur n'a également pris en charge aucun des chiffreurs qui étaient activés dans mon client. Il s'avère que Java 7 avait moins de la moitié de ses codes supportés activés, beaucoup d'entre eux étant vraiment peu sûr et certains des plus sûrs étaient désactivés.
après quelques contre-vérifications, j'ai trouvé la liste suivante de TLS 1.2-supported secure ciphers:
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"
}
S'il y a des experts en cryptographie autour, n'hésitez pas à mettre à jour cette liste. J'ai utilisé Qualys SSL Labs,c'Sécurité de l'Information SE répondre et IANA comme mes sources.
pour ceux qui veulent un échantillon du code source que j'ai utilisé, voir ci-dessous. J'utilisais Apache Commons HttpClient 3.0, donc vous aurez probablement besoin de télécharger ce qui suit binaires:
- https://archive.apache.org/dist/httpcomponents/commons-httpclient/3.0/binary/commons-httpclient-3.0.1.zip
- https://archive.apache.org/dist/commons/logging/binaries/commons-logging-1.0.4.zip
- https://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.3.zip
- https://archive.apache.org/dist/commons/lang/binaries/commons-lang-2.6-bin.zip
TLS12SocketFactory.java
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));
}
}
Main.java
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);
}
}
}