Come risolvere il problema “java.security.cert.CertificateException: nessun nome alternativo di sobject presente”?

Ho un client di servizi Web Java che utilizza un servizio Web tramite 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); } 

Quando mi collego all’URL del servizio ( https://AAA.BBB.CCC.DDD:9443/ISomeService ), ottengo l’eccezione java.security.cert.CertificateException: No subject alternative names present .

Per risolvere il problema, ho prima eseguito openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt e ho ottenuto il seguente contenuto nel file 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, ora ho bisogno di

  1. estrai la parte di certs.txt tra -----BEGIN CERTIFICATE----- e -----END CERTIFICATE----- ,
  2. modificarlo in modo che il nome del certificato sia uguale a AAA.BBB.CCC.DDD e
  3. quindi importare il risultato utilizzando keytool -importcert -file fileWithModifiedCertificate (dove fileWithModifiedCertificate è il risultato delle operazioni 1 e 2).

È corretto?

In tal caso, in che modo posso eseguire esattamente il certificato dal passaggio 1 con l’add -ress basato su IP ( AAA.BBB.CCC.DDD )?

Aggiornamento 1 (23.10.2013 15:37 MSK): In una risposta a una domanda simile , ho letto quanto segue:

Se non hai il controllo di quel server, usa il suo nome host (ammesso che ci sia almeno un CN che corrisponde al nome host nel certificato esistente).

Cosa significa esattamente “usare”?

Ho risolto il problema disabilitando i controlli HTTPS utilizzando l’approccio presentato qui :

ISomeService il seguente codice nella class 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(); } } 

Poiché sto utilizzando https://AAA.BBB.CCC.DDD:9443/ISomeService solo a scopo di test, è una soluzione abbastanza buona.

Ho lo stesso problema e ho risolto questo codice. Ho messo questo codice prima della prima chiamata ai miei webservices.

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

È semplice e funziona bene.

Ecco la fonte originale.

La verifica dell’id quadro del certificato viene eseguita rispetto a ciò che il cliente richiede.

Quando il client utilizza https://xxx.xxx.xxx.xxx/something (dove xxx.xxx.xxx.xxx è un indirizzo IP), l’id quadro del certificato viene verificata rispetto a questo indirizzo IP (in teoria, utilizzando solo una SAN IP estensione).

Se il tuo certificato non ha SAN IP, ma DNS SAN (o se nessuna SAN DNS, un nome comune nel DN dell’object), puoi farlo funzionare facendo in modo che il client usi un URL con quel nome host (o un nome host) per cui la cert sarebbe valida, se ci sono più valori possibili). Ad esempio, se il certificato ha un nome per www.example.com , utilizza https://www.example.com/something .

Naturalmente, avrai bisogno di quel nome host per risolvere l’indirizzo IP.

Inoltre, se sono presenti SAN DNS, il CN nel DN object verrà ignorato, quindi utilizzare un nome che corrisponde a una delle SAN DNS in questo caso.

Per importare il certificato:

  1. Estrai il certificato dal server, ad esempio openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt Questo estrae i certificati in formato PEM.
  2. Converti il ​​certificato in formato DER poiché questo è ciò che si aspetta da keytool, ad esempio openssl x509 -in certs.txt -out certs.der -outform DER
  3. Ora vuoi importare questo cert nel file ‘cacert’ di default del sistema. Individua il file ‘cacerts’ di default del sistema per l’installazione di Java. Dai un’occhiata a Come ottenere la posizione dei cacerts dell’installazione java predefinita?
  4. Importare i certificati in quel file cacerts: sudo keytool -importcert -file certs.der -keystore password cacerts predefinita è ‘changeit’.

Se il certificato viene emesso per un FQDN e stai cercando di connetterti per indirizzo IP nel tuo codice Java, probabilmente questo dovrebbe essere corretto nel tuo codice piuttosto che fare confusione con il certificato stesso. Cambia il tuo codice per connettersi tramite FQDN. Se FQDN non è risolvibile sulla macchina dev, è sufficiente aggiungerlo al file host o configurare la macchina con un server DNS in grado di risolvere questo FQDN.

il mio problema con l’ottenimento di questo errore è stato risolto utilizzando l’URL completo “qatest.ourCompany.com/webService” invece di “qatest / webService”. Il motivo era che il nostro certificato di sicurezza aveva un carattere jolly “* .ourCompany.com”. Una volta inserito l’indirizzo completo, l’eccezione è andata via. Spero che questo ti aiuti.

Potresti non voler disabilitare tutte le verifiche di ssl e quindi puoi semplicemente disabilitare la verifica hostName tramite questo, che è un po ‘meno spaventoso dell’alternativa:

 HttpsURLConnection.setDefaultHostnameVerifier( SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

[MODIFICARE]

Come accennato da conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER è ora deprecato, quindi potrebbe essere rimosso in una versione successiva, quindi potresti essere costretto in futuro a eseguire il rollover, anche se direi che preferirei evitare qualsiasi soluzione in cui è presente tutta la verifica spento.

Ho risolto il problema in questo modo.

1. Creazione di una class. La class ha alcune implementazioni vuote

 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. Creazione di un metodo

 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. Chiama il metodo disableSSL () dove viene generata l’eccezione. Ha funzionato bene.

Aggiungi il tuo indirizzo IP nel file hosts. Che si trova nella cartella C: \ Windows \ System32 \ drivers \ etc. Aggiungere inoltre IP e nome dominio dell’indirizzo IP. esempio: aaa.bbb.ccc.ddd abc@def.com