Java TLS douille : Pas de certificat de confiance trouvé
Laissez-moi vous expliquer rapidement ce que je suis en train de faire. Je suis en train de construire mon propre Apple Push Notification service en java (pour les tests). Ce service fonctionne grâce à TLS socket.
J'ai un client java pour créer un TLS socket pour envoyer des notifications push à l'Apn. J'ai changé l'hôte de l'url pour rediriger la prise de localhost:2195. Maintenant je suis en train d'écrire un java socket serveur pour obtenir la demande de notification.
Cependant, j'obtiens une exception lors de la poignée de main et ne trouve pas comment le résoudre.
Note : je suis en utilisant le même certificat sur les deux côtés, c'est un standard .fichier p12 qui fonctionne pour envoyer des notifications push à l'Apn.
Ici, c'est le client (simplifié) :
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(certificatePath), password.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
kmf.init(ks, password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
tmf.init((KeyStore)null);
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory ssf = sc.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket(InetAddress.getLocalHost(), 2195);
socket.startHandshake();
Voici le serveur :
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(certificatePath), password.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
kmf.init(ks, password.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory ssf = context.getServerSocketFactory();
serverSocket = (SSLServerSocket) ssf.createServerSocket(2195);
Et ici, c'est l'exception :
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
Je suppose que le client n'est pas de faire confiance au certificat du serveur. J'ai essayé de définir le client est TrustManager à accepter le serveur (p12) et cela a fonctionné, cependant j'ai besoin de ce travail, sans avoir à éditer le client (puisque c'est de travailler de cette façon avec les vrais Apn).
Quel type de certificat doit le serveur pour être approuvé par le client ?
Merci d'avance.
OriginalL'auteur Owumaro | 2014-04-17
Vous devez vous connecter pour publier un commentaire.
MODIFIER: J'AI EU TORT! tmf.init(null) utilise la valeur par défaut du fichier de clés comme sslctx.init(,null) !
Qui par défaut est normalement le fichier cacerts dans JRE/lib/security qui NE fait confiance établi de nombreux CAs
alors maintenant, je pense que nous pouvons avoir la certitude que le vrai serveur est à l'aide d'un cert sous un établi CA (et donc
la confiance de votre client), tandis que le cert dans votre p12 apparemment n'est pas;
mais il y a deux possibilités ici:
il est autosignés, ou émis par un inconnu, obscur, ou non prouvées CA
il est délivré par un "vrai" CA le cadre d'un "intermédiaire" autorité de certification qui a besoin d'une chaîne de cert (ou plusieurs)
et vous n'avez pas la chaîne cert(s) dans votre p12. Remarque, cela pourrait encore travailler pour l'authentification des clients
au serveur réel, parce que le vrai serveur peut facilement avoir la chaîne cert(s) "préchargé'
dans son truststore même s'ils ne sont pas en Java.
De distinguer ces, regardez
keytool -keystore file -storetype pkcs12 -list -v
et voir ce que cert ou d'une séquence de certs que vous avez là.
Alors il peut y avoir plusieurs approches de solution:
si vous ne manquant de la chaîne d'cert(s) d'un CA de les obtenir et de les ajouter.
keytool seulement vous permet de remplacer l'ensemble de la chaîne de sorte que vous devez obtenir tous besoin certs;
openssl (si vous en avez ou obtenir) peut sortir la clé et le cert(s) à partir d'un pkcs12,
remplacer ou d'ajouter des certs, et se joindre à eux.
créer un autre magasin et une clé pour le serveur et obtenir un cert (chaîne) à partir d'un CA.
Habituellement, les coûts de l'argent et vous demande de prouver le contrôle du serveur de nom de domaine.
(Votre client peut et doit toujours utiliser ce p12. Les deux côtés ne doit pas être le même.)
localiser l'ancre de confiance (à partir de la p12, ou de quelque chose comme CA) et l'ont
dans un truststore le client explicitement des charges. Vous pouvez effectivement essayé en utilisant la
p12 comme le truststore et dire que vous ne voulez pas que.
mettre l'ancre de confiance dans le client par défaut de truststore, de sorte que le client continue
à l'aide de la valeur par défaut. Si vous n'avez pas l'esprit de la modification de votre environnement JRE (et aucun autre utilisateur ou de l'application
sur votre système est gêné) vient de s'ajouter à JRE/lib/security/cacerts. Ou, en supposant que vous pouvez définir
propriétés système, mettre l'ancre dans un magasin ou tout simplement le laisser dans le p12
et ensemble javax.net.le protocole ssl.trustStore{,Mot de passe,Type} pour indiquer que magasin.
(Si vous copiez vous devez prendre uniquement le cert; p12 est l'un des PRINCIPAUX cert ET pas seulement un cert.
Ne vous contentez pas -importkeystore; -importcert un cert fichier, créé avec -exportcert si nécessaire).
(Vous pouvez Système.setProperty dans votre code, mais c'est la modification de votre code. Si vous exécutez à partir de
ligne de commande vous pouvez utiliser 'java-Dname=valeur...'. Pour les autres cas, YMMV.)
Il est possible, 'type' question: si le cert a été publié avec ExtendedKeyUsage extension
et cette valeur spécifie seulement TLSclient et pas TLSserver (dont le CA peut choisir de le faire)
puis de l'utiliser pour le serveur probablement ne fonctionne pas -- il semble JSSE applique EKU restrictions.
Mais si c'est un problème, vous aurez un très différents de l'Exception.
Et vous pouvez voir aussi dans le keytool -list-v ci-dessus.
Puisque vous (à juste titre) voulez utiliser cette p12 pour votre client, votre serveur logique de la même façon besoins
confiance en elle. (De l'utiliser pour les appels sortants auth n'en fait PAS automatiquement une solution de confiance pour la réception d'auth.)
Mais seulement si/quand clientAuth est en fait fait, ce qui n'est pas la valeur par défaut, votre serveur de code
.setNeedClientAuth(true) sur la SSLServerSocket avant d'accepter la connexion?
Possible approches sont équivalentes à la ci-dessus, sauf en sautant #2 comme inapplicable.
Si le client et le serveur utilisent le même JRE, qui rend le fichier cacerts façon un peu plus facile.
Enfin, oui TrustManager 'PKIX' est plus récente, et généralement plus plein de fonctionnalités que 'SunX509'.
Mais pour le test de base "est l'ancre de confiance dans notre truststore' ils sont équivalents.
Encore désolé pour l'induire en erreur.
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
(plus parce que c'estPKIX
par défaut, pasSunX509
).OriginalL'auteur dave_thompson_085