DH 文件还是 tls-auth 密钥?分清两个 OpenVPN 文件
一个文件保存公开的组参数,另一个是共享的机密材料。三个条件决定各自属于哪条指令。
两个文件、两条指令,再加上“按它配置的东西来命名”的习惯。于是 dh.pem 被塞进 tls-auth 那一行,客户端就带着“意外的密钥格式”报错失败。你面前要决定的不是哪个文件更强,而是部署真正需要哪个角色;三个条件就能定下来:你的 TLS 栈将协商哪种密钥交换、你到底要不要控制通道认证、以及这份材料是否必须保密。
按顺序回答这三问,文件问题自然有答案。跳过它们,指令名就开始看起来可以互换,而这正是此类错误的来源。
先读标签,再看文件名
文件第一行比文件名更能说明问题,因为名字只是人的习惯,而标签是工具生成的。Diffie-Hellman 参数带有 BEGIN DH PARAMETERS 这一 PEM 标签;OpenVPN 静态密钥则是完全不同的结构,有自己的头部和十六进制载荷。
改名不能完成任何转换。叫 ta.key 的参数文件仍然是参数,叫 dh.pem 的静态密钥仍然是静态密钥;解析器读的是内容,对不上就拒绝。改配置之前先查一下:
head -n 1 dh.pem
head -n 1 ta.key决定你需要哪个文件的三个条件
第一个条件是密钥交换。有限域 Diffie-Hellman 握手需要一组参数,而 dh 指令正是服务器为它指定参数的地方。椭圆曲线握手根本不需要那个文件,因为曲线本身就是参数集。如果你的服务器只协商 ECDHE 套件,DH 文件就是死重,而不是额外强度。
第二个条件是控制通道认证,它是独立功能,有自己的材料。tls-auth 文件是双方共有的静态密钥,用来给控制通道数据包签名,使未通过认证的一方连握手都无法完成。它与你是否使用有限域 DH 无关,与组参数也没有关系。
第三个条件是保密与分发。DH 参数可以公开而不削弱会话,因为秘密值每次握手都会重新生成,且从不离开双方。而静态密钥绝不能公开:两端是同一串字节,它不会自行轮换,任何持有者都能生成有效的控制通道签名。这两个答案指向完全不同的处理规则,所以一个文件可以放进仓库,另一个不行。
为每个角色生成正确的材料
用能生成指令所需格式的工具,而不是在两种格式之间转换。对 OpenVPN 2.6 的共享密钥来说,生成器的带类型写法会明确写出用途。
openvpn --genkey tls-auth ta.key这条命令只生成新的机密材料;它既不修复也不检查已有密钥,再运行一次会得到别人没有的另一把密钥。请用你处理任何共享机密时会用的通道,把生成的文件复制给需要的对端,并保持方向约定一致:使用 tls-auth 时,一侧用 key-direction 0,另一侧用 key-direction 1。
需要 DH 参数时,它来自参数生成而不是密钥生成器;即使输出是公开的,来源也很重要。从不明来源取来的组不会因为公开就变得可信;它仍必须是各方都认可的组,且不能因尺寸或构造而变弱。
dh none 意味着什么、不意味着什么
dh none 是一条含义很窄的真实指令:不会加载任何有限域参数文件,因为握手使用椭圆曲线 Diffie-Hellman。它不是“跳过 DH 步骤”的简写(那会暗示削弱什么),更不是让 OpenVPN 接受别的文件来替代。
误读会带来两个错误。其一,以为 dh none 取消了 tls-auth 的必要性,其实两者管的是不同的事。其二,在只有曲线的配置旁留着过时的 dh 行,然后纳闷服务器到底在用哪个文件;只要指令在,文件就会被读取,那里路径坏了就会让启动失败,而原因与将要协商的密钥交换无关。
如果错误文件已经上线
从配置所有者那里恢复本该使用的机密,同时不要改动证书验证。这是格式不匹配,不是信任失效;为了绕过报错而关闭验证,等于把启动问题换成一个安静的问题。
然后把人们常混为一谈的两种事故分开。公开 DH 参数文件几乎无害,因为这些参数本来就是公开的。泄露 tls-auth 密钥则是另一回事:它要为每个持有者认证控制通道数据包,所以更换必须在整个部署中协调,而不是只在一台主机上处理。
五分钟检查就能判断你属于哪种情况:读每个文件的第一行、确认引用它的指令、再确认分发方式符合材料的要求。这比重新生成一套可用的 PKI 工作量小,也正是那三个条件一直指向的结论。