Android新旧证书信任差异:旧证正常新证报Trust anchor缺失
Android Retrofit证书信任异常问题
场景与代码
我有一个用Retrofit开发的Android应用,用来调用服务器API。服务器最近更新了证书,应用没有自定义网络配置、证书固定或其他证书自定义规则,初始化代码如下:
object ServiceBuilder { fun <T> buildService(service: Class<T>, interceptor: Interceptor): T { val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() val client: OkHttpClient = OkHttpClient.Builder() .followRedirects(false) .addInterceptor(interceptor) .build() val retrofit: Retrofit = Retrofit.Builder() .addConverterFactory(MoshiConverterFactory.create(moshi)) .baseUrl(DemoServerUrl.LOCALHOST_URL.url) .client(client) .build() return retrofit.create(service) } }
旧证书场景
服务器未发送完整证书链,仅发送首证书,但应用能正常调用API。该证书的根证书是Android系统信任的DigiCert Global Root CA;只有禁用这个根证书时才会报错。
新证书场景
服务器同样只发送首证书,应用调用API时出现Trust anchor for certification path not found错误。该证书的根证书是Android系统信任的DigiCert Global Root G2。
已清理测试设备上的所有自定义证书,确保设备没有未知中间证书。
疑问
为什么旧证书能正常调用,新证书不行?按理解Android不会遵循AIA获取缺失链,两者都应该报错才对。
解答
核心原因是旧证书的首证书(服务器证书)要么直接由DigiCert Global Root CA签发,要么其缺失的中间证书已被Android系统预装信任,而新证书对应的中间证书不在系统预装列表里,Android又不会主动通过AIA下载缺失链,导致无法完成信任链验证。
具体拆解:
- 旧证书场景:虽然服务器只发送了首证书,但如果该证书是根CA直接签发的,系统能直接完成验证;或者对应的中间证书是Android系统默认预装信任的(比如DigiCert的部分中间证书被内置在系统信任库),即便服务器没发,系统也能自动补上缺失的链,完成信任校验。
- 新证书场景:新的服务器证书由
DigiCert Global Root G2下的某个中间CA签发,而这个中间证书不在Android系统的预装信任列表中,服务器又未发送完整证书链,系统找不到能连接到根CA的完整信任路径,就会抛出信任锚找不到的错误。
可以通过以下方式验证结论:
- 用
openssl s_client -connect 你的域名:443命令查看新旧证书的链结构,对比旧证书的中间证书是否存在于系统信任库中。 - 手动将新证书对应的中间证书安装到测试设备,再调用API,如果能正常运行,就说明问题确实出在缺失的中间证书未被系统信任。
内容的提问来源于stack exchange,提问作者Santacrab
相关产品推荐
相关产品推荐

