命令行工具

unable to load certificate:OpenSSL 证书格式不对怎么办

作者: · 最后核实

报错信息unable to load certificate ... error:0909006C:PEM routines:get_name:no start line ... Expecting: TRUSTED CERTIFICATE

unable to load certificate 的意思是:你给 OpenSSL 的文件里,没有它期望的 PEM 格式证书。 证书本身通常没问题,只是格式不同(DER、PKCS#7、PKCS#12),或者用错了文件(私钥、CSR),或者 PEM 文本在复制时被破坏了。

快速修复

修法是先认出文件格式,再用对应的命令转成 PEM。先看文件到底是什么:

file cert.crt
head -c 64 cert.crt | xxd | head -3
grep -- "-----BEGIN" cert.crt

再用对应的命令:

看到的内容 格式 命令
-----BEGIN CERTIFICATE----- PEM 证书 检查是否损坏(见下文)
二进制,以 30 82 开头 DER 证书 openssl x509 -inform DER -in cert.crt -out cert.pem
-----BEGIN PKCS7----- 或 .p7b PKCS#7 证书包 openssl pkcs7 -print_certs -in cert.p7b -out chain.pem
二进制 .pfx / .p12 PKCS#12 openssl pkcs12 -in cert.pfx -nokeys -out chain.pem
BEGIN PRIVATE KEY / CERTIFICATE REQUEST 不是证书 换成正确的文件

各种格式和转换方法见 SSL 格式转换工具。

原因

前 3 种是证书用了 PEM 以外的格式,后 3 种是用错文件、PEM 文本损坏和 OpenSSL 1.1.1 的提示写法。

1. 证书是 DER 编码

Windows 导出时选了“DER 编码二进制 X.509”(DER 是二进制编码),Java 工具和部分 CA 也会给二进制证书,扩展名常常是 .cer 或 .crt。

  • 确认: grep BEGIN 什么都找不到;openssl x509 -inform DER -in cert.crt -noout -subject 能正常输出。
  • 修复: 用表格里的命令转成 PEM。

2. 是 PKCS#7 证书包

PKCS#7 的 .p7b / .p7c 文件只装证书不装私钥,Windows 和一些 CA 平台常用这种格式。

  • 确认: 文件以 -----BEGIN PKCS7----- 开头;或者是二进制,openssl pkcs7 -inform DER -in file -print_certs 能用。
  • 修复: 用 -print_certs 导出,给 Web 服务器用时站点证书放最前,中间证书在后。

3. 是 PKCS#12 文件

PKCS#12 的 .pfx / .p12 文件同时包含私钥和证书,有密码保护。阿里云、腾讯云下载 IIS 或 Tomcat 格式时拿到的就是它。

  • 修复: 证书用 openssl pkcs12 -in cert.pfx -nokeys -out chain.pem,私钥用 -nocerts -nodes -out key.pem。用旧算法(如 RC2)生成的文件,在 OpenSSL 3 上可能需要加 -legacy。更省事的办法是在云控制台直接下载 Nginx 或 Apache 格式。

4. 用错了文件

把私钥、CSR 或公钥文件传给 openssl x509,报错相同。

  • 确认: grep BEGIN 显示 PRIVATE KEY、CERTIFICATE REQUEST 或 PUBLIC KEY。
  • 修复: 换成证书文件;查看 CSR 用 openssl req -in file -noout -text。

5. PEM 文本被破坏

从邮件、微信、网页上复制,可能多了空格、行被合并、BEGIN/END 行丢了,或者加了 UTF-8 BOM、Windows 换行符。

  • 确认: cat -A cert.pem | head 能看到 ^M 或奇怪字符;BEGIN 行的横线数量不对或多了空格。
  • 修复: 执行 dos2unix,去掉 BOM,确认每行 64 个 base64 字符,或者重新下载文件。

6. Expecting: TRUSTED CERTIFICATE

这只是 OpenSSL 1.1.1 的 openssl x509 在找不到可用内容时,报出它在找的 PEM 类型名。它同样接受普通的 BEGIN CERTIFICATE 块,所以这句话并不表示你需要一种特殊的“受信任证书”,原因仍是上面几条之一。

各环境修法

各环境最后都要得到 PEM 文件,Nginx、Apache 和宝塔只接受 PEM。

Windows: 证书导出向导里选“Base64 编码 X.509 (.CER)”,直接得到 PEM。

Java: keytool -exportcert -rfc -alias 名称 -keystore store.jks 输出 PEM;不加 -rfc 输出的是 DER。

Nginx / Apache / 宝塔: 只接受 PEM。先转换,再让 ssl_certificate / SSLCertificateFile 指向 PEM 证书链;宝塔里粘贴的也必须是 PEM 文本。

在 Windows 上转换: 没有装 OpenSSL 的 Windows 电脑,可以用 Git for Windows 自带的 openssl,或者在 WSL 里执行上面的命令;也可以在证书管理器(certmgr.msc)里重新导出为 Base64 格式。

Kubernetes: TLS Secret 里存的是 PEM 内容的 base64;把 DER 文件 base64 后放进去,控制器加载不了。

不要这样做

下面 3 种做法解决不了格式问题,其中一种还会泄露私钥。

  • 把扩展名改成 .pem 就指望能用。 扩展名改变不了编码。
  • 因为一个文件加载不了,就重新生成私钥和证书。 转换现有文件即可,很少需要重新签发。
  • 把 .pfx 和它的密码通过同一个渠道发送。 里面有私钥。

常见问题

怎么快速区分 PEM 和 DER?

PEM 是文本,开头是 -----BEGIN CERTIFICATE----- 这样的行;DER 是二进制,head -c 2 file | xxd 通常显示 3082,这是 ASN.1 长序列的开头。扩展名(.crt、.cer)不能说明编码方式。

CA 发来一个 .p7b 文件,里面有哪些证书?

PKCS#7 是一个容器,可以装站点证书和中间证书。openssl pkcs7 -print_certs -in bundle.p7b 会以 PEM 格式列出它们;如果 .p7b 是二进制,加 -inform DER。

能把证书贴到在线工具里看吗?

证书是公开信息,可以。证书解析工具支持粘贴 PEM 文本。但私钥绝不要粘贴到任何网站。

资料来源

  1. OpenSSL openssl-x509
  2. OpenSSL openssl-pkey
  3. RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures