Como consertar o " java.seguranca.certificado.CertificateException: No subject alternative names present " error?

tenho um cliente de Serviço Web Java, que consome um serviço web através de 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 me ligo ao URL do serviço (https://AAA.BBB.CCC.DDD:9443/ISomeService), recebo a excepção java.security.cert.CertificateException: No subject alternative names present.

para corrigi-lo, eu corri pela primeira vez openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt e consegui seguir o conteúdo no ficheiro 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, agora preciso

  1. extrair a parte de certs.txt entre -----BEGIN CERTIFICATE----- e -----END CERTIFICATE-----,
  2. alterá-lo de modo a que o nome do certificado seja igual a AAA.BBB.CCC.DDD e
  3. depois importar o resultado usando keytool -importcert -file fileWithModifiedCertificate (em que fileWithModifiedCertificate é o resultado das operações 1 e 2).
Isto está correcto?

Em caso afirmativo, como é que posso fazer com que o certificado do Passo 1 funcione com adddress baseado em IP (AAA.BBB.CCC.DDD) ?

Atualização 1 (23.10.2013 15:37 MSK): em resposta a uma pergunta similar , Eu li o seguinte:

Se não controlares esse servidor, usa o nome da máquina (indicado que existe pelo menos um CN correspondente ao nome da máquina existente certificado).

O que significa exactamente "usar"?

Author: Community, 2013-10-23

9 answers

Corrigi o problema desactivando as verificações dos HTTPS utilizando a abordagem apresentada aqui:

Coloquei o seguinte código na 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();
    }
}
Uma vez que estou a usar o https://AAA.BBB.CCC.DDD:9443/ISomeService só para testes, é uma solução boa o suficiente.
 118
Author: DP_, 2013-10-23 13:09:33
Tenho o mesmo problema e resolvi com este código. Pus este código antes da primeira chamada para os meus 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");
    }
});
É simples e funciona bem.

Aqui está a fonte original.

 23
Author: juanmhidalgo, 2016-03-10 19:19:30
A verificação da identidade do certificado é efectuada em função do pedido do cliente.

Quando o seu cliente usa https://xxx.xxx.xxx.xxx/something (em que xxx.xxx.xxx.xxx é um endereço IP), a identidade do certificado é verificada com este endereço IP (em teoria, apenas usando uma extensão IP SAN).

Se o seu certificado não tiver IP SAN, mas o DNS SANs (ou se não tiver DNS SAN, um nome comum no assunto DN), poderá fazer com que isto funcione fazendo com que o seu cliente use uma URL com o nome da máquina em vez disso (ou um nome da máquina para qual o certificado seria válido, se houver vários valores possíveis). Por exemplo, se o seu cert tem um nome para www.example.com, use https://www.example.com/something.

É claro que vai precisar do nome da máquina para resolver o endereço IP.

Além disso, se houver algum DNS SANs, o CN no assunto DN será ignorado, então use um nome que corresponda a um dos DNS SANs neste caso.

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

Para importar o certificado:

  1. extrair o certificado do servidor, por exemplo {[0] } Isto irá extrair certs no formato PEM.
  2. converta o certificado no formato DER, pois é isto que o keytool espera, por exemplo openssl x509 -in certs.txt -out certs.der -outform DER
  3. agora quer importar este certificado para o ficheiro 'cacert' predefinido do sistema. Localiza o ficheiro predefinido do sistema 'cacerts' para a sua instalação Java. Dê uma olhada em Como obter a localização dos cacerts da instalação padrão java?
  4. importar os certificados nesse ficheiro cacerts: sudo keytool -importcert -file certs.der -keystore <path-to-cacerts> a senha predefinida do cacerts é 'changeit'.

Se o certificado for emitido para um FQDN e estiver a tentar ligar-se pelo endereço IP no seu código Java, então provavelmente isto deverá ser corrigido no seu código em vez de interferir com o próprio certificado. Altere o seu código para se conectar por FQDN. Se o FQDN não for resolúvel na sua máquina dev, basta adicioná-lo ao seu ficheiro hosts, ou configurar a sua máquina com o servidor DNS que possa resolver este FQDN.

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

O meu problema em obter este erro foi resolvido usando o URL completo "qatest.ourCompany.com/webService" em vez de apenas "qatest / webService". A razão era que o nosso certificado de segurança tinha um wildcard ou seja"*. ourCompany.com" assim que coloquei o endereço completo, a excepção desapareceu. Espero que isto ajude.

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

Poderá não querer desactivar toda a verificação do ssl e por isso poderá desactivar a verificação do nome da máquina com isto, o que é um pouco menos assustador do que a alternativa:

HttpsURLConnection.setDefaultHostnameVerifier(
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

[editar]

Como mencionado por conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER está agora desactualizado, por isso pode ser removido numa versão posterior, para que você possa ser forçado no futuro a rolar o seu próprio, embora eu ainda diria que eu iria afastar-me de qualquer solução onde toda a verificação é desligada.

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

Corrigi esta questão de uma forma correcta, adicionando os nomes de assuntos alt no certificado, em vez de fazer quaisquer alterações no código ou desactivar o SSL, ao contrário do que outras respostas sugerem aqui. Se você ver claramente a exceção diz que os "Suject alt names estão faltando" então a maneira certa deve ser adicioná-los

Por favor, Veja este link para entender passo a passo.

O erro acima significa que o seu ficheiro JKS não tem o domínio necessário no qual está a tentar aceder ao aplicacao.Terá de usar o SSL aberto e a ferramenta chave para adicionar vários domínios

  1. copia o openssl.cnf numa pasta actual
  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. Exportar a chave pública (.pem) ficheiro para o formato PKS12. Isto pedir-lhe-á a senha

    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. Criar um a. JKS a partir de auto-assinado PEM (Keystone)

    keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
    
  7. Gerar um certificado a partir de um teclado ou JKS acima ficheiro

    keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
    
  8. Uma vez que o certificado acima é auto-assinado e não é validado por CA, ele precisa ser adicionado na Trustore(Cacerts file em baixo local para MAC, Para Windows, descubra onde o seu JDK está instalado.)

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

A resposta Original foi postada neste link aqui.

 0
Author: Abhishek Galoda, 2018-10-04 09:24:47
Resolvi o problema da seguinte forma.

1. Criar uma classe . A classe tem algumas implementações vazias

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. Criar um método

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. chama o método disableSSL() onde a excepção é lançada. Funcionou bem.
 -1
Author: Aditya Bhuyan, 2016-08-29 04:19:58

Adicione o seu endereço IP no ficheiro hosts.que está na pasta de C:\Windows\System32\drivers\etc. Também adicione IP e nome de domínio do endereço IP. exemplo: aaa.bbb.ccc.ddd [email protected]

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