Comment fixer le "java.sécurité.cert.CertificateException: Aucun nom alternatif de sujet ne présente " erreur?


J'ai un client de service Web Java, qui consomme un service Web via HTTPS.

import javax.xml.ws.Service;

@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
    extends Service
{

    public ISomeService() {
        super(__getWsdlLocation(), ISOMESERVICE_QNAME);
    }

Lorsque je me connecte à l'URL du service (https://AAA.BBB.CCC.DDD:9443/ISomeService), j'obtiens l'exception java.security.cert.CertificateException: No subject alternative names present.

Pour le fixer, j'ai d'abord couru openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt et a obtenu contenu suivant dans le fichier certs.txt:

CONNECTED(00000003)
---
Certificate chain
 0 s:/CN=someSubdomain.someorganisation.com
   i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-MD5            
    Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Session-ID-ctx:                 
    Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Key-Arg   : None
    Start Time: 1382521838
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---

AFAIK, maintenant j'ai besoin de

  1. extrait de la partie de certs.txt entre -----BEGIN CERTIFICATE----- et -----END CERTIFICATE-----,
  2. modifier pour que le nom du certificat est égal à AAA.BBB.CCC.DDD et
  3. puis importez le résultat en utilisant keytool -importcert -file fileWithModifiedCertificate (où fileWithModifiedCertificate est le résultat des opérations 1 et 2).

Est-ce exact?

Si oui, comment puis-je faire fonctionner le certificat de l'étape 1 avec adddress basé sur IP (AAA.BBB.CCC.DDD) ?

Mise à Jour 1 (23.10.2013 15:37 MSK): Dans une réponse à une question similaire, j'ai lu la suivante:

Si vous ne contrôlez pas ce serveur, utilisez son nom d'hôte (fourni qu'il y a au moins un CN correspondant à ce nom d'hôte dans l'existant cert).

Que signifie exactement "utiliser"?

Author: Community, 2013-10-23

9 answers

J'ai résolu le problème en désactivant les vérifications HTTPS en utilisant l'approche présentée ici :

J'ai mis le code suivant dans la classe ISomeService:

static {
    disableSslVerification();
}

private static void disableSslVerification() {
    try
    {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }
        };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Create all-trusting host name verifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        // Install the all-trusting host verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }
}

Puisque j'utilise le https://AAA.BBB.CCC.DDD:9443/ISomeService à des fins de test uniquement, c'est une solution assez bonne.

 118
Author: DP_, 2013-10-23 13:09:33

J'ai le même problème et résolu avec ce code. J'ai mis ce code avant le premier appel à mes services.

javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){

    public boolean verify(String hostname,
            javax.net.ssl.SSLSession sslSession) {
        return hostname.equals("localhost");
    }
});

, C'est simple et fonctionne très bien.

Voici la source originale.

 23
Author: juanmhidalgo, 2016-03-10 19:19:30

La vérification de l'identité du certificat est effectuée par rapport à ce que le client demande.

Lorsque votre client utilise https://xxx.xxx.xxx.xxx/something (où xxx.xxx.xxx.xxx est une adresse IP), l'identité du certificat est vérifiée par rapport à cette adresse IP (en théorie, en utilisant uniquement une extension IP SAN).

Si votre certificat n'a pas de SAN IP, mais des SAN DNS (ou si aucun SAN DNS, un nom commun dans le DN Sujet), vous pouvez obtenir cela en obligeant votre client à utiliser une URL avec ce nom d'hôte à la place (ou un nom d'hôte pour lequel le certificat serait valide, s'il y a plusieurs valeurs possibles). Par exemple, si votre certificat a un nom pour www.example.com, utilisez https://www.example.com/something.

Bien sûr, vous aurez besoin de ce nom d'hôte pour résoudre cette adresse IP.

De plus, s'il y a des SANS DNS, le CN dans le DN sujet sera ignoré, alors utilisez un nom qui correspond à l'un des SANS DNS dans ce cas.

 14
Author: Bruno, 2013-10-23 11:56:11

Pour importer le certificat:

  1. Extrayez le certificat du serveur, par exemple openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt Cela extraira les certificats au format PEM.
  2. Convertissez le certificat au format DER car c'est ce que keytool attend, par exemple openssl x509 -in certs.txt -out certs.der -outform DER
  3. Maintenant, vous voulez importer ce certificat dans le fichier 'cacert' par défaut du système. Localisez le fichier' cacerts ' par défaut du système pour votre installation Java. Jetez un oeil à Comment obtenir l'emplacement des cacerts de l'installation java par défaut?
  4. Importer les certificats dans ce fichier cacerts: sudo keytool -importcert -file certs.der -keystore <path-to-cacerts> Le mot de passe cacerts par défaut est 'changeit'.

