格式转换与 PKCS#12
OpenSSL 证书格式转换:PEM、DER、P7B、PFX、JKS
证书格式之间的区别只在于“怎么包装同一份数据”:PEM 是 Base64 文本,DER 是二进制,PKCS#7 打包多张证书,PKCS#12 把私钥和证书打包在一起,JKS 是 Java 自己的密钥库。下面每种转换都是一条 openssl 或 keytool 命令,证书内容不会因此改变。OpenSSL 输出来自 3.6.1;本机没有 JDK,keytool 的输出是 JDK 17 以上版本的典型提示。
为什么会有这么多格式,见证书格式详解;PKCS#12 的参数和兼容性问题另有专页:PKCS#12 命令。不方便用命令行时,可以用在线格式转换工具,转换在浏览器本地完成。
判断文件是什么格式
先看第一行,二进制文件再用 file 或 asn1parse 确认。
head -1 server.crt server.key bundle.p7b server.csr
file server.der example.pfx
openssl asn1parse -inform DER -in example.pfx | head -3
==> server.crt <==
-----BEGIN CERTIFICATE-----
==> server.key <==
-----BEGIN PRIVATE KEY-----
==> bundle.p7b <==
-----BEGIN PKCS7-----
==> server.csr <==
-----BEGIN CERTIFICATE REQUEST-----
server.der: Certificate, Version=3
example.pfx: data
0:d=0 hl=4 l=1723 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :03
7:d=1 hl=4 l=1641 cons: SEQUENCE
| 第一行或内容 | 格式 | 常见扩展名 |
|---|---|---|
-----BEGIN CERTIFICATE----- |
PEM 证书 | .pem .crt .cer |
-----BEGIN PRIVATE KEY----- / RSA PRIVATE KEY / EC PRIVATE KEY |
PEM 私钥(PKCS#8 / PKCS#1 / SEC1) | .key .pem |
-----BEGIN ENCRYPTED PRIVATE KEY----- |
加密的 PKCS#8 私钥 | .key |
-----BEGIN PKCS7----- |
PEM 格式的 PKCS#7 证书包 | .p7b .p7c |
二进制,file 显示 Certificate |
DER 证书 | .der .cer |
二进制,asn1parse 先是 INTEGER :03 再是 pkcs7-data |
PKCS#12 | .pfx .p12 |
PKCS#12 文件以版本号 3 开头,asn1parse 就是靠这个和 DER 证书区分的。Windows 上没有 file 命令,可以用 Git Bash 或 WSL 执行。
PEM 转 DER
-outform DER 输出同一张证书的二进制编码。
openssl x509 -in server.crt -outform DER -out server.der
ls -l server.crt server.der | awk '{print $5, $NF}'
709 server.crt
483 server.der
去掉 Base64 后体积约为原来的四分之三。Windows、Java 和很多嵌入式设备、网络设备都接受 DER 格式的 .cer。一个 DER 文件只能装一张证书,证书链要逐张转换或者改用 PKCS#7。
DER 转 PEM
-inform DER 读取二进制输入,输出默认就是 PEM。
openssl x509 -in server.der -inform DER -out server.pem
head -1 server.pem
-----BEGIN CERTIFICATE-----
OpenSSL 3.x 多数情况下能自动识别 DER,但脚本里保留 -inform 以兼容 1.1.1。报 wrong tag 或 not enough data 时,文件多半是 PKCS#7 或 PKCS#12,而不是单张 DER 证书。
私钥在 PEM 和 DER 之间转换
用 openssl pkey,所有算法通用。
openssl pkey -in server.key -outform DER -out server.key.der
openssl pkey -in server.key.der -inform DER -out server.key.pem
head -1 server.key.pem
-----BEGIN PRIVATE KEY-----
输出是 PKCS#8;目标程序要 BEGIN RSA PRIVATE KEY 时加 -traditional。DER 私钥主要给 Java(PKCS8EncodedKeySpec)和部分硬件用,Web 服务器和宝塔面板都要 PEM。
PEM 转 PKCS#7(.p7b)
crl2pkcs7 -nocrl 把一张或多张 PEM 证书打成 PKCS#7 包。
openssl crl2pkcs7 -nocrl -certfile server.crt -certfile intermediate.crt -out bundle.p7b
head -1 bundle.p7b
-----BEGIN PKCS7-----
加 -outform DER 生成二进制 .p7b,Windows 导入更稳。PKCS#7 永远不含私钥;Windows/IIS 用它表示“证书链”,Tomcat 往已有密钥库导入 CA 回执时也接受它。
PKCS#7(.p7b)转 PEM
pkcs7 -print_certs 把里面每张证书都解成 PEM。
openssl pkcs7 -in bundle.p7b -print_certs -out chain.pem
# 二进制 .p7b
openssl pkcs7 -in bundle.p7b -inform DER -print_certs -out chain.pem
grep -E "^subject|^issuer" chain.pem
subject=CN=example.com
issuer=CN=Example Test Intermediate CA
subject=CN=Example Test Intermediate CA
issuer=CN=Example Test Root CA
subject=、issuer= 行是注释,Nginx 和 Apache 会忽略。当证书链用之前检查顺序:服务器证书必须排第一。
PEM 转 PFX(PKCS#12)
pkcs12 -export 把私钥、证书和证书链合成一个带密码的文件。
openssl pkcs12 -export -inkey server.key -in server.crt -certfile intermediate.crt \
-name "example.com" -out example.pfx
Enter Export Password:
Verifying - Enter Export Password:
IIS、Azure、Windows 证书导入和不少 Java 服务都要这个格式。OpenSSL 3.0 起默认用 AES-256-CBC 加密、SHA-256 做 MAC,Windows Server 2016 及更早版本、老版本 Java 和 macOS 可能导入失败,这时加 -legacy。详见 PKCS#12 命令。
PFX 转 PEM
pkcs12 -noenc 把私钥和全部证书写进一个 PEM 文件。
openssl pkcs12 -in example.pfx -noenc -out example-all.pem
grep -E "BEGIN|friendlyName|subject=" example-all.pem
Enter Import Password:
friendlyName: example.com
subject=CN=example.com
-----BEGIN CERTIFICATE-----
subject=CN=Example Test Intermediate CA
-----BEGIN CERTIFICATE-----
friendlyName: example.com
-----BEGIN PRIVATE KEY-----
-noenc(3.0 起,之前叫 -nodes)表示私钥不加密输出,不加会要求你再设一个 PEM 密码。报错里出现 unsupported 和 RC2-40-CBC,说明 PFX 用的是旧算法(比如从老版 Windows 导出),加 -legacy 即可。
把 PFX 拆成私钥、证书、证书链
用 -nocerts、-clcerts、-cacerts 分别取出 Web 服务器要的三个文件。
openssl pkcs12 -in example.pfx -nocerts -noenc -out example.com.key
openssl pkcs12 -in example.pfx -clcerts -nokeys -out example.com.crt
openssl pkcs12 -in example.pfx -cacerts -nokeys -out chain.crt
Enter Import Password:
Enter Import Password:
Enter Import Password:
加 -passin file:pass.txt 免去三次输入;云厂商 IIS 证书包里的 .txt 就是 PFX 密码。输出开头的 Bag Attributes 行无害,但宝塔面板等控制台可能不认,可以重写到新文件去掉它:openssl pkey -in example.com.key -out clean.key、openssl x509 -in example.com.crt -out clean.crt。
PFX 转 Java 密钥库(JKS)
keytool -importkeystore 把 PKCS#12 里的条目复制到 JKS。
keytool -importkeystore \
-srckeystore example.pfx -srcstoretype PKCS12 \
-destkeystore example.jks -deststoretype JKS
Importing keystore example.pfx to example.jks...
Entry for alias example.com successfully imported.
Import command completed: 1 entries successfully imported, 0 entries failed or cancelled
别名来自 PFX 的友好名(-name)。较新的 JDK 会警告 JKS 是专有格式:Java 9 起默认密钥库类型已是 PKCS12,Tomcat、Spring Boot、Jetty 都能直接加载 .pfx(keystoreType="PKCS12"),很多时候根本不需要 JKS。
JKS 转 PFX 和 PEM
反过来先用 keytool 转成 PKCS#12,再交给 OpenSSL。
keytool -importkeystore -srckeystore keystore.jks -srcstoretype JKS \
-destkeystore keystore.p12 -deststoretype PKCS12
openssl pkcs12 -in keystore.p12 -noenc -out keystore.pem
Importing keystore keystore.jks to keystore.p12...
Entry for alias tomcat successfully imported.
Import command completed: 1 entries successfully imported, 0 entries failed or cancelled
密钥库里有多个条目时用 -srcalias 只导出一个。keytool 的 PKCS12 密钥库只有一个密码,原 JKS 的私钥密码和库密码不同时,导出时会让你统一。
拼接 fullchain.pem
把服务器证书和中间证书按顺序拼起来,服务器证书在前,不放根证书。
cat example.com.crt intermediate.crt > fullchain.pem
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout
subject=CN=example.com
issuer=CN=Example Test Intermediate CA
subject=CN=Example Test Intermediate CA
issuer=CN=Example Test Root CA
Nginx 的 ssl_certificate、Apache 2.4.8 以上的 SSLCertificateFile、宝塔面板的“证书(PEM 格式)”框都填这个内容。顺序反了 Nginx 会报 key values mismatch;漏了中间证书,安卓、curl、Java 和微信小程序请求会报缺少中间证书。如果前一个文件末尾没有换行,cat 会把 -----END CERTIFICATE----------BEGIN CERTIFICATE----- 粘在一行,用 grep -c BEGIN fullchain.pem 数一下张数。
常见问题
.crt 文件是 PEM 还是 DER?
都有可能。.crt、.cer、.pem 这些扩展名只是习惯,不代表格式。用记事本打开或执行 head -1:以 -----BEGIN CERTIFICATE----- 开头的是 PEM,一堆乱码的是 DER。
云厂商下载的证书包里为什么有好几个文件夹?
阿里云、腾讯云等平台按服务器类型打包:Nginx 目录里是 PEM 格式的证书(通常已拼好中间证书)和私钥,Apache 目录把证书和链分成两个文件,IIS 目录是 .pfx 加一个密码文件,Tomcat 目录是 .jks 或 .pfx。选对文件夹就不用自己转换。
.p7b 能直接转成 .pfx 吗?
只有手里还有私钥才行。.p7b 里只有证书:先用 openssl pkcs7 -print_certs 取出 PEM,再用 openssl pkcs12 -export -inkey 你的私钥 生成 .pfx。