PEM(Privacy-Enhanced Mail)是 OpenSSL 和大多数 Linux/Unix 系统中最常用的证书和私钥格式。理解 PEM 的内部结构有助于排查格式转换问题、编写自动化脚本,以及深入理解 PKI 工作原理。
PEM 格式概述#
PEM 是一种基于 Base64 编码的格式,用于存储DER编码的二进制数据。其核心特点:
- 文本友好:内容为可打印的 ASCII 字符,便于复制粘贴
- 结构化:使用
-----BEGIN xxx----- 和 -----END xxx----- 标记包裹
- Base64 编码:将 DER 二进制数据转换为 ASCII 字符
PEM 文件结构#
典型的 PEM 文件结构如下:
1
2
3
4
|
-----BEGIN TYPE-----
Base64 编码的 DER 数据
(每行 64-76 字符)
-----END TYPE-----
|
实际示例:X.509 证书#
1
2
3
4
5
6
|
-----BEGIN CERTIFICATE-----
MIIC/zCCAeegAwIBAgIUE7Few6gydfFoBDQ+1aAHba6absYwDQYJKoZIhvcNAQEL
BQAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNjA3MTYxNjA4MDFaFw0yNjA3MTcxNjA4
MDFaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
...
-----END CERTIFICATE-----
|
实际示例:私钥(PKCS#8 格式)#
1
2
3
4
5
6
|
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDwyIPC1HgFgg7v
RcV/Lbxy/zb7j2hVcnZgOjg5sb6HbTLa18MfoFDhQzOfyYwTlrcE2MdUhST9VyDa
4Y+iWxY3XL6xZHaNNf7s0bWgxUwc2Z9sx2hCBaHP7zndwipcgE1n4BH82sRTtCbn
...
-----END PRIVATE KEY-----
|
实际示例:PKCS#1 格式 RSA 私钥#
1
2
|
# 使用 -traditional 参数生成
openssl genrsa -traditional -out key.pem 2048
|
1
2
3
4
5
|
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvT0G582+zwdzDDHH9oCOprlkyB1htiKySMWvxR30CZHeUhlF
Qr37x0WxG9Fa6XJPWN8mOV1jLFRvORhizynQsss8O/XdUsOVwEwlY0UgEzvuG0hd
...
-----END RSA PRIVATE KEY-----
|
实际示例:证书签名请求(CSR)#
1
2
3
4
5
|
-----BEGIN CERTIFICATE REQUEST-----
MIICZjCCAU4CAQAwITENMAsGA1UEAwwEVGVzdDEQMA4GA1UECgwHVGVzdE9yZzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPDIg8LUeAWCDu9FxX8tvHL/
...
-----END CERTIFICATE REQUEST-----
|
实际示例:PKCS#7 / CMS 签名数据#
1
2
3
4
5
|
-----BEGIN PKCS7-----
MIIFeAYJKoZIhvcNAQcCoIIFaTCCBWUCAQExDzANBglghkgBZQMEAgEFADALBgkq
hkiG9w0BBwGgggMDMIIC/zCCAeegAwIBAgIUE7Few6gydfFoBDQ+1aAHba6absYw
...
-----END PKCS7-----
|
Base64 编码与 DER 的关系#
PEM 实际上是 DER 格式的 Base64 表示。让我们验证这个关系:
1
2
3
4
5
6
7
8
|
# 查看 PEM 文件大小
$ ls -l server.crt
-rw-r--r-- 1 root root 1099 Jul 17 00:08 server.crt
# 提取 Base64 内容并解码,对比 DER 大小
$ cat server.crt | sed -n '/-----BEGIN/,/-----/p' | \
grep -v "BEGIN\|END" | base64 -d | wc -c
771
|
结论:PEM 文件(约 1099 字节)比原始 DER 数据(约 771 字节)大约 43%,这是 Base64 编码的开销(每 3 字节变成 4 字符)。
解码验证#
1
2
3
4
5
|
# 将 PEM 解码为 DER 格式
openssl x509 -in cert.pem -outform DER -out cert.der
# 使用 openssl asn1parse 解析 DER 内容
openssl asn1parse -in cert.der -inform DER
|
输出示例:
1
2
3
4
5
|
0:d=0 hl=4 l= 767 cons: SEQUENCE
4:d=1 hl=4 l= 231 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: INTEGER 02:03:01:02
11:d=2 hl=2 l= 20 cons: INTEGER 13:B1:5E:C3:A8:32:75:F1:68:04:34:3E:D5:A0:07:6D:AE
...
|
常见的 PEM 类型标识#
| 类型标识 |
内容 |
OpenSSL 命令 |
CERTIFICATE |
X.509 证书 |
openssl x509 |
CERTIFICATE REQUEST |
CSR |
openssl req |
RSA PRIVATE KEY |
PKCS#1 RSA 私钥 |
openssl rsa -traditional |
PRIVATE KEY |
PKCS#8 私钥 |
openssl pkcs8 |
ENCRYPTED PRIVATE KEY |
加密的 PKCS#8 私钥 |
- |
PKCS7 |
PKCS#7 签名数据 |
openssl smime |
CMS |
CMS 签名数据(PKCS#7 的 RFC 名称) |
openssl cms |
EC PARAMETERS |
EC 曲线参数 |
openssl ecparam |
DH PARAMETERS |
DH 参数 |
openssl dhparam |
多证书 PEM 文件#
PEM 格式支持在一个文件中包含多个证书(证书链):
1
2
3
4
5
|
# 创建证书链文件
cat server.crt intermediate.crt root.crt > chain.pem
# OpenSSL 可以正确读取
openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt
|
文件结构示例:
1
2
3
4
5
6
7
8
9
|
-----BEGIN CERTIFICATE-----
[服务器证书]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[中间证书]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[根证书]
-----END CERTIFICATE-----
|
格式转换实战#
DER 转 PEM#
1
2
3
4
5
|
# 证书 DER -> PEM
openssl x509 -in cert.der -inform DER -out cert.pem
# 私钥 DER -> PEM (PKCS#8)
openssl pkcs8 -topk8 -inform DER -in key.der -out key.pem
|
PEM 转 DER#
1
2
3
4
5
|
# 证书 PEM -> DER
openssl x509 -in cert.pem -outform DER -out cert.der
# 私钥 PEM -> DER
openssl pkcs8 -topk8 -in key.pem -outform DER -out key.der
|
PKCS#1 与 PKCS#8 私钥互转#
1
2
3
4
5
|
# PKCS#1 (RSA PRIVATE KEY) -> PKCS#8 (PRIVATE KEY)
openssl pkcs8 -topk8 -in key-pkcs1.pem -out key-pkcs8.pem
# PKCS#8 -> PKCS#1 (使用 -traditional)
openssl rsa -in key-pkcs8.pem -traditional -out key-pkcs1.pem
|
加密与解密私钥#
1
2
3
4
5
|
# 加密私钥(AES-256-CBC)
openssl pkcs8 -topk8 -in key.pem -out key-encrypted.pem -v1 PBE-SHA1-3DES
# 解密私钥
openssl pkcs8 -topk8 -in key-encrypted.pem -out key-decrypted.pem
|
查看 PEM 文件信息#
方法一:使用 openssl#
1
2
3
4
|
# 自动检测格式并显示
openssl x509 -in cert.pem -noout -text
openssl rsa -in key.pem -noout -text
openssl req -in req.pem -noout -text
|
方法二:提取并解码 Base64#
1
2
3
4
5
6
7
|
# 提取 Base64 内容
sed -n '/-----BEGIN/,/-----/p' input.pem | \
grep -v "BEGIN\|END" | base64 -d > output.der
# 手动检查文件类型
file output.der
# 输出: output.der: X.509 certificate
|
方法三:检查文件头#
1
2
3
|
# 快速检查 PEM 类型
head -1 input.pem
# 输出: -----BEGIN CERTIFICATE-----
|
常见问题排查#
问题 1:PEM 格式不被支持#
某些应用需要特定格式(如 Apache 旧版本需要 PKCS#1):
1
2
3
4
5
|
# 检查当前格式
head -1 yourkey.pem
# 如果是 PKCS#8,转换为 PKCS#1
openssl rsa -in yourkey.pem -traditional -out legacy-key.pem
|
问题 2:证书链顺序错误#
验证失败可能是证书顺序错误:
1
2
3
4
|
# 正确顺序:服务器证书 -> 中间证书 -> 根证书
# 检查当前顺序
openssl crl2pkcs7 -nocrl -certfile CHAIN.pem | \
openssl pkcs7 -print_certs -noout
|
问题 3:Base64 解码失败#
检查 PEM 文件是否有非法字符:
1
2
|
# 检查非 Base64 字符
grep -vE '^[A-Za-z0-9+/=]+$' your.pem
|
| 特性 |
说明 |
| 编码方式 |
Base64 |
| 原始格式 |
DER(ASN.1 编码的二进制) |
| 文件扩展名 |
.pem, .crt, .cer, .key, .csr |
| 多证书支持 |
是(串联存放) |
| 加密支持 |
是(通过 PKCS#8 加密私钥) |
理解 PEM 格式的内部结构,能够帮助你在遇到证书相关问题时快速定位根因,特别是在处理格式转换和证书链验证场景时。
参考来源: