同样的 ca.crt 文件名,不同的证书:该比较什么
两个配置文件可能带着内容不同的 ca.crt。给进程实际加载的证书取指纹,然后确认它是你预期的信任锚。
两个配置文件都带有一个名为 ca.crt 的文件,一条隧道能建立,另一条却因链错误失败。把两个文件并排打开很少能得出结论,而关闭验证则会把结论带向错误方向。错误真正问的问题更窄:每个进程把哪张证书当作自己的信任锚加载,两者是否同一个对象?先回答这一点,其余诊断才有方向。文件名只是打包标签,配置里写的路径也不权威,所以一切都取决于进程实际读取的内容。
找出客户端实际加载的证书
OpenVPN 以两种形式接受认证机构,形式决定哪些字节重要。配置可以用 ca 指向外部文件,也可以把证书嵌入配置自身的 <ca> 块中。两者同时存在时,嵌入的块胜出,配置旁边的文件永远不会被打开。
先读失败的配置,在比较任何东西之前弄清它用的是哪种形式。从相邻目录或另一个配置来源的安装包中取来的副本,不能说明这个进程信任什么。配置中的路径同样如此:它相对于客户端启动的位置解析,而那不一定是你正在看的目录。读配置,不要读文件夹。
证书由内容识别:公钥、主体与颁发者、有效期,以及覆盖这一切的签名。字节相同的两个文件无论叫什么都是同一张证书,而同名的两个文件可能毫无关系。名字是打包标签,不是身份。
用 openssl 给两份副本取指纹
指纹是对证书 DER 编码的哈希,也就是签名覆盖的形式,因此行尾和头部文本不会影响它。对每个文件计算一次,你会得到两个以冒号分隔的十六进制字符串,要么相同,要么不同。回答比较问题不需要读证书里的其他内容。
openssl x509 -in /etc/openvpn/office/ca.crt -noout -fingerprint -sha256
openssl x509 -in ~/profiles/lab-ca.pem -noout -fingerprint -sha256
把 openssl 指向配置本身很诱人,但它读的是文件中出现的第一个证书块,而配置通常先有 <cert>、后有 <ca>。先抽出认证机构块,再对抽出的文件取指纹,因为那才是客户端真正会用的副本。
sed -n '/^<ca>$/,/^<\/ca>$/p' office.ovpn | sed '1d;$d' > /tmp/office-ca.pem
openssl x509 -in /tmp/office-ca.pem -noout -fingerprint -sha256
指纹相同意味着信任材料相同,链错误另有原因,那是另一项调查。指纹不同意味着证书不同,下一节就从这里开始。
在假定遭受攻击之前先读差异
指纹不同只意味着证书不同,仅此而已。重新签发、轮换、更名机构或过期包都会产生历史完全合法的不同文件。哪一份属于部署,要问运维人员或部署记录,而不是看文件的修改时间。归档会复制时间戳,所以更新的文件并不自动是正确的锚。
自签名根证书是正常的,找到一张并不构成问题的证据。验证者的任务是从服务器证书构建一条通向交给它的锚的路径,链错误通常意味着这条路径无法走完。
检查失败配置的锚是不是部署仍在签发的机构。如果指纹在部署记录里对不上任何一条,配置就是过时了,客户端侧的任何调整都修不好。
在不关闭验证的前提下修复信任
短期修法是关闭验证,或者把链上的每张证书都加为锚。两者都会让报错消失,也都会改变客户端此后接受哪些服务器。重新打开验证,安装正确的锚,再测一遍。
如果链现在能建起来,但出现了别的错误,那是进展:名称验证、有效期和吊销是彼此独立的检查,各有各的报错。把指纹对和原始错误文本一起放进工单,下一个人就能看到加载的是哪个锚、预期的是哪个。一对指纹小到可以贴进交接备注,下次再遇到时五分钟就能解决,而不是耗掉一下午。
通过与交付配置相同的已认证渠道取得正确的机构。因为主体看着眼熟就从服务器上拽一张证书是另一回事,它会悄悄扩大客户端愿意信任的范围。