javax.net.ssl.SSLHandshakeException: No negotiable cipher suite (fatal error: 80: problem wrapping app data)

javax.net.ssl.SSLHandshakeException: No negotiable cipher suite (fatal error: 80: problem wrapping app data)

我正在使用码头 (9.4.12.v20180830) HTTPClient 来调用 REST API。

SSL/TLS 握手失败,出现以下异常跟踪。

我们是 IBM java 1.8 版本。

jdk.tls.client.protocols 定义为 TLSv1.2 已请求 SSLv3 协议但未启用 支持:[TLSv1、TLSv1.1、TLSv1.2] SERVER_DEFAULT: [TLSv1, TLSv1.1, TLSv1.2] CLIENT_DEFAULT:[TLSv1.2] IBMJSSE2 将启用 CBC 保护 使用 SSLEngineImpl。 IBMJSSE2 将允许每个 com.ibm.jsse2.renegotiate 设置为 none 或默认值的 RFC 5746 重新协商 根据 com.ibm.jsse2.renegotiation.indicator 设置为可选或采用默认设置,IBMJSSE2 在初始握手期间不需要重新协商指示符 根据 com.ibm.jsse2.renegotiation.peer.cert.check 设置为 OFF 或默认值,IBMJSSE2 将不会在重新协商期间针对对等证书检查执行身份检查 IBMJSSE2 将允许客户端根据 jdk.tls.rejectClientInitiatedRenegotiation 设置为 FALSE 或默认值发起的重新协商 根据 jdk.tls.allowUnsafeServerCertChange 设置为 FALSE 或默认值

,IBMJSSE2 将不允许在重新协商期间更改不安全的服务器证书
Is initial handshake: true
%% No cached client session
HttpClient@21ffc2b4-32, fatal error: 80: problem wrapping app data
javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
HttpClient@21ffc2b4-32, SEND TLSv1.2 ALERT:  fatal, description = internal_error
HttpClient@21ffc2b4-32, WRITE: TLSv1.2 Alert, length = 2
HttpClient@21ffc2b4-32, called closeOutbound()
HttpClient@21ffc2b4-32, closeOutboundInternal()
[Raw write]: length = 7
0000: 15 03 03 00 02 02 50                               ......P

java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
        at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118)
        at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:110)
        at

jdk.tls.client.protocols is defined as TLSv1.2
    SSLv3 protocol was requested but was not enabled
    SUPPORTED: [TLSv1, TLSv1.1, TLSv1.2]
    SERVER_DEFAULT: [TLSv1, TLSv1.1, TLSv1.2]
    CLIENT_DEFAULT: [TLSv1.2]
    IBMJSSE2 will enable CBC protection
    Using SSLEngineImpl.
    IBMJSSE2 will allow RFC 5746 renegotiation per com.ibm.jsse2.renegotiate set to none or default
    IBMJSSE2 will not require renegotiation indicator during initial handshake per com.ibm.jsse2.renegotiation.indicator set to OPTIONAL or default taken
    IBMJSSE2 will not perform identity checking against the peer cert check during renegotiation per com.ibm.jsse2.renegotiation.peer.cert.check set to OFF or default
    IBMJSSE2 will allow client initiated renegotiation per jdk.tls.rejectClientInitiatedRenegotiation set to FALSE or default
    IBMJSSE2 will not allow unsafe server certificate change during renegotiation per jdk.tls.allowUnsafeServerCertChange set to FALSE or default

    Is initial handshake: true
    %% No cached client session
    HttpClient@21ffc2b4-32, fatal error: 80: problem wrapping app data
    javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
    HttpClient@21ffc2b4-32, SEND TLSv1.2 ALERT:  fatal, description = internal_error
    HttpClient@21ffc2b4-32, WRITE: TLSv1.2 Alert, length = 2
    HttpClient@21ffc2b4-32, called closeOutbound()
    HttpClient@21ffc2b4-32, closeOutboundInternal()
    [Raw write]: length = 7
    0000: 15 03 03 00 02 02 50                               ......P

    java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: No negotiable cipher suite
            at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118)
            at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:110)
            at

下面是使用的示例代码,

public void initialise() {
        /*
         * This is to suppress Jetty logging framework, otherwise it will log
         * errors & traces into stderr. Create and set a dummy Jetty Framework
         * as the Jetty logger class.
         */
        System.setProperty("org.eclipse.jetty.util.log.class",
                "com.ibm.tivoli.netcool.integrations.transportmodule.JettyLoggerSink");

        if (sslEnabled) {
            try {
                logger.log(Level.FINEST, "Initializing secure connection");
                if (keyStoreFilename == null || keyStorePassword == null) {
                    throw new Exception(
                            "Key store filename or password not set.");
                }
                SslContextFactory sslContext = new SslContextFactory(false);
                sslContext.setKeyStorePath(keyStoreFilename);
                sslContext.setKeyStorePassword(keyStorePassword);               
                sslContext.setProtocol("TLSv1.2");                
                sslContext.start();
                client = new HttpClient(sslContext);
            } catch (Exception e) {
                initialise_successful = false;
            }
        } else {
            /*
             * Non-SSL client initialization
             */
            client = new HttpClient();
        }
        try {
            client.start();

        } catch (Exception e) {
            initialise_successful = false;
        }
        initialise_successful = true;
        logger.log(Level.FINEST,
                "HTTP client has been successfully initialized");
    }

我们将不胜感激。

这个问题完全是 IBM 维护的非标准 JVM 的结果(它不符合 Java JVM 标准,也不符合 SSL/TLS 标准)。

您的具体问题的核心是 IBM JVM 出于某种原因没有使用 SSl/TLS 密码套件的 RFC 标准名称。

您必须手动配置排除和包含的密码套件才能发挥任何功能。

首先,使用 SslContextFactory.setExcludeCipherSuites() 一次将排除项设置为空白,然后重试。 (这清除了已知易受攻击的密码套件)。

默认的排除密码套件列表是 JVM 排除的内容、OS 库排除的内容以及 what Jetty excludes.

的组合
// Jetty Exclusion List

private static final String[] DEFAULT_EXCLUDED_CIPHER_SUITES = {
    // Exclude weak / insecure ciphers
    "^.*_(MD5|SHA|SHA1)$",
    // Exclude ciphers that don't support forward secrecy
    "^TLS_RSA_.*$",
    // The following exclusions are present to cleanup known bad cipher
    // suites that may be accidentally included via include patterns.
    // The default enabled cipher list in Java will not include these
    // (but they are available in the supported list).
    "^SSL_.*$",
    "^.*_NULL_.*$",
    "^.*_anon_.*$"
};

然后,在您决定使用此易受攻击的配置之前,您必须通过 SslContextFactory.setIncludeCipherSuites(...) 调用手动声明要限制使用的 IBM JVM 命名密码套件。