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

查看:23
本文介绍了使用自定义 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

不支持的扩展类型_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 类中有两个额外的方法,它们没有被声明为抽象的,但必须被正确使用:

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)

通过将调用委托给我的 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天全站免登陆