2013-03-21 23 views
6

Ho un web-server Tomcat7 che ho provato a configurare per accettare connessioni sicure con l'aggiunta di questo connettore al file server.xml:SSLHandshakeException: Ricevuto avviso fatale: handshake_failure quando si imposta cifrari su Tomcat 7 Server

<Connector SSLEnabled="true" 
      acceptCount="100" 
      connectionTimeout="20000" 
      executor="tomcatThreadPool" 
      keyAlias="server" 
      keystoreFile="c:\opt\engine\conf\tc.keystore" 
      keystorePass="o39UI12z" 
      maxKeepAliveRequests="15" 
      port="8443" 
      protocol="HTTP/1.1" 
      redirectPort="8443" 
      scheme="https" 
      secure="true" 
      sslProtocol="TLS"/> 

I 'm utilizzando un certificato auto-firmato generato utilizzando questo comando:

%JAVA_HOME%/bin/keytool -genkeypair -keystore c:\opt\engine\conf\tc.keystore -storepass o39UI12z-keypass o39UI12z-dname "cn=Company, ou=Company, o=Com, c=US" -alias server -validity 36500 

Sul lato client ho un'applicazione di primavera che si collega con il server utilizzando RestTemplate. Sul contesto di applicazione di avvio ho inizializzare l'istanza restTemplate in questo modo:

final ClientHttpRequestFactory clientHttpRequestFactory = 
     new MyCustomClientHttpRequestFactory(new NullHostNameVerifier(), serverInfo); 
    restTemplate.setRequestFactory(clientHttpRequestFactory); 

Il MyCustomClientHttpRequestFactory classe si presenta così:

public class MyCustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory { 

private static final Logger LOGGER = LoggerFactory 
    .getLogger(MyCustomClientHttpRequestFactory.class); 

private final HostnameVerifier hostNameVerifier; 
private final ServerInfo serverInfo; 

public MyCustomClientHttpRequestFactory (final HostnameVerifier hostNameVerifier, 
    final ServerInfo serverInfo) { 
    this.hostNameVerifier = hostNameVerifier; 
    this.serverInfo = serverInfo; 
} 

@Override 
protected void prepareConnection(final HttpURLConnection connection, final String httpMethod) 
    throws IOException { 
    if (connection instanceof HttpsURLConnection) { 
     ((HttpsURLConnection) connection).setHostnameVerifier(hostNameVerifier); 
     ((HttpsURLConnection) connection).setSSLSocketFactory(initSSLContext() 
      .getSocketFactory()); 
    } 
    super.prepareConnection(connection, httpMethod); 
} 

private SSLContext initSSLContext() { 
    try { 
     System.setProperty("https.protocols", "TLSv1"); 

     // Set ssl trust manager. Verify against our server thumbprint 
     final SSLContext ctx = SSLContext.getInstance("TLSv1"); 
     final SslThumbprintVerifier verifier = new SslThumbprintVerifier(serverInfo); 
     final ThumbprintTrustManager thumbPrintTrustManager = 
      new ThumbprintTrustManager(null, verifier); 
     ctx.init(null, new TrustManager[] { thumbPrintTrustManager }, null); 
     return ctx; 
    } catch (final Exception ex) { 
     LOGGER.error(
      "An exception was thrown while trying to initialize HTTP security manager.", ex); 
     return null; 
    } 
} 

Fino a qui tutto ha funzionato bene. Quando ho inserito un punto di interruzione nella classe SslThumbprintVerifier, il codice ha raggiunto questo punto e anche la classe NullHostNameVerifier. Questo è stato testato in produzione e ha funzionato alla grande.

Ora volevo estendere la sicurezza, limitando le suite di cifratura e ho aggiunto questa proprietà per il connettore ho presentato all'inizio:

ciphers="TLS_KRB5_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_SHA,SSL_DHE_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_AES_256_CBC_SHA,SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_DHE_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_KRB5_WITH_3DES_EDE_CBC_SHA" 

Ora quando sono in esecuzione il codice del client ottengo questa eccezione:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 

Questo succede nel metodo restTemplate.doExecute(). Il codice non raggiunge la classe del verificatore di impronte digitali né la classe del verificatore del nome host come prima di aggiungere le cifre.

In di debug ho controllato il ctx.getSocketFactory().getSupportedCipherSuites() che ha mostrato:

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_256_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5] 

