certificates - ssl certificate java keystore




Alerta de handshake SSL: erro unrecognized_name desde a atualização para o Java 1.7.0 (11)

Apenas para adicionar uma solução aqui. Isso pode ajudar os usuários do LAMP

Options +FollowSymLinks -SymLinksIfOwnerMatch

A linha acima mencionada na configuração do host virtual foi o culpado.

Configuração do host virtual quando erro

<VirtualHost *:80>
    DocumentRoot /var/www/html/load/web
    ServerName dev.load.com
    <Directory "/var/www/html/load/web">
        Options +FollowSymLinks -SymLinksIfOwnerMatch
        AllowOverride All
        Require all granted
        Order Allow,Deny
        Allow from All
    </Directory>
     RewriteEngine on
     RewriteCond %{SERVER_PORT} !^443$
     RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>

Configuração de trabalho

<VirtualHost *:80>
    DocumentRoot /var/www/html/load/web

   ServerName dev.load.com
   <Directory "/var/www/html/load/web">

        AllowOverride All

        Options All

        Order Allow,Deny

        Allow from All

    </Directory>

    # To allow authorization header
    RewriteEngine On
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

   # RewriteCond %{SERVER_PORT} !^443$
   # RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]


</VirtualHost>

Eu atualizei do Java 1.6 para o Java 1.7 hoje. Desde então, ocorreu um erro quando tentei estabelecer uma conexão com o meu servidor da Web sobre SSL:

javax.net.ssl.SSLProtocolException: handshake alert:  unrecognized_name
    at sun.security.ssl.ClientHandshaker.handshakeAlert(ClientHandshaker.java:1288)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1904)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1027)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1289)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1273)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at java.net.URL.openStream(URL.java:1035)

Aqui está o código:

SAXBuilder builder = new SAXBuilder();
Document document = null;

try {
    url = new URL(https://some url);
    document = (Document) builder.build(url.openStream());
} catch (NoSuchAlgorithmException ex) {
    Logger.getLogger(DownloadLoadiciousComputer.class.getName()).log(Level.SEVERE, null, ex);  
}

Seu único projeto de teste é por isso que eu permito e uso certificados não confiáveis ​​com o código:

TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {

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

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

try {

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {

    Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, e);
} 

Tentei me conectar com sucesso a https://google.com.br . onde é minha culpa?

Obrigado.


Correu para este problema com boot de mola e jvm 1.7 e 1.8. Na AWS, não tínhamos a opção de alterar o ServerName e o ServerAlias ​​para corresponder (eles são diferentes), por isso fizemos o seguinte:

Em build.gradle nós adicionamos o seguinte:

System.setProperty("jsse.enableSNIExtension", "false")
bootRun.systemProperties = System.properties

Isso nos permitiu contornar o problema com o "Nome não reconhecido".


Em vez de confiar no mecanismo de host virtual padrão no apache, você pode definir um último virtualhost catchall que usa um ServerName arbitrário e um curinga ServerAlias, por exemplo

ServerName catchall.mydomain.com
ServerAlias *.mydomain.com

Dessa forma, você pode usar o SNI e o apache não retornará o aviso SSL.

Claro, isso só funciona se você puder descrever todos os seus domínios facilmente usando uma sintaxe curinga.


Eu acertei o mesmo problema e descobriu-se que o DNS reverso não estava configurado corretamente, apontava para o nome do host errado para o IP. Depois de corrigir o DNS reverso e reiniciar o httpd, o aviso desaparece. (se eu não corrigir o dns reverso, adicionar o ServerName também me ajudou)


Eu tive o mesmo problema com um servidor Ubuntu Linux executando subversão quando acessado via Eclipse.

Ele mostrou que o problema tinha a ver com um aviso quando o Apache (re) foi iniciado:

[Mon Jun 30 22:27:10 2014] [warn] NameVirtualHost *:80 has no VirtualHosts

... waiting [Mon Jun 30 22:27:11 2014] [warn] NameVirtualHost *:80 has no VirtualHosts

Isto foi devido a uma nova entrada no ports.conf , onde outra diretiva NameVirtualHost foi inserida ao lado da diretiva em sites-enabled/000-default .

Depois de remover a diretiva no ports.conf , o problema desapareceu (depois de reiniciar o Apache, naturalmente)


Eu tive o que acredito que o mesmo problema é. Descobri que precisava ajustar a configuração do Apache para incluir um ServerName ou ServerAlias ​​para o host.

Este código falhou:

public class a {
   public static void main(String [] a) throws Exception {
      java.net.URLConnection c = new java.net.URL("https://mydomain.com/").openConnection();
      c.setDoOutput(true);
      c.getOutputStream();
   }
}

E esse código funcionou:

public class a {
   public static void main(String [] a) throws Exception {
      java.net.URLConnection c = new java.net.URL("https://google.com/").openConnection();
      c.setDoOutput(true);
      c.getOutputStream();
   }
}

O Wireshark revelou que durante o TSL / SSL Hello o alerta de alerta (Level: Warning, Description: Nome Não Reconhecido), Server Hello estava sendo enviado do servidor para o cliente. Foi apenas um aviso, no entanto, o Java 7.1 respondeu imediatamente de volta com uma "Fatal, Descrição: Mensagem Inesperada", o que suponho que significa que as bibliotecas Java SSL não gostam de ver o aviso de nome não reconhecido.

Do Wiki na Segurança da Camada de Transporte (TLS):

112 Aviso de nome não reconhecido somente TLS; O Indicador do Nome do Servidor do cliente especificou um nome de host não suportado pelo servidor

Isso me levou a olhar meus arquivos de configuração do Apache e descobri que, se eu adicionasse um ServerName ou ServerAlias ​​para o nome enviado do lado do cliente / java, ele funcionava corretamente sem erros.

<VirtualHost mydomain.com:443>
  ServerName mydomain.com
  ServerAlias www.mydomain.com

O ServerName meu VirtualHost foi comentado por padrão. Funcionou depois de descomentar.


O Java 7 introduziu o suporte a SNI que é ativado por padrão. Descobri que certos servidores configurados incorretamente enviam um aviso "Nome não reconhecido" no handshake SSL, que é ignorado pela maioria dos clientes ... exceto pelo Java. Como o @Bob Kerns mencionou, os engenheiros da Oracle se recusam a "consertar" esse bug / recurso.

Como solução alternativa, eles sugerem para definir a propriedade jsse.enableSNIExtension . Para permitir que seus programas funcionem sem recompilar, execute seu aplicativo como:

java -Djsse.enableSNIExtension=false yourClass

A propriedade também pode ser configurada no código Java, mas deve ser configurada antes de qualquer ação SSL . Depois que a biblioteca SSL for carregada, você poderá alterar a propriedade, mas isso não afetará o status do SNI . Para desabilitar o SNI em tempo de execução (com as limitações mencionadas acima), use:

System.setProperty("jsse.enableSNIExtension", "false");

A desvantagem de definir esse sinalizador é que o SNI está desabilitado em todos os lugares no aplicativo. Para fazer uso do SNI e ainda suportar servidores mal configurados:

  1. Crie um SSLSocket com o nome do host ao qual você deseja se conectar. Vamos nomear este sslsock .
  2. Tente executar sslsock.startHandshake() . Isso irá bloquear até que seja feito ou lançar uma exceção no erro. Sempre que um erro ocorreu em startHandshake() , obtenha a mensagem de exceção. Se for igual ao handshake alert: unrecognized_name , você encontrou um servidor mal configurado.
  3. Quando você receber o aviso unrecognized_name (fatal em Java), tente abrir um SSLSocket novamente, mas desta vez sem um nome de host. Isso efetivamente desabilita o SNI (afinal, a extensão SNI é sobre adicionar um nome de host à mensagem ClientHello).

Para o proxy SSL do Webscarab, este commit implementa a configuração de fall-back.


Também encontramos esse erro em uma nova compilação do servidor Apache.

A correção em nosso caso foi definir um ServerAlias no httpd.conf que correspondia ao nome do host ao qual o Java estava tentando se conectar. Nosso ServerName foi definido para o nome do host interno. Nosso certificado SSL estava usando o nome do host externo, mas isso não foi suficiente para evitar o aviso.

Para ajudar a depurar, você pode usar este comando ssl:

openssl s_client -servername <hostname> -connect <hostname>:443 -state

Se houver um problema com esse nome de host, ele imprimirá essa mensagem perto do topo da saída:

SSL3 alert read: warning:unrecognized name

Também devo observar que não obtivemos esse erro ao usar esse comando para conectar-se ao nome do host interno, mesmo que ele não corresponda ao certificado SSL.


Usar:

  • System.setProperty ("jsse.enableSNIExtension", "false");
  • Reinicie seu Tomcat (importante)

Você pode desativar o envio de registros SNI com a propriedade do sistema jsse.enableSNIExtension = false.

Se você puder alterar o código, será útil usar SSLCocketFactory#createSocket() (sem parâmetro de host ou com um soquete conectado). Nesse caso, ele não enviará uma indicação de server_name.