Comment fixer le "java.sécurité.cert.CertificateException: aucun sujet noms alternatifs présents " erreur?

j'ai un client Java web service, 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);
    }

quand 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 corriger, j'ai d'abord couru openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt et obtenu le 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)
---

autant que je sache, maintenant, j'ai besoin de

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

est-ce correct?

si oui, comment 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 , je lis ce qui suit:

si vous n'avez pas le contrôle de ce serveur, utilisez son nom d'hôte (à condition QU'il y a au moins un CN correspondant à ce nom d'hôte dans le cert).

Que signifie exactement "?

66
demandé sur Community 2013-10-23 15:23:27

9 réponses

j'ai corrigé 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();
    }
}

comme j'utilise le https://AAA.BBB.CCC.DDD:9443/ISomeService uniquement pour les tests, c'est une bonne solution.

118
répondu 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 ça marche très bien.

ici est la source originale.

23
répondu 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 principe, seulement en utilisant une extension IP SAN).

si votre certificat n'a pas D'IP SAN, mais DNS SANs (ou si pas de DNS SAN, un nom commun dans le DN sujet), vous pouvez faire fonctionner cela en faisant utiliser à votre client une URL avec ce nom d'hôte au lieu (ou un nom d'hôte pour qui le cert serait valide, s'il y a plusieurs valeurs possibles). Par exemple , si vous avez 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 vous résoudre à cette adresse IP.

de plus, s'il y a un Dns SANs, le CN dans le DN en question sera ignoré, donc utilisez un nom qui correspond à l'un des DNS SANs dans ce cas.

14
répondu Bruno 2013-10-23 11:56:11

pour importer le cert:

  1. extraire le cert du serveur, par exemple openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt cela extraira les Cert au format PEM.
  2. convertir le cert en 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 cert 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 la localisation des cacerts de l'installation java par défaut?
  4. importer les certs dans ce fichier cacerts: sudo keytool -importcert -file certs.der -keystore <path-to-cacerts> mot de passe cacerts par défaut est 'changeit'.

si le cert est émis pour un FQDN et que vous essayez de vous connecter par adresse IP dans votre code Java, alors cela devrait probablement être corrigé dans votre code plutôt que de jouer avec le certificat lui-même. Changez votre code pour vous connecter par FQDN. Si FQDN n'est pas résolvable sur votre dev machine, il suffit de l'ajouter à votre fichier hosts, ou configurer votre machine avec le serveur DNS qui peut résoudre ce FQDN.

9
répondu 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é comportait un caractère de remplacement, 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
répondu Shahriar 2015-07-21 22:26:05

vous pouvez ne pas vouloir désactiver toute verification ssl et donc vous pouvez juste désactiver la vérification du nom d'hôte via ceci qui est un peu moins effrayant que l'alternative:

HttpsURLConnection.setDefaultHostnameVerifier(
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

[EDIT]

comme mentionné par conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER est maintenant déprécié, de sorte qu'il peut être supprimé dans une version ultérieure, de sorte que vous pouvez être forcé dans le futur à rouler votre propre, bien que je dirais encore que je serais détourner de toutes les solutions où toute la vérification est éteindre.

3
répondu lifesoordinary 2018-04-27 12:04:34

j'ai corrigé cette question de manière correcte en ajoutant les noms alt des sujets dans le certificat plutôt que d'apporter des changements dans le code ou de désactiver SSL contrairement à ce que d'autres réponses suggèrent ici. Si vous voyez clairement l'exception dit "les noms alt Suject sont manquants" alors la bonne façon devrait être de les ajouter

s'il vous Plaît regarder cette lien à comprendre, étape par étape .

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

  1. Copie de la 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/emailAddress=postmaster@example.com' -days 365
  5. exporter la clé publique (.pem) 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 from self-signed PEM (Keystore)

    keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
    
  7. Générer un Certificat à partir de ci-dessus de magasin de clés ou JKS fichier

    keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
    
  8. comme le certificat ci-dessus est auto-signé et n'est pas validé par CA, il doit être ajouté dans le fichier Trustststststore(Cacerts dans le fichier 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 à cette question posté sur ce lien ici .

0
répondu Abhishek Galoda 2018-10-04 09:24:47

j'ai résolu le problème de la façon 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 lancée. Il a bien fonctionné.
-1
répondu Aditya Bhuyan 2016-08-29 04:19:58

ajoutez votre adresse IP dans le fichier hosts.qui est 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 abc@def.com

-2
répondu Prakash Soni 2016-03-02 05:31:03