导入因证书错误而失败,于是最直观的做法看起来就是转换。这个直觉把人带上一条路:文件扩展名变了,拒绝却一模一样。authorized_keys 里的 ssh-ed25519 行和 OpenVPN 客户端证书是两类不同的凭据对象,签发者不同、编码不同、吊销路径也不同。按顺序走完这些检查,一分钟内就能判断转换到底有没有用。

你手里究竟是哪一个对象?

人们称为密钥的东西有五种,只有一种是 TLS 配置文件真正需要的。SSH 公钥是一行文本,带类型前缀和 base64 载荷。OpenSSH 证书是这把公钥加上签名、principals 和选项,由 ssh-keygen 充当自己的小型 CA 生成。X.509 证书则是完全不同的结构,携带主体、有效期、扩展以及来自证书颁发机构的签名。私钥是保密的那一半,而签发的捆绑包通常是证书、证书链和私钥合在一个文件里。

第一个测试只花一条命令。让 openssl 指向该文件,请它解析证书结构:

openssl x509 -in client.crt -noout -subject -issuer

如果它以无法加载或 PEM 错误失败,那么无论你把它命名成什么,该文件都不是 X.509 证书。改名不会重写内部的 ASN.1,把公钥行包进 PEM 头文本同样不会。

配置文件到底要不要证书?

客户端证书只是若干身份验证方式之一,许多能正常工作的 TLS 配置文件从不索要它。服务器可以通过插件、用户名加密码或令牌后端验证用户,同时仍要求客户端验证服务器身份。如果配置里没有客户端证书指令,就永远不会索要证书,任何转换也无法让网关开口要一个。

更早的静态密钥配置又是第三种情况。它早于 TLS 握手,期待的是预先共享的密钥文件,所以把公钥粘进那个字段同样行不通。在断定凭据有误之前,先读懂配置文件究竟要什么。

重新编码能做什么、不能做什么

私钥确实有正当的替代容器。同一把 RSA 或 EC 密钥可以写成传统的 PEM、PKCS#8,或放进 PKCS#12 捆绑包,工具之间也乐于互相转换。公钥的故事类似:ssh-keygen 能输出 SSH 密钥的 RFC 4716 形式,OpenSSH 也认得它自己的证书格式。这些全都是表示形式,而表示形式不等于信任。

转换做不到的是:让一个从未见过你这把密钥的证书颁发机构凭空产生签名。证书是签发者的一项断言——某把公钥属于某个主体、用于某个用途。重新编码保留了密钥的字节,却让这项断言缺席,于是网关没有任何东西可以拿它的信任库去校验。

大多数尝试就是在这里悄悄失败的:文件现在以 .crt 结尾,客户端读它时也不报错,握手却仍然中止,因为 对端无法构建到可信签发者的证书链。

证书颁发机构在何处登场

真正的注册从你掌控的密钥对开始,并提交一份携带运维方所期待主体的证书签发请求。运维方核验资格后,用 CA 密钥对请求签名,把签发的证书连同客户端必须出示的任何中间链一起返回。随后客户端需要那张为它签名的 CA 证书,因为正是它让客户端能够确认:自己正在对话的服务器属于同一套部署。

最后这个文件极易被遗忘,也完全无法替代。CA 的签名密钥本身从不属于客户端配置,任何本地转换都造不出你本该收到的那条链。

复用 SSH 密钥的代价

假设某次转换确实产出了可接受的东西。把同一对密钥同时用于 SSH 访问和 VPN 身份验证,仍然把两个独立的安全决策绑在一起。删掉 authorized_keys 里的一行会止住 SSH 登录,却对 VPN 的 CA 已经为同一把公钥签发的证书毫无作用。VPN 一侧要通过它自己的机制吊销,也就是证书吊销列表或运维方的注册记录。

所以清单的结尾是一个停止条件,而不是一个花招。如果 openssl 无法把文件解析为证书,就停止转换,并说明你手里是什么:SSH 密钥、SSH 证书、X.509 证书、私钥或捆绑包。如果配置文件不索要客户端证书,就停下来问服务器期待哪种身份验证方式。只有当两个答案都指向 X.509 时,注册才是下一步;而第一句话里用对名词,这场对话会快得多。

相关文章