一个同时要求用户证书和 CA 证书的 Android IKEv2 界面,看起来像是把同一件事问了两遍。并非如此。IKEv2 在同一次交换中、沿两个方向认证双方,而手机在每个方向上扮演不同角色:它必须证明自己是谁,也必须决定信任哪个网关。用户证书回答第一个问题,受信任的 CA 回答第二个问题,两者谁也替代不了谁。

同一次交换中的两个认证方向

IKEv2 分两个阶段建立控制通道。第一次交换协商算法与密钥;第二次即 IKE_AUTH,携带双方各一个 AUTH 负载,以及各自的身份。该负载是对整次交换计算的签名或 MAC,并用接收方已经信任的东西来验证。

网关用自己的证书证明身份,手机则把该证书的链条验证到一个它愿意信任的根,然后检查证书中的身份是否与它打算连接的网关一致。手机用自己的凭据证明身份,网关用签发客户端证书的 CA 来验证它。

这就是两个字段背后的全部机制。用户证书是手机关于自身的一项声明;CA 字段则是关于它会相信谁的声明。只有其中一个而缺另一个的配置无法完成双向认证,重试多少次都改变不了这一点。两种失败看起来甚至不同:缺少用户密钥时手机根本无法生成签名,而缺少信任锚时它无法接受网关的证书。

MaterialRoleWhat it cannot do
User certificate plus its private keyProves possession of the enrolled client identityEstablish that the gateway is the right one
Trusted CA certificateValidates the gateway chain under the intended identity checksProve the client's identity to the gateway
Expected gateway identityPins which server the phone acceptsGrant that user access to every private resource

Android 配置构建器要求什么

Google 的 IKEv2 配置构建器 把每种认证方法分别暴露出来,而不是合并成一个证书模式。数字签名方法需要用户证书、私钥和服务器根 CA。其他方法需要用户名和密码,或预共享密钥。

请仔细读这一签名,因为它编码了上面的机制。用户名和密码方法中没有用户私钥的字段,PSK 方法中也没有网关信任锚的字段,原因很简单:这些方法证明的是不同的事情。把密码粘贴到证书字段里把两者混在一起,得到的配置会在 IKE_AUTH 失败,而报错信息不会点名其中任何一个。

数字签名方法记录的私钥类型是 RSA。标有 IPsec 或证书的菜单并不意味着支持 ECDSA;基于它支持这一假设搭出来的配置,在网络还没参与之前就会在平台 API 上失败。

为什么只有公开的用户证书还不够

AUTH 负载是用客户端私钥对整次交换做出的签名。持有公开证书能让网关校验签名;对手机毫无帮助,因为它需要私钥才能生成签名。只导入 .crt 而 把私钥落下,是这类失败中最常见的一种。

Android 的密钥基础设施正反映了这一点。选择客户端身份要经过 KeyChain,它要求访问相应的私钥,而不只是一条证书条目。把两者一起安装的注册包或设备管理工作流,才是获得可用身份的常规方式;手工复制一个证书文件通常不是。

所以配置里的这两项并不是一个证书包和它的副本。一项是平台必须能用来签名的密钥对,另一项是平台用来比对的信任锚。把两者当作两个独立事实来检查:这个配置能签名吗?它知道该信任谁吗?

信任锚属于应用,而不属于手机

把根证书装进用户存储并不会让每个 Android 应用都信任它:从 Android 7 起,应用必须通过网络安全性配置主动选择加入,而在该版本之前,用户安装的 CA 被接受的范围要宽得多。应用的信任配置可能各不相同,管理自己信任材料的 VPN 客户端甚至可能根本不看用户存储。这就是同一个 CA 文件在一个客户端里可用、在另一个里却像被忽略的原因。

于是有两种归属模型。系统托管的 VPN 配置使用设备的证书安装或管理员注册流程,配置随后引用预期的 CA。应用托管的 VPN 保留自己的信任材料,使用自己文档化的导入流程,它可能与 Android 设置界面完全无关。修复断链的地方也在这里:系统托管的情形在 CA 存储和配置选择中,应用托管的情形在客户端自己的导入界面上。

在导入任何东西之前先确定自己处于哪种模型,然后确认当前配置的信任选择。如果运维方的说明与客户端菜单不一致,对那次安装而言以客户端文档化的行为为准,但 CA 仍必须通过你能验证的渠道来自运维方。文件名并不能证明是谁签发的。

先选模式,再选文件

证书模式需要客户端密钥对、网关侧的签发 CA、用于网关证书的信任锚,以及对这张证书必须携带哪个身份的预期。用户名和密码模式用凭据替代客户端密钥对,但保留对网关的信任要求。PSK 模式用共享密钥替代两者,它改变的是信任模型,而不是简化它。

无论选哪种,都保持常规校验开启。客户端若提供不校验选项,它取消的正是 CA 字段存在的意义;它并不能修复缺失的信任锚。仅仅因为连接在没有校验时也能工作就接受任何服务器证书,也是同样的问题。

然后在正确的地方验证:导入材料,连接一次,并在客户端的连接详情中确认网关身份正是你预期的那个,且配置报告的正是你打算使用的认证方法。用错方法却连接成功,是一个你还没弄懂的配置,等运维方下次收紧策略时它就会失败。

相关文章