使用自定义X509KeyManager时,Java无法为SSL握手确定匹配的密码套件 [英] When using a custom X509KeyManager Java is not able to determine a matching cipher suite for the SSL handshake

查看:176
本文介绍了使用自定义X509KeyManager时,Java无法为SSL握手确定匹配的密码套件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Java7和JAX-WS 2.2。

I'm working with Java7 and JAX-WS 2.2.

对于SOAP Web服务,我需要创建一个自定义 X509KeyManager 为了在JKS密钥库中为每个连接客户端找到正确的证书。

For a SOAP web service I need to create a custom X509KeyManager in order to find the correct certificate for each connecting client in a JKS keystore.

但是,我已经在努力获取我的自定义密钥管理器运行。到目前为止,我使用的是默认值(从初始化的 KeyManagerFactory 中检索),它基本上有效 - 但当然它没有选择正确的证书。所以第一个想法是创建一个自定义 X509KeyManager ,它包含原始密钥管理器,只写出一些日志消息,但通常使用默认行为。

However, I'm already struggling to get the my custom key manager running. So far I'm using the default one (retrieved from the initialized KeyManagerFactory) and it basically works - but of course it doesn't select the correct certificate. So the first idea was to create a custom X509KeyManager which holds the original key manager, only writes out some log messages but generally uses the default behaviour.

由于某些原因根本不起作用。无法建立SSL握手。在 ClientHello 之后,日志显示以下错误:

For some reason that doesn't work at all. The SSL handshake cannot be established. After the ClientHello the log shows the following error:

Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Thread-3, READ: TLSv1 Handshake, length = 149
*** ClientHello, TLSv1
RandomCookie:  GMT: 1476877930 bytes = { 207, 226, 8, 128, 40, 207, 47, 180, 146, 211, 157, 64, 239, 13, 201, 92, 158, 111, 108, 44, 223, 136, 193, 251, 33, 202, 7, 90 }
Session ID:  {}
Cipher Suites: [TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
%% Initialized:  [Session-3, SSL_NULL_WITH_NULL_NULL]
Thread-3, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
%% Invalidated:  [Session-3, SSL_NULL_WITH_NULL_NULL]
Thread-3, SEND TLSv1 ALERT:  fatal, description = handshake_failure
Thread-3, WRITE: TLSv1 Alert, length = 2
Thread-3, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common

我没有删除任何密码根据我的知识套房!并且SSL握手可以使用相同的证书。

I didn't remove any cipher suites at all to my knowledge! And the SSL handshake can be made with the same certificates.

这是我的主要经理:

public class CustomX509KeyManager extends X509ExtendedKeyManager
{
   private static final Logger LOG = Logger.getLogger( CustomX509KeyManager.class );
   private final X509KeyManager originalKeyManager;

   public CustomX509KeyManager(final X509KeyManager keyManager)
   {
      super();
      this.originalKeyManager = keyManager;
   }

   @Override
   public String chooseServerAlias(final String keyType, final Principal[] issuers,
     final Socket socket)
   {
      final String serverAliases=
            this.originalKeyManager.chooseServerAlias( keyType, issuers, socket );
      CustomX509KeyManager.LOG.info( "chooseServerAlias() " + serverAliases );
      return serverAliases;
   }

   ...
}

其他方法(此处未显示)也只是调用 originalKeyManager 中的相应方法。在测试期间,我从未看到来自 chooseServerAlias()方法的日志消息。

The other methods (not shown here) are just calling the corresponding methods in the originalKeyManager as well. During testing I never see the log message from the chooseServerAlias() method.

并且它是从另一个类中初始化的 getSslContext()方法:

And it's initialized from another class in the getSslContext()method:

private KeyManager[] getKeyManagers(final KeyManagerFactory keyManagerFactory)
{
   final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

   // replace any X509KeyManager with our own implementation
   for ( int i = 0; i < keyManagers.length; i++ )
   {
      if ( keyManagers[i] instanceof X509KeyManager )
      {
         keyManagers[i] =
               new CustomX509KeyManager( ( X509KeyManager ) keyManagers[i] );
      }
   }

   return keyManagers;
}

public SSLContext getSslContext()
{
  // create the KeyStore and load the JKS file
  final KeyStore keyStore = createKeyStore();

  // initialize key and trust manager factory
  final KeyManagerFactory keyManagerFactory =
        KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
  keyManagerFactory.init( keyStore, "changeit".toCharArray() );
  final TrustManagerFactory trustManagerFactory =
        TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
  trustManagerFactory.init( keyStore );

  // initialize the SSL context
  final SSLContext sslContext = SSLContext.getInstance( "TLS" );
  // sslContext.init( keyManagerFactory.getKeyManagers(),
  //      trustManagerFactory.getTrustManagers(), new SecureRandom() );
  sslContext.init( getKeyManagers( keyManagerFactory ),
        trustManagerFactory.getTrustManagers(), new SecureRandom() );
  return sslContext;
}

注释行显示默认密钥管理器的原始用法。

The commented lines show the original usage of the default key manager.

知道什么是错的吗?为什么使用我的 CustomX509KeyManager 的行为与默认密钥管理器的不同之处在于无法进行握手?使用默认密钥管理器,将为TLS_DHE_RSA_WITH_AES_128_CBC_SHA算法协商加密,该算法也可用于自定义密钥管理器,但由于某些原因未选择。

Any idea what's wrong? Why is the behaviour of using my CustomX509KeyManager so different than the default key manager that the handshake cannot be done? With the default key manager the encryption is negotiated for the TLS_DHE_RSA_WITH_AES_128_CBC_SHA algorithm which is available with the custom key manager as well but for some reason not chosen.

我正在尝试以客户端模式将openssl连接到服务器,但服务器遇到使用SSL的相同问题。当我使用TLS协议时,附加的错误消息

I'm trying to connect with openssl in client mode to the server now but the server encounters the same problem using SSL. When I use the TLS protocol then the additional error message


不支持的扩展名type_35,数据:

Unsupported extension type_35, data:

出现。

我可以确认关于不受支持的扩展的上述通知也会在成功握手时出现,因此这是一个错误的痕迹。

I can confirm that the above notice about unsupported extensions also appears upon successful handshakes so this is a false trace.

推荐答案

经过几天的试用和放大;错误我终于找到了我的错误!

After a few days of trial & error I finally found my mistake!

在Java 7中,自定义密钥管理器应扩展 X509ExtendedKeyManager ,它强制您实现接口 X509KeyManager 的五种方法。但是,类 X509ExtendedKeyManager 中还有两个方法,它们未被声明为abstract,但必须才能被覆盖以便正确使用:

In Java 7 a custom key manager should extend the X509ExtendedKeyManager which forces you to implement five methods of the interface X509KeyManager. However, there are two additional methods in the class X509ExtendedKeyManager which are not declared as abstract but must be overwritten for proper usage:


  • chooseEngineClientAlias(String [],Principal [],SSLEngine)

  • chooseEngineServerAlias(String,Principal [],SSLEngine)

  • chooseEngineClientAlias(String[], Principal[], SSLEngine)
  • chooseEngineServerAlias(String, Principal[], SSLEngine)

之后通过委托调用我的 originalKeyManager (其类型为 X509ExtendedKeyManager )来覆盖和实现方法SSL握手终于成功了。

After overwriting and implementing the methods by delegating the call to my originalKeyManager (which became of type X509ExtendedKeyManager as well) the SSL handshake finally succeeded.

这篇关于使用自定义X509KeyManager时,Java无法为SSL握手确定匹配的密码套件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