自定义DefaultTlsClient时如何在BouncyCastle中启用TLS重协商
自定义DefaultTlsClient时如何在BouncyCastle中启用TLS重协商
看起来你已经做了不少基础配置,但还是卡在TLS重协商的问题上,我来帮你梳理几个关键的调整方向和遗漏点:
一、确保系统属性设置的时机与正确性
首先要保证重协商的全局开关属性在任何JSSE组件初始化之前设置,比如放在Application的onCreate最开头(甚至早于super.onCreate()),同时注意引号的正确性:
override fun onCreate() { // 必须在所有TLS相关操作前设置这个属性 System.setProperty("org.bouncycastle.jsse.client.acceptRenegotiation", "true") super.onCreate() // 后续的Provider替换等操作 }
这个属性是BCJSSE全局生效的开关,晚于JSSE初始化设置的话会完全失效。
二、完善自定义TlsClient的重协商实现
仅仅重写getRenegotiationPolicy可能不够,还需要确保客户端在握手时主动声明支持重协商扩展,完善你的mTlsClient:
public final class mTlsClient(secureRandom: SecureRandom) : DefaultTlsClient(BcTlsCrypto(secureRandom)) { override fun getRenegotiationPolicy(): Int { return RenegotiationPolicy.ACCEPT } // 主动添加重协商信息扩展,确保服务器能识别客户端支持重协商 override fun getClientExtensions(): TlsClientExtensions? { val extensions = super.getClientExtensions() extensions?.addRenegotiationInfoExtension() return extensions } // 可选:监听重协商触发事件,用于调试确认流程 override fun notifyRenegotiationBeginning() { super.notifyRenegotiationBeginning() println("TLS重协商流程已触发") } }
三、确认BCJSSE完全接管TLS握手流程
要确保你创建的SSLContext和Socket完全使用BCJSSE实现,而不是回退到Android系统默认的JSSE:
1. 修正Provider替换逻辑
保证BCJSSE的优先级最高,避免系统Provider被优先调用:
// 先移除旧的BC和BCJSSE实例 Security.removeProvider("BC") Security.removeProvider("BCJSSE") // 插入新的Provider,BCJSSE必须是第一优先级 val newBcProvider = BouncyCastleProvider() Security.insertProviderAt(newBcProvider, 2) Security.insertProviderAt(BouncyCastleJsseProvider(), 1) // 验证Provider是否正确加载 println("已加载BCJSSE:${Security.getProvider("BCJSSE")}") println("已加载BC:${Security.getProvider("BC")}")
2. 用BCJSSE创建SSLContext
明确指定使用BCJSSE来初始化TLS 1.2的SSLContext:
val secureRandom = SecureRandom() // 必须指定"BCJSSE"作为Provider,确保使用BouncyCastle的实现 val sslContext = SSLContext.getInstance("TLSv1.2", "BCJSSE") sslContext.init(null, null, secureRandom) // 创建SSLSocket时强制使用TLS 1.2 val sslSocket = sslContext.socketFactory.createSocket(host, port) as SSLSocket sslSocket.enabledProtocols = arrayOf("TLSv1.2")
四、开启调试日志定位问题
如果还是无法解决,开启BCJSSE的调试日志,能帮你看到TLS握手和重协商的详细交互过程,找出警报触发的具体原因:
System.setProperty("org.bouncycastle.jsse.debug", "true")
日志会输出客户端与服务器的每一步握手细节,比如服务器是否发送了重协商请求、客户端是否正确响应,或者哪一步触发了no_renegotiation警报。
五、排查Android 11的系统限制
Android 11默认禁用了一些不安全的TLS配置,但你已经强制使用TLS 1.2并替换了BCJSSE,主要需要确认:没有代码路径意外使用了系统默认的SSLContext或SocketFactory,确保所有TLS操作都通过BCJSSE执行。
备注:内容来源于stack exchange,提问作者user3429974
相关产品推荐
相关产品推荐