Si le certificat est émis pour un FQDN et que vous essayez de vous connecter par adresse IP dans votre code Java, cela devrait probablement être corrigé dans votre code plutôt que de jouer avec le certificat lui-même. Modifiez votre code pour vous connecter par FQDN. Si le FQDN n'est pas résoluble sur votre machine de développement, ajoutez-le simplement à votre fichier hosts ou configurez votre machine avec un serveur DNS capable de résoudre ce FQDN.

 9
Author: AndreyT, 2017-05-23 12:10:26

Mon problème avec l'obtention de cette erreur a été résolu en utilisant l'URL complète "qatest.ourCompany.com/webService "au lieu de simplement "qatest / webService". La raison en était que notre certificat de sécurité avait un caractère générique, c'est-à-dire "*.ourCompany.com". Une fois que j'ai mis l'adresse complète, l'exception a disparu. Espérons que cette aide.

 3
Author: Shahriar, 2015-07-21 22:26:05

Vous ne voudrez peut-être pas désactiver toute la vérification ssl et vous pouvez donc simplement désactiver la vérification du nom d'hôte via ce qui est un peu moins effrayant que l'alternative:

HttpsURLConnection.setDefaultHostnameVerifier(
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

[MODIFIER]

Comme mentionné par conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER est maintenant obsolète, il peut donc être supprimé dans une version ultérieure, vous pourriez donc être obligé à l'avenir de lancer le vôtre, bien que je dirais toujours que je m'éloignerais de toutes les solutions où toute vérification est désactivée.

 3
Author: lifesoordinary, 2018-04-27 12:04:34

J'ai résolu ce problème de la bonne manière en ajoutant les noms alt de sujet dans le certificat plutôt que d'apporter des modifications au code ou de désactiver SSL contrairement à ce que d'autres réponses suggèrent ici. Si vous voyez clairement l'exception dit que les "noms alt de sujet sont manquants", la bonne façon devrait être de les ajouter

Veuillez regarder ce lienpour comprendre étape par étape .

L'erreur ci-dessus signifie que votre fichier JKS manque le domaine requis sur lequel vous essayez d'accéder application.Vous devrez utiliser Open SSL et l'outil clé pour ajouter plusieurs domaines

  1. Copiez l'openssl.cnf dans un répertoire courant
  2. echo '[ subject_alt_name ]' >> openssl.cnf
  3. echo 'subjectAltName = DNS:example.mydomain1.com, DNS:example.mydomain2.com, DNS:example.mydomain3.com, DNS: localhost'>> openssl.cnf
  4. openssl req -x509 -nodes -newkey rsa:2048 -config openssl.cnf -extensions subject_alt_name -keyout private.key -out self-signed.pem -subj '/C=gb/ST=edinburgh/L=edinburgh/O=mygroup/OU=servicing/CN=www.example.com/[email protected]' -days 365
  5. Exporter la clé publique (.pem) fichier au format PKS12. Cela vous demandera le mot de passe

    openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in
    self-signed.pem -inkey private.key -name myalias -out keystore.p12
    
  6. Créer un. JKS à partir de PEM auto-signé (Keystore)

    keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
    
  7. Générer un certificat à partir du Keystore ou JKS ci-dessus fichier

    keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
    
  8. Puisque le certificat ci-dessus est auto-signé et n'est pas validé par CA, il doit être ajouté dans Truststore(fichier Cacerts dans l'emplacement ci-dessous pour MAC, pour Windows, découvrez où votre JDK est installé.)

    sudo keytool -importcert -file selfsigned.crt -alias myalias -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
    

Réponse originale postée sur ce lien ici .

 0
Author: Abhishek Galoda, 2018-10-04 09:24:47

J'ai résolu le problème de la manière suivante.

1. La création d'une classe . La classe a quelques implémentations vides

class MyTrustManager implements X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    return null;
}

public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
        throws CertificateException {
    // TODO Auto-generated method stub

}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
        throws CertificateException {
    // TODO Auto-generated method stub

}

2. Création d'une méthode

private static void disableSSL() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

  1. Appelez la méthode disableSSL() où l'exception est levée. Il a bien fonctionné.
 -1
Author: Aditya Bhuyan, 2016-08-29 04:19:58

Ajoutez votre adresse IP dans le fichier hosts.qui se trouve dans le dossier de C:\Windows\System32\drivers\etc. Ajoutez également l'adresse IP et le nom de domaine de l'adresse IP. exemple: AAA.BBB.ccc.ddd [email protected]

 -2
Author: Prakash Soni, 2016-03-02 05:31:03