自签名客户端证书?VPN 服务器仍然拒绝
客户端证书必须能链接到服务器信任的 CA,而自签名证书永远做不到。下面说明 CSR 能做什么,以及应当索取什么。
运维方给了一个地址和一个用户名,客户端则要求提供 CA 文件、证书和私钥。在本地生成这三样东西似乎是理所当然的下一步。结果得到的是一张只有你自己的机器才相信的证书。服务器的信任锚定在你无法控制的 CA 上,因此握手还没开始就已经结束。
信任在服务器上,不在你的配置里
证书认证是一次比对。客户端出示证书;网关检查它是否由其配置中某个 CA 签发。
你的配置指定客户端用来验证服务器的 CA 文件。它无法指定服务器应该用哪个 CA 来验证你。配置的那一半不归你管。
自己制作的证书即便在技术上完美无缺,也过不了这次比对。它有有效的签名、主体和有效期,但签发者是一个网关从未听说过的 CA。错误出现在握手过程中,而且是在服务器已经请求证书之后。客户端配置里没有任何东西能改变这个答案。
为什么自签名证书不能替代
自签名证书由它自己的密钥签发。签名针对同一个文件验证,因此它自洽,但作为别人网关的凭证毫无用处。
网关并不过问证书内部是否自洽。它问的是,这张证书是否由受信任的签发者签发。
这就是错误信息令人困惑的原因。客户端可能报告一个听起来像服务器故障的验证失败,而服务器记录的是未知签发者。两者从相反的两端描述同一个不匹配。
走 CSR 这条路可以保住你的私钥
大部分工作仍然可以在本地完成。生成一对密钥,围绕公钥那一半构造证书签名请求,再把请求发给运维方。离开你机器的只有请求本身。私钥那一半留在原处。
openssl req -new -newkey rsa:3072 -nodes -keyout client.key -out client.csr -subj "/CN=laptop-01"
运维方用自己的 CA 签署请求并返回证书。你的私钥从未离开,结果也能链接到网关信任的锚点。
托管服务常常跳过 CSR,直接下发整个包。当同一家提供商本来就负责隧道终结并持有 CA 时,这是合理的交换。把私钥留下并不会改善保管,因为提供商随时可以重新签发一把。
配置包是导入的,不是安装的
名字听起来很安全的厂商包往往是 OpenVPN 配置。它们包含配置,有时也包含证书,但不会安装任何东西。把文件导入支持该协议的客户端,连接就配置好了。
处理规则取决于内容。如果配置内嵌了私钥,它就是凭证,值得像密码一样对待:不要发邮件、不要进仓库、不要放在共享下载目录。当运维方分别提供 ca.crt、client.crt 和 client.key 时,把它们放在一起并设置严格权限,让配置指向它们。
补上运维方可能省略的检查
路由器生成的配置有时缺少对端校验。remote-cert-tls server 要求对端证书带有服务器认证用途,这样客户端证书就无法被当作服务器重放。这一行是改动很小、理由充分的设置。
当运维方能给出预期主体或 SAN 时,verify-x509-name 可以更进一步。两者都是对配置的小补充,也都站得住脚。导入之前先检查你拿到的东西。
openssl x509 -in client.crt -noout -issuer -subject -dates
openssl verify -CAfile ca.crt client.crt
校验设置不是对断裂链条的修复。如果签发者不对,答案应该是来自正确 CA 的证书,而不是关掉检查的开关。关闭校验只是把认证失败变成未被发现的失败。
一次要齐:PEM 格式的 CA 证书、由该 CA 签发的客户端证书、你自己生成或通过可信渠道拿到的私钥,以及证书应当出示的确切服务器名。在同一条消息里记下到期日,因为过期的证书几个月后看起来就像网络故障。