web-dev-qa-db-fra.com

Comment les noms de serveur de certificat SSL sont-ils résolus? Puis-je ajouter d'autres noms à l'aide de keytool?

Celles-ci peuvent être formulées sous forme de questions distinctes pour plus de clarté, mais elles sont toutes liées au même problème.

Comment les noms de serveur de certificat SSL sont-ils résolus?

Pourquoi les navigateurs semblent-ils utiliser le champ CN du certificat, alors que le mécanisme de Java semble ne considérer que les "noms alternatifs de sujet"?

Est-il possible d'ajouter d'autres noms à un certificat SSL à l'aide de keytool? Sinon, est-ce que openSSL est une bonne option?

Juste un peu d'arrière-plan: J'ai besoin d'un serveur principal pour communiquer avec plusieurs serveurs utilisant HTTPS. Évidemment, nous ne souhaitons pas acheter de certificats SSL pour chaque serveur (il pourrait y en avoir beaucoup), je souhaite donc utiliser des certificats auto-signés (j'ai utilisé keytool pour les générer). Après avoir ajouté les certificats comme étant approuvés dans le système d'exploitation, les navigateurs (IE et Chrome) acceptent avec joie la connexion comme étant approuvée. Cependant, même après avoir ajouté les certificats aux comptes Java, Java n'accepte toujours pas la connexion comme étant de confiance et lève l'exception suivante:

Causée par: Java.security.cert.CertificateException: aucun autre nom de sujet n'est présent dans Sun.security.util.HostnameChecker.matchIP (HostnameChecker.Java:142) dans Sun.security.util.HostnameChecker.match (HostnameChecker.Java:75). à com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity (X509T rustManagerImpl.Java:264) à com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.Java:264) à com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.ChampSourceServiceTrusted (X509T) (X509TrustManager) Sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate (Clien tHandshaker.Java:1185) ... 14 autres

J'ai trouvé que je pouvais faire Java faire confiance au certificat implémentant mon propre HostNameVerifier, que j'ai copié à partir de cet endroit: com.Sun.jbi.internal.security.https.DefaultHostnameVerifier juste pour tester (au fait, le nom d'hôte passé en argument à HostnameVerifier est correct, je pense donc qu'il aurait dû être accepté).

J'utilise le champ de certificat CN comme nom d'hôte (généralement l'adresse IP).

Quelqu'un peut-il me dire s'il me plaît si je fais quelque chose de mal et me diriger dans la bonne direction?

71
Renato

La manière dont la vérification du nom d'hôte doit être effectuée est définie dans RFC 6125 , qui est assez récente et généralise la pratique à tous les protocoles, et remplace RFC 2818 , qui était spécifique à HTTPS. (Je ne suis même pas sûr Java 7 utilise RFC 6125, ce qui est peut-être trop récent pour cela.)

De RFC 2818 (section 3.1) :

Si une extension subjectAltName de type dNSName est présente, elle DOIT être utilisée comme identité. Sinon, le champ Nom commun (le plus spécifique) dans le champ Objet du certificat DOIT être utilisé. Bien que l'utilisation du nom commun soit une pratique existante, elle est déconseillée et les autorités de certification sont encouragées à utiliser plutôt le nom de fichier dNS.

[...]

Dans certains cas, l'URI est spécifié sous la forme d'une adresse IP plutôt que d'un nom d'hôte. Dans ce cas, le sujet iPAddress subjectAltName doit être présent dans le certificat et doit correspondre exactement à l'adresse IP de l'URI.

Le problème spécifique que vous rencontrez provient essentiellement du fait que vous utilisez des adresses IP dans votre CN et non un nom d’hôte. Certains navigateurs peuvent fonctionner parce que tous les outils ne suivent pas cette spécification de manière stricte, notamment parce que "le plus spécifique" de la RFC 2818 n'est pas clairement défini (voir les discussions de la RFC 6215).

Si vous utilisez keytool, à partir de Java 7, keytool a = une option pour inclure un autre nom de sujet (voir la table dans la documentation pour -ext): vous pouvez utiliser -ext san=dns:www.example.com ou -ext san=ip:10.0.0.1.

EDIT:

Vous pouvez demander un SAN dans OpenSSL en changeant openssl.cnf] (La copie sera placée dans le répertoire en cours si vous ne voulez pas éditer la configuration globale, pour autant que vous le souhaitez. souvenez-vous ou vous pouvez choisir un emplacement explicite à l’aide de la variable d’environnement OPENSSL_CONF).

Définissez les options suivantes (recherchez d'abord les sections appropriées entre crochets):

[req]
req_extensions = v3_req

[ v3_req ]
subjectAltName=IP:10.0.0.1
# or subjectAltName=DNS:www.example.com

Il existe également une astuce intéressante pour utiliser une variable d’environnement à cet effet (plutôt que de le corriger dans un fichier de configuration) ici: http://www.crsr.net/Notes/SSL.html

91
Bruno