e anche controllato ctx.getSocketFactory().getDefaultCipherSuites():

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 

e infine il ctx.getSupportedSSLParameters().getCipherSuites():

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_256_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5] 

Per quanto ho capito, se c'è un'intersezione tra il cliente sup suite di crittografia con porting/abilitato e suite di crittografia supportate dal server dovrebbe funzionare (abbiamo tale intersezione con SSL_RSA_WITH_RC4_128_SHA per esempio). Eppure sto ricevendo questo errore.

Nella fase successiva ho aggiunto il parametro java:

-Djavax.net.debug=ssl,handshake,failure 

Il registro ha mostrato solo il client-ciao, con nessun server-ciao risposta:

 

[2013-03-20 15:29:51.315] [INFO ] data-service-pool-37   System.out              trigger seeding of SecureRandom 
[2013-03-20 15:29:51.315] [INFO ] data-service-pool-37   System.out              done seeding SecureRandom 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              Allow unsafe renegotiation: false 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              Allow legacy hello messages: true 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              Is initial handshake: true 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              Is secure renegotiation: false 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              %% No cached client session 
[2013-03-20 15:30:38.894] [INFO ] data-service-pool-37   System.out              *** ClientHello, TLSv1 
[2013-03-20 15:30:38.941] [INFO ] data-service-pool-37   System.out              RandomCookie: GMT: 1363720446 bytes = { 99, 249, 173, 214, 110, 82, 58, 52, 189, 92, 74, 169, 133, 128, 250, 109, 160, 64, 112, 253, 50, 160, 255, 196, 85, 93, 33, 172 } 
[2013-03-20 15:30:38.941] [INFO ] data-service-pool-37   System.out              Session ID: {} 
[2013-03-20 15:30:38.941] [INFO ] data-service-pool-37   System.out              Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 
[2013-03-20 15:30:38.956] [INFO ] data-service-pool-37   System.out              Compression Methods: { 0 } 
[2013-03-20 15:30:38.956] [INFO ] data-service-pool-37   System.out              *** 
[2013-03-20 15:30:38.956] [INFO ] data-service-pool-37   System.out              data-service-pool-37, WRITE: TLSv1 Handshake, length = 81 
[2013-03-20 15:30:38.956] [INFO ] data-service-pool-37   System.out              data-service-pool-37, READ: TLSv1 Alert, length = 2 
[2013-03-20 15:30:38.956] [INFO ] data-service-pool-37   System.out              data-service-pool-37, RECV TLSv1 ALERT: fatal, handshake_failure 
[2013-03-20 15:30:38.972] [INFO ] data-service-pool-37   System.out              data-service-pool-37, called closeSocket() 
[2013-03-20 15:30:38.972] [INFO ] data-service-pool-37   System.out              data-service-pool-37, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 
 

Quando si rimuovono le cifre dalla server.xml funziona di nuovo. Inoltre, ricorderò che sto testando sia il server che il client sulla stessa macchina. Ho provato a impostare l'IP del server nella richiesta del client su "localhost" e sull'IP della macchina reale e non ha funzionato in entrambi i casi.Inoltre, ho avuto questo server in esecuzione su una macchina Linux diversa (il keystore è stato generato sulla macchina Linux con un percorso linux ovviamente) e ancora - funziona senza cifrari e smette di lavorare con le cifre.

risposta

12

Bene, ho risolto questo problema. Sembra che creando un certificato autofirmato, utilizzando keytool, senza fornire il parametro -keyalg, l'algoritmo delle coppie di chiavi sia impostato su DSA. Nessuna delle mie suite di crittografia includeva l'algoritmo DSA. In tal caso, sebbene il client e il server avessero un'intersezione tra i loro pacchetti di crittografia, nessuno dei due era adatto per l'algoritmo chiave.

L'aggiunta di -keyalg RSA durante la generazione del keystore ha risolto il problema.