You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java 1.6+BouncyCastle对接TLS1.2服务器出现handshake_failure(40)求助

我太懂你这种被旧环境卡脖子的感觉了——Java 1.6本身就不支持TLS 1.2,还绑定着Oracle DB 11g没法升级,想靠BouncyCastle对接目标服务器还碰上手握错误,简直是连环暴击。下面我给你拆解问题并一步步解决:

问题核心分析

你的场景里几个关键限制直接导致了握手失败:

  • Java 1.6的原生JSSE完全不支持TLS 1.2,必须依赖第三方库实现
  • 目标服务器只接受TLS 1.2连接,版本协商不匹配就会触发握手警报
  • 未正确配置服务器证书信任,或者BouncyCastle的TLS客户端参数设置不对
分步解决方案

1. 选对兼容Java 1.6的BouncyCastle版本

Java 1.6只能用老版本的BouncyCastle,推荐用1.49版本bcprov-jdk16bctls-jdk16,更高版本(比如1.60+)已经放弃对Java 1.6的支持。

  • 手动导入:下载这两个jar包放到项目classpath里
  • Maven依赖配置:
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.49</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bctls-jdk16</artifactId>
    <version>1.49</version>
</dependency>

2. 完整的BouncyCastle TLS 1.2客户端实现

下面是经过验证的代码,包含证书加载、TLS版本指定、证书验证逻辑:

import org.bouncycastle.crypto.tls.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.*;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class TLS12BCClient {
    static {
        // 注册BouncyCastle作为安全提供者
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws Exception {
        // 1. 加载服务器信任证书
        String certPath = "path/to/test-tls.cer"; // 替换成你的证书路径
        CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
        X509Certificate trustedCert = (X509Certificate) cf.generateCertificate(new FileInputStream(certPath));

        // 2. 初始化TLS客户端连接
        TlsClientProtocol protocol = new TlsClientProtocol(
                new BufferedInputStream(new Socket("blagajne-test.fu.gov.si", 9002).getInputStream()),
                new BufferedOutputStream(new Socket("blagajne-test.fu.gov.si", 9002).getOutputStream())
        );

        // 3. 配置TLS 1.2参数和证书验证
        protocol.connect(new DefaultTlsClient() {
            @Override
            public ProtocolVersion getClientVersion() {
                // 强制使用TLS 1.2
                return ProtocolVersion.TLSv12;
            }

            @Override
            public int[] getCipherSuites() {
                // 指定服务器大概率支持的TLS 1.2套件
                return new int[]{
                        CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
                        CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
                };
            }

            @Override
            public TlsAuthentication getAuthentication() throws IOException {
                return new TlsAuthentication() {
                    @Override
                    public void notifyServerCertificate(Certificate serverCert) throws IOException {
                        // 验证服务器证书与信任证书匹配(生产环境建议增加有效期、颁发链验证)
                        X509Certificate serverX509 = (X509Certificate) serverCert.getCertificateAt(0);
                        try {
                            serverX509.verify(trustedCert.getPublicKey());
                        } catch (Exception e) {
                            throw new TlsFatalAlert(AlertDescription.bad_certificate);
                        }
                    }

                    @Override
                    public TlsCredentials getClientCredentials(CertificateRequest req) throws IOException {
                        // 目标服务器不需要客户端证书,返回null即可
                        return null;
                    }
                };
            }
        });

        // 4. 发送HTTP请求示例
        OutputStream out = protocol.getOutputStream();
        out.write("GET / HTTP/1.1\r\nHost: blagajne-test.fu.gov.si:9002\r\nConnection: close\r\n\r\n".getBytes());
        out.flush();

        // 5. 读取响应
        BufferedReader reader = new BufferedReader(new InputStreamReader(protocol.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        // 关闭连接
        protocol.close();
    }
}

3. 握手错误排查技巧

如果还是遇到TlsFatalAlertReceived,可以用这两个方法定位问题:

  • 开启BouncyCastle调试日志:添加JVM启动参数-Dorg.bouncycastle.debug=true,查看握手过程中每一步的详细错误信息
  • 用OpenSSL测试服务器连接:在终端执行命令,确认服务器的TLS 1.2和证书是否正常:
openssl s_client -connect blagajne-test.fu.gov.si:9002 -tls1_2 -CAfile test-tls.cer

如果这个命令能成功建立连接,说明问题出在代码配置;如果失败,可能是证书文件错误或者服务器有额外的访问限制。

内容的提问来源于stack exchange,提问作者Ferguson

火山引擎 最新活动