OkHttp Security Providers 深度指南:JVM、Android 与 GraalVM 的 TLS/HTTP/2 能力全景
【免费下载链接】okhttpA meticulous HTTP client for the JVM, Android, and GraalVM.项目地址: https://gitcode.com/gh_mirrors/okh/okhttp
导读
Security Providers 是 OkHttp 官方安全文档中对「TLS 与 HTTP/2 能力矩阵」的权威说明,回答了同一个问题:在 JVM、Android、GraalVM 以及 Bouncy Castle、Conscrypt、OpenJSSE、Corretto 等第三方安全提供者(Security Provider)之上,OkHttp 分别能拿到哪些协议能力。读完本文你将掌握:每个提供者的 HTTP/2 与 TLSv1.3 支持情况、OkHttp 底层如何按优先级自动探测并选用平台实现、如何通过把 Provider 注册到首位来切换 TLS 引擎,以及各类限制与已知跟踪问题。
一、Provider 能力总览表(原文核心)
下表是官方文档给出的完整能力矩阵,是所有后续讨论的事实基础:
| Provider | HTTP/2 | TLSv1.3 | Powered By | Notes |
|---|---|---|---|---|
| JVM default | Java 9+ | Java 11+ | [OpenJDK] | |
| Android default | ✅ | Android 10+ | [BoringSSL] | |
| [GraalVM] | ✅ | [OpenJDK] | Only actively tested with JDK 11, not with 8 target | |
| [Bouncy Castle] | ✅ | [Bouncy Castle] | [Tracking bug.][bug5698] | |
| [Conscrypt] | ✅ | ✅ | [BoringSSL] | Activated if Conscrypt is first registered provider. |
| [OpenJSSE] | ✅ | [OpenJDK] | OpenJDK backport. | |
| [Corretto] | ✅ | ✅ | [OpenSSL] | Amazon's high-performance provider. [Tracking bug.][bug5592] |
关键公共基线:所有 Provider 均支持 HTTP/1.1 与 TLSv1.2。
解读这张表需要注意三点:
- 能力是「平台提供」而非「OkHttp 实现」:HTTP/2 依赖 ALPN 协商,TLSv1.3 依赖底层 SSLContext 实现,OkHttp 自身不实现 TLS,它只是把能力翻译成自己的
Protocol与TlsVersion模型。 - 「✅」与「版本号」含义不同:
Java 9+、Android 10+、Java 11+表示能力随运行平台版本渐进出现;单独的 ✅ 表示在该 Provider 选型下该能力默认可用(如 Conscrypt/Corretto 同时点亮两列)。 - 两处 Tracking bug:Bouncy Castle 与 Corretto 各有一个跟踪缺陷,官方在能力标注后明确挂出了跟踪问题链接,说明这两者在某些场景下有已知边界(详见下文第五节)。
二、OkHttp 如何选择 Security Provider:PlatformRegistry 源码级解析
从源码结构看,OkHttp 的 JVM 端平台探测集中在 PlatformRegistry.kt 的findPlatform()中,其选择逻辑严格遵循「第一个 Security Provider 是谁」这一标准:
private val isConscryptPreferred: Boolean get() { val preferredProvider = Security.getProviders()[0].name return "Conscrypt" == preferredProvider } // 同理还有 isOpenJSSEPreferred("OpenJSSE")与 isBouncyCastlePreferred("BC")findPlatform()的完整决策链为:
- 若
Security.getProviders()[0]名为Conscrypt,则尝试ConscryptPlatform.buildIfSupported(); - 否则若首位名为
BC,尝试BouncyCastlePlatform.buildIfSupported(); - 否则若首位名为
OpenJSSE,尝试OpenJSSEPlatform.buildIfSupported(); - 然后回退到
Jdk9Platform.buildIfSupported()(对应 JDK 9+ 或 JDK 8u251+ 之类带 ALPN 的 JDK); - 再回退到
Jdk8WithJettyBootPlatform.buildIfSupported()(JDK 8 早期版本 + Jetty ALPN boot); - 最后兜底返回基础
Platform()。
这就是文档中「Activated if Conscrypt is first registered provider」的实现依据:Conscrypt 必须被注册为第一个 Provider 才会被 OkHttp 采用,Bouncy Castle 与 OpenJSSE 同理(分别要求首位名为BC与OpenJSSE)。因此在实际应用中,激活第三方 TLS 引擎的标准做法是在创建OkHttpClient之前,用Security.insertProviderAt(provider, 1)把目标 Provider 插到首位。
三、七大 Provider 逐一深入
1. JVM default(OpenJDK)
JVM 默认平台是 OpenJDK 安全组实现:HTTP/2 需要 Java 9+(ALPN 被合入 JDK 9),TLSv1.3 需要 Java 11+。在PlatformRegistry中对应Jdk9Platform分支,这也是所有 JVM 应用的基线路径。
2. Android default(BoringSSL)
Android 内置 BoringSSL 作为 TLS 后端,HTTP/2 开箱可用,TLSv1.3 自 Android 10(API level 29)起可用。Android 端使用独立的平台实现(见 okhttp/src/androidMain 下的平台代码),与 JVM 的PlatformRegistry逻辑无关。
3. GraalVM
GraalVM 由 OpenJDK 驱动,HTTP/2 可用。文档特别注明:官方只以 JDK 11 目标进行过主动测试,不支持 JDK 8 target。从 GraalSvm.kt 的 Native Image 配置可以看出其特殊处理:在 GraalVM 原生镜像中,BouncyCastlePlatform、ConscryptPlatform、Jdk8WithJettyBootPlatform、OpenJSSEPlatform全部被@Delete剔除,findPlatform()被替换为固定返回Jdk9Platform:
@TargetClass(Platform.Companion::class) class TargetPlatform { @Substitute fun findPlatform(): Platform = Jdk9Platform.buildIfSupported()!! }也就是说:在 GraalVM Native Image 场景下,第三方 Provider 平台类会被整体移除,统一走 JDK9 平台路径,这是本文表中 GraalVM 行「仅 JDK 11 主动测试」的深层原因之一。
4. Bouncy Castle
- 依赖:
org.bouncycastle:bctls-jdk15on需在 classpath 上(见 BouncyCastlePlatform.kt 注释)。 - HTTP/2 可用(通过其 JSSE 实现的 ALPN),但 TLSv1.3 列为空。
- 实现要点:内部创建
BouncyCastleJsseProvider,newSSLContext()以SSLContext.getInstance("TLS", provider)获取上下文;ALPN 通过BCSSLSocket.parameters.applicationProtocols配置;platformTrustManager()使用"PKIX"算法 +BouncyCastleJsseProvider.PROVIDER_NAME。 - 已知限制:
trustManager(sslSocketFactory)直接抛出UnsupportedOperationException,即使用clientBuilder.sslSocketFactory(SSLSocketFactory)自定义工厂与 Bouncy Castle 不兼容;同时官方挂有 [bug5698] 跟踪问题。 - 测试佐证:BouncyCastleTest.kt 在
assumeBouncyCastle()前置条件下验证真实网络请求可达 HTTP/2 与 TLSv1.3。
5. Conscrypt(首推的 JVM 加速引擎)
- 依赖:
org.conscrypt:conscrypt-openjdk-uber >= 2.1.0(见 ConscryptPlatform.kt 注释)。 - 能力:HTTP/2 与 TLSv1.3 双 ✅,底层是 BoringSSL(Android 同源),因此在 JVM 上能获得与 Android 一致的 TLS 栈体验。
- 激活条件:
isSupported要求Conscrypt.isAvailable()且版本>= 2.1.0(atLeastVersion(2, 1, 0)),并额外做Class.forName("org.conscrypt.Conscrypt$Version")提前抛异常而非致命错误;且必须注册为第一个Provider。 - 实现要点:
newSSLContext()用 Conscrypt 的 Provider 获取"TLS"上下文(版本 API >= 1.4.0 时默认支持 TLSv1.3);configureTlsExtensions()中开启 session tickets(Conscrypt.setUseSessionTickets)并设置 ALPN 协议列表;信任管理器上挂一个DisabledHostnameVerifier,因为主机名校验由 OkHttp 自己负责。 - 测试佐证:ConscryptTest.kt 验证
Platform.get().platformTrustManager()确为 Conscrypt 实例,并覆盖atLeastVersion版本比较逻辑。
6. OpenJSSE
- 依赖:
org.openjsse:openjsse >= 1.1.0。 - 能力:TLSv1.3 ✅、HTTP/2 列为空;它是 OpenJDK TLS 实现的后向移植(backport),适合在旧 JDK 上提前获得 TLSv1.3。
- 实现要点(OpenJSSEPlatform.kt):
newSSLContext()直接请求"TLSv1.3"上下文——注释说明这是为了「对目标版本范围更明确,因为不同 VM 在支持与默认启用的 TLS 版本上常有差异」;ALPN 通过org.openjsse.javax.net.ssl.SSLParameters.applicationProtocols设置。 - 同样限制:
trustManager(sslSocketFactory)抛出UnsupportedOperationException。 - 测试佐证:OpenJSSETest.kt 用 MockWebServer 验证 TLSv1.3 握手成功、协议为 HTTP/2,且底层 socket 确为
org.openjsse.sun.security.ssl.SSLSocketImpl。
7. Corretto(Amazon Corretto Crypto Provider)
- 能力:HTTP/2 与 TLSv1.3 双 ✅,底层 OpenSSL,官方定位为高性能加密 Provider。
- 文档标注了 [bug5592] 跟踪问题,提示其在 OkHttp 集成中存在已知缺陷需要关注。
- 测试佐证:CorrettoTest.kt 通过
PlatformRule.isCorrettoSupported/isCorrettoInstalled断言其可用性,并验证真实网络请求得到 HTTP/2 与 TLSv1.3。
四、如何配置:把 Provider 注册到首位
由于 OkHttp 只看Security.getProviders()[0],正确接入第三方 Provider 的步骤是(以 Conscrypt 为例):
import org.conscrypt.Conscrypt; import java.security.Security; // 必须在创建 OkHttpClient 之前执行 Security.insertProviderAt(Conscrypt.newProvider(), 1); OkHttpClient client = new OkHttpClient();insertProviderAt(provider, 1)中的1表示插入到索引 1(索引 0 是第一个位置),使Security.getProviders()[0]变为目标 Provider;- 同理,Bouncy Castle 需要把
BouncyCastleProvider(JCE 部分,名字为BC)与BouncyCastleJsseProvider(JSSE 部分)注册好,其中 JSSE Provider 名需为BC以命中isBouncyCastlePreferred判断; - OpenJSSE 则注册
new OpenJSSE()到首位。
仓库自带的测试基建演示了这套配置的自动化形式:PlatformRule.kt 内部通过Security.insertProviderAt(provider, 1)插入 Conscrypt / OpenJSSE / BouncyCastle,并通过Security.insertProviderAt(BouncyCastleProvider(), 1)+Security.insertProviderAt(BouncyCastleJsseProvider(), 2)处理 BC 的两段注册,还提供了assumeConscrypt()、assumeOpenJSSE()、assumeCorretto()、assumeBouncyCastle()等前置条件与expectFailureOnConscryptPlatform()等失败预期工具,方便 CI 在多平台矩阵上跑同一套测试。
配置完成后,验证当前生效平台的方式:检查Platform.get()返回的实例类型(如ConscryptPlatform、OpenJSSEPlatform、Jdk9Platform),或在握手后读取response.handshake?.tlsVersion与response.protocol确认 TLSv1.3 / HTTP/2 是否按预期协商。
五、边界与限制(原文 Notes 的展开)
- 版本门槛:JVM 的 HTTP/2 依赖 Java 9+ 的 ALPN 支持、TLSv1.3 依赖 Java 11+;若跑在 JDK 8 早期版本(无 ALPN),
Jdk8WithJettyBootPlatform是最后的兼容路径。想提前在旧平台获得新能力,应选用 Conscrypt(HTTP/2 + TLSv1.3)或 OpenJSSE(TLSv1.3 backport)。 - Bouncy Castle 的兼容性代价:其
sslSocketFactory(SSLSocketFactory)自定义工厂不被支持;且 BouncyCastle 测试基建中注释提到 ECDSA 密钥场景下该 Provider 存在工作异常,测试会退化为 RSA 证书(见 PlatformRule.kt 中localhostHandshakeCertificatesWithRsa2048相关逻辑)。 - GraalVM 特例:Native Image 下第三方平台类被删除,只走
Jdk9Platform,且官方仅以 JDK 11 目标测试,使用 GraalVM 时请锁定 JDK 11 系环境。 - Corretto 与 Bouncy Castle 的已知缺陷:官方分别以 [bug5592] 与 [bug5698] 跟踪,接入前应关注对应 issue 状态。
- Android 无需干预:Android 默认栈(BoringSSL)已覆盖 HTTP/2 与 Android 10+ 的 TLSv1.3,一般不需要额外注册 Provider。
六、延伸阅读
- 官方安全总览与支持版本策略:security.md(版本支持矩阵、漏洞报告与制品签名验证方式)
- TLS 配置历史与演进:tls_configuration_history.md
- HTTPS 与证书校验指南:https.md
- 平台探测源码:PlatformRegistry.kt 及各
*Platform.kt实现 - 多平台测试基建:PlatformRule.kt 与 ConscryptTest.kt、OpenJSSETest.kt、CorrettoTest.kt、BouncyCastleTest.kt
- GraalVM 原生镜像适配:GraalSvm.kt
【免费下载链接】okhttpA meticulous HTTP client for the JVM, Android, and GraalVM.项目地址: https://gitcode.com/gh_mirrors/okh/okhttp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考