6

에 암호를 설정할 때 나는 내가 server.xml 파일에이 커넥터를 추가하여 보안 연결을 허용하도록 구성 할 시도한 Tomcat7 웹 서버가 있습니다SSLHandshakeException이는 치명적인 경고를받은 : handshake_failure를 바람둥이 7 서버

<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을 나는 서버가 RestTemplate를 사용하여 연결하는 봄 응용 프로그램이 클라이언트 측에서

%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 

: '이 명령을 사용하여 생성 된 자체 서명 된 인증서를 사용하고 있습니다.

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

클래스 MyCustomClientHttpRequestFactory은 다음과 같습니다 :

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; 
    } 
} 

가 여기까지 모든 것이 잘 작동 애플리케이션 컨텍스트 시작에 나는 restTemplate 경우이 방법을 initalize. SslThumbprintVerifier 클래스에 중단 점을 넣으면 코드가이 지점과 NullHostNameVerifier 클래스에 도달했습니다. 이것은 생산 과정에서 테스트되었고 훌륭하게 작동했습니다.

는 지금은 암호 스위트를 제한하여 보안을 확장하고 싶어하고 나는 처음에 제시 한 커넥터에이 속성을 추가 : 나는이 예외가 클라이언트 코드를 실행 해요 때 이제

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" 

:

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

이것은 restTemplate.doExecute() 방법에서 발생합니다. 코드는 암호를 추가하기 전에 수행 한 것처럼 지문 검증기 클래스 나 호스트 이름 검증기 클래스에 도달하지 않습니다. 디버그에서

내가 보여 ctx.getSocketFactory().getSupportedCipherSuites() 확인 :

[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] 

을 또한 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] 

그리고 마지막으로 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] 

를 지금까지 내가 이해, 클라이언트의 sup가 교차하는 경우 예를 들어, SSL_RSA_WITH_RC4_128_SHA과 같은 교차점을 가지고있는 서버에서 지원되는 암호 스위트를 사용할 수 있습니다. 그런데도이 오류가 발생합니다. 나는이 자바 매개 변수를 추가 한 다음 단계에서

는 :

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

는 로그없이 서버 안녕하세요 응답 만 클라이언트 인사했다 :

 

[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 
 

로부터의 암호를 제거 server.xml이 다시 작동합니다. 또한 동일한 컴퓨터에서 서버와 클라이언트를 모두 테스트 할 것이라고 언급 할 것입니다. 클라이언트 요청에서 서버의 IP를 'localhost'로 설정하고 실제 컴퓨터 IP로 설정하려고 시도했지만 두 경우 모두 작동하지 않았습니다.또한, 나는이 서버를 다른 리눅스 머신에서 실행했다. (키 스토어는 리눅스 경로에서 Linux 머신에서 생성되었다.) 여전히 - 이것은 암호없이 작동하고 암호로 작업하는 것을 멈춘다.

답변

12

음,이 문제가 해결되었습니다. 자체 서명 인증서를 작성하면 keytool을 사용하여을 제공하지 않고 을 제공하지 않으면 키 쌍 알고리즘이 기본적으로 DSA가됩니다. 내 암호 제품군에는 DSA 알고리즘이 포함되어 있지 않습니다. 이 경우 클라이언트와 서버가 암호 스위트간에 교차점을 가졌지 만 키 알고리즘에는 적합하지 않습니다.

키 저장소를 생성 할 때 -keyalg RSA을 추가하면 문제가 해결됩니다.