openSSL介绍

OpenSSL 深度实战指南


1. 核心概念与文件后缀

在使用命令之前,必须理解 OpenSSL 操作的对象是什么。

后缀 全称 含义 内容
.key Private Key 私钥 包含私有密钥信息,绝密,用于解密或签名。
.csr Certificate Signing Request 证书签名请求 包含公钥和身份信息(CN, O 等),发送给 CA 进行签名。
.crt / .pem Certificate 证书 包含公钥、身份信息、CA 的签名、有效期等。通常是 PEM 编码。
.der Distinguished Encoding Rules 二进制证书 证书的二进制格式,无法直接用文本编辑器查看。
.pfx / .pkcs12 PKCS#12 证书包 包含证书链和私钥的加密打包文件,常用于 Windows/IIS/Java。
.cnf / .conf Configuration 配置文件 定义 OpenSSL 行为、扩展属性(如 SAN)的文件。

注意.pem 是一种编码格式(Base64 文本),.crt.key 文件内部通常也是 PEM 格式。可以用文本编辑器打开查看 -----BEGIN... 头尾。


2. 核心命令详解

OpenSSL 命令繁多,但证书管理主要围绕以下 4 个核心命令。

2.1 genrsa - 生成私钥

用于生成 RSA 算法的私钥。

1
openssl genrsa -out server.key 2048
  • -out: 输出文件路径。

  • 2048: 密钥长度。建议最低 2048,生产环境推荐 4096。

  • 进阶: 生成 ECC 密钥(性能更好,证书更短):

    1
    openssl ecparam -genkey -name prime256v1 -out server.key

2.2 req - 管理证书请求 (CSR) 和自签名证书

这是最常用的命令,既能生成 CSR,也能直接生成自签名证书(CA)。

场景 A:生成 CSR (用于发给 CA 签名)

1
openssl req -new -key server.key -out server.csr -subj "/CN=example.com"
  • -new: 生成一个新的证书请求。
  • -key: 指定已有的私钥。
  • -subj: 直接指定主题信息,避免交互式输入。

场景 B:生成自签名证书 (常用于 CA 或测试)

1
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt
  • -x509: 关键参数。输出自签名证书,而不是 CSR。
  • -nodes: No DES。私钥不加密保护。如果去掉此参数,生成私钥时会要求输入密码,每次使用私钥都需要密码。
  • -days: 证书有效期。

2.3 x509 - 证书操作与签名

用于查看证书内容,或作为 CA 签署 CSR

场景:CA 签署服务器证书

1
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
  • -req: 输入是一个 CSR 文件。
  • -CA / -CAkey: 指定颁发者(CA)的证书和私钥。
  • -CAcreateserial: 自动创建序列号文件 (ca.srl),每次签名序列号递增。
  • -extfile: (重要) 指定扩展配置文件,用于添加 SAN 等信息。

2.4 verify - 验证证书链

用于检查证书是否合法,是否由受信任的 CA 签署。

1
2
# 验证 server.crt 是否由 ca.crt 签署
openssl verify -CAfile ca.crt server.crt
  • 输出 OK 表示验证通过。
  • 如果证书链中间有缺失,可以使用 -untrusted 参数加载中间证书。

3. 关键参数深度解析

理解参数背后的含义比死记硬背更重要。

3.1 -subj (主题信息)

格式为 /类型=值/类型=值。常见字段:

  • CN (Common Name): 通用名称。旧版 TLS 依赖它验证域名,新版依赖 SAN
  • O (Organization): 组织名称。
  • OU (Organizational Unit): 部门。
  • C (Country): 国家代码 (如 CN, US)。
  • ST (State): 省份。
  • L (Locality): 城市。

示例: "/C=CN/ST=Beijing/L=Beijing/O=MyCorp/CN=api.example.com"

3.2 -nodes (私钥加密)

  • 含义: 生成的私钥文件不使用密码加密。
  • 生产建议: 生产环境私钥应该加密(去掉 -nodes),但这样会导致服务重启时需要人工输入密码,不利于自动化。通常做法是:生成时加密,部署到服务器后移除密码保护,并通过文件系统权限 (chmod 600) 保护私钥。

3.3 -sha256 (签名算法)

  • 含义: 使用 SHA-256 哈希算法进行签名。
  • 注意: 绝对不要使用 md5sha1,它们已被认为不安全,现代浏览器和客户端会拒绝信任。

3.4 扩展属性 (Extensions)

这是最容易出错的地方。证书不仅仅是公钥 + 身份,还包含用途限制

  • basicConstraints: 标识是否为 CA 证书 (CA:TRUECA:FALSE)。
  • keyUsage: 密钥用途 (如 digitalSignature, keyEncipherment)。
  • extendedKeyUsage (EKU): 扩展用途。
    • serverAuth: 只能用于服务器端 (TLS Web Server Authentication)。
    • clientAuth: 只能用于客户端 (TLS Web Client Authentication)。
    • 错误后果: 如果用服务器证书去做客户端认证,握手会失败 (tls: internal error)。

4. SAN (Subject Alternative Name) 专题

为什么重要?
从 Go 1.15、Chrome 58 开始,不再信任 CN 字段,只信任 SAN 字段。如果证书没有 SAN,客户端会报错 x509: certificate relies on legacy Common Name field

方法一:命令行直接添加 (OpenSSL 1.1.1+)

适合快速测试。

1
2
3
openssl req -new -key server.key -out server.csr \
-subj "/CN=example.com" \
-addext "subjectAltName = DNS:example.com,DNS:www.example.com,IP:192.168.1.1"
  • DNS: 后面跟域名。
  • IP: 后面跟 IP 地址。

