为什么 cryptoapicert 在 OpenVPN 3 和 Connect 于 Windows 上失败
该指令属于某一个 Windows 客户端,而不属于协议。核心库提供签名回调,前端则有各自的导入流程。
你把一个可用的 OpenVPN 2 配置文件复制到较新的 Windows 客户端,而旧客户端自己找到的那张证书不再被提供。让这件事成立的那一行是 Community 2 客户端专属的 Windows 选择器,而较新的应用是另一个程序,凭据路径也不同。配置文件除这一行之外没有任何变化,而正因如此,差异才难以察觉。
那份报告把三个层次混为一谈:Community 客户端、核心库,以及某人安装的前端。只有其中一个真正理解过这条指令。
这个选项在它存在的地方意味着什么
在 Windows 上的 Community OpenVPN 2 客户端里,cryptoapicert 指定客户端应在 Windows 证书存储区而不是文件中查找的证书。这是 Windows 专属的便利功能,之所以有效,是因为该客户端知道如何枚举存储区,并把得到的密钥交给自己的 TLS 栈。因此这条指令属于该客户端的配置语言,而不是 OpenVPN 协议的属性。传输格式中没有任何东西携带它。
把同一行复制到另一个应用,你就复制了一个新程序可能解析、忽略或拒绝的词。指令不是协议特性,这条甚至不是每个会说 OpenVPN 的客户端都具备的特性。
核心库转而提供什么
OpenVPN 3 Core 是一个被其他应用嵌入的库,它通过 API 而不是存储区查询来处理外部凭据。嵌入它的应用提供证书链,之后请求该库用外部密钥签名,库再回调应用来完成这件事。这是更通用的设计,也意味着由前端决定存在哪些提供者。在核心库自己的选项处理中,cryptoapicert 出现在未实现的指令之列,这与那样的职责划分相符。
这些回调的存在,并不意味着某个打包应用会枚举当前用户的个人存储区、支持某个特定的密钥提供者,或能完成智能卡提示。这些都属于前端的属性,每一项都必须由前端自行记录。
Windows 前端转而做什么
OpenVPN Connect 走的是另一条路:操作者 导入 PKCS#12 文件,该文件包含证书及其私钥,把它放进为此目的创建的 OpenVPN Certificate Store,然后把外部证书分配给配置文件。这是刻意的导入步骤,而不是自动发现个人存储区里恰好有什么。当有人以为为其他用途安装的证书会直接出现在客户端列表中时,这个区别就很重要。
导入对密钥策略也有影响,因为把密钥导出成 P12 文件,正是不可导出密钥所要阻止的事。这是策略问题而不是配置问题,在任何人尝试导入之前,它值得一个答案。
选择与密钥策略相符的路径
如果凭据可导出,且策略允许按文档导入,就使用组织受保护的注册流程,并把临时 P12 及其密码排除在日志和脚本之外。如果密钥绝不能离开智能卡或受保护的提供者,就选择明确支持该要求的客户端与提供者组合,或者针对你安装的版本向供应商取得确认。两条分支都不是另一条的绕行办法。
把指令加回配置文件,并不能提供该应用所没有的集成。更新的客户端版本也不一定会加上它,因为这种能力属于前端自身的设计。
本地密钥可用之后,服务器仍然检查证书身份、证书链和授权。可用的本地密钥与被接受的 VPN 身份是两个独立的结果,把它们分开,才能阻止前端的限制变成被削弱的证书策略。