方法二:使用配置文件 (兼容所有版本,推荐生产)

创建一个 ext.cnf 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = example.com
DNS.2 = www.example.com
IP.1 = 192.168.1.1

生成 CSR 时使用:

1
openssl req -new -key server.key -out server.csr -config ext.cnf

签署证书时使用:

1
2
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-out server.crt -days 365 -sha256 -extfile ext.cnf -extensions v3_req

5. 证书查验与调试 (Inspect & Debug)

当证书出现问题时,不要猜,用 OpenSSL 查看。

5.1 查看证书详细信息

1
openssl x509 -in server.crt -text -noout
  • -text: 以文本形式打印详细信息。
  • -noout: 不输出编码后的证书本身。
  • 重点关注:
    • Validity: 检查 Not BeforeNot After 是否过期。
    • Subject: 检查 CN。
    • X509v3 Subject Alternative Name: 检查是否有 SAN
    • X509v3 Extended Key Usage: 检查是 TLS Web Server Authentication 还是 Client Authentication
    • Signature Algorithm: 确认是 sha256WithRSAEncryption

5.2 查看私钥信息

1
openssl rsa -in server.key -text -noout
  • 可以确认私钥长度(如 2048 bit)。
  • 可以确认私钥是否加密(如果有 Proc-Type: 4,ENCRYPTED 则表示加密)。

5.3 验证证书链

1
2
3
4
5
# 验证 server.crt 是否信任 ca.crt
openssl verify -CAfile ca.crt server.crt

# 如果有中间证书 intermediate.crt
openssl verify -CAfile ca.crt -untrusted intermediate.crt server.crt
  • 如果返回 error 20 at 0 depth lookup: unable to get local issuer certificate,说明找不到颁发者。

5.4 调试神器:s_client

模拟客户端发起 TLS 握手,查看服务器返回的证书链。

1
openssl s_client -connect example.com:443 -servername example.com
  • -connect: 目标地址。
  • -servername: SNI 扩展,指定虚拟主机名(多域名证书必需)。
  • 输出分析:
    • 查看 Certificate chain 部分,确认服务器发送了完整的证书链。
    • 查看 Verify return code: 0 (ok) 确认验证通过。
    • 查看 ProtocolCipher 确认加密套件强度。

6. 格式转换

不同平台需要不同的证书格式,OpenSSL 是转换工具。

6.1 PEM 转 DER (二进制)

1
openssl x509 -in cert.pem -outform der -out cert.der

6.2 PEM 转 PKCS12 (包含私钥,用于 Windows/Java)

1
openssl pkcs12 -export -out cert.pfx -inkey server.key -in server.crt -certfile ca.crt
  • 会提示设置导出密码。

6.3 PKCS12 转 PEM

1
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
  • -nodes: 导出的私钥不加密。

7. 配置文件 openssl.cnf 详解

在生产环境中,为了统一管理策略(如强制密钥长度、强制扩展属性),通常不依赖命令行参数,而是修改 openssl.cnf

默认路径通常在 /etc/ssl/openssl.cnf/usr/lib/ssl/openssl.cnf

关键配置段示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[ CA_default ]
default_days = 365
default_md = sha256
policy = policy_match

[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
commonName = supplied

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_server ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
  • basicConstraints = critical, CA:true: 标记为 CA 证书,且关键扩展不可忽略。
  • keyUsage: 限制私钥只能用于数字签名和密钥加密,不能用于身份认证等其他用途。
  • critical: 标记为关键扩展,如果客户端不认识该扩展,必须拒绝连接(安全增强)。

8. 安全最佳实践总结

  1. 密钥长度: RSA 至少 2048 位,推荐 4096 位。或者使用 ECC (P-256)。
  2. 算法: 签名算法必须使用 SHA-256 或更高。禁止 MD5/SHA1。
  3. SAN: 必须配置 SAN,不要依赖 CN。
  4. 私钥保护:
    • 文件权限设置为 600 (chmod 600 *.key)。
    • 不要将私钥提交到代码仓库。
    • 定期轮换密钥。
  5. 证书有效期: 不要设置过长(如 10 年)。公共 CA 通常最长 1 年。内部 CA 建议 1-2 年,配合自动化轮换。
  6. 扩展用途 (EKU): 严格区分 serverAuthclientAuth,不要混用。
  7. 证书链: 服务器配置时,必须发送完整证书链(服务器证书 + 中间证书),否则旧客户端或 Java 客户端可能无法验证。

9. 常见错误速查表

错误信息 可能原因 OpenSSL 排查命令
unable to get local issuer certificate 缺少 CA 根证书或中间证书 openssl verify -CAfile ca.crt server.crt
certificate has expired 证书过期 openssl x509 -in cert.crt -noout -dates
x509: certificate relies on legacy Common Name field 缺少 SAN 扩展 openssl x509 -in cert.crt -text -noout | grep -A1 "Subject Alternative Name"
remote error: tls: bad certificate 证书用途不对 (如客户端用了服务器证书) openssl x509 -in cert.crt -text -noout | grep "Extended Key Usage"
certificate is valid for A, not B 访问域名与证书 SAN 不匹配 检查 openssl s_client 连接时的域名

通过以上指南,您应该能够熟练掌握 OpenSSL 的核心用法,独立完成证书生成、管理、调试和故障排查。

1
2
3
4
5
6
7
8
9
10
# 1. 生成私钥
openssl genrsa -out server.key 2048

# 2. 生成证书请求
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"

# 3. 生成自签名证书 (有效期 365 天)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# 现在你有了 server.crt (公钥) 和 server.key (私钥)
[up主专用,视频内嵌代码贴在这]