自签名证书生成:从零到一的手工活

说实话,很多人在生产环境里第一次接触证书,都是从自签名证书开始的。我自己刚入行那会儿,被领导丢了个任务——「给内网测试环境配个 HTTPS」。当时我连 PEM 和 DER 是什么都没搞清楚,硬着头皮查了一下午文档才搞定。

这一章,我就带你亲手走一遍。生成 RSA 私钥、创建自签名证书、再折腾一下格式转换。做完这些,你对证书的底层结构会有很直观的感觉。

本章核心目标:掌握 OpenSSL 命令行工具,完成从私钥生成到证书导出的完整流程,理解 PEM 与 DER 两种编码格式的本质区别。

3.1 准备工作:你需要什么

工欲善其事,必先利其器。我们只需要一个工具——OpenSSL。它几乎是所有 Linux 发行版的标配,macOS 也自带。Windows 的话,我建议用 Git Bash 或者 WSL,省得折腾环境变量。

验证一下你的环境:

openssl version

如果看到类似 OpenSSL 1.1.1k 25 Mar 2021 的输出,那就没问题。版本 1.0.2 以上都够用。

3.2 生成 RSA 私钥

私钥是整个证书体系的根基。它一旦泄露,你签发的所有证书都不再可信。所以,生成私钥这一步,我建议你养成好习惯——指定加密算法和密钥长度。

3.2.1 生成 2048 位 RSA 私钥

openssl genrsa -out server.key 2048

这条命令会生成一个 2048 位的 RSA 私钥,保存到 server.key 文件里。2048 位是目前业界的最低安全标准。1024 位已经被证明不够安全了,别用。

我的习惯:生成私钥时,我会顺手加上 -aes256 参数,给私钥文件本身加一道密码保护。虽然每次启动服务都要输密码有点烦,但安全上确实多了一层保障。

openssl genrsa -aes256 -out server.key 2048

3.2.2 查看私钥内容

生成的私钥是 PEM 格式的,你可以直接 cat 出来看看:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
...
-----END RSA PRIVATE KEY-----

嗯,就是一堆 Base64 编码的文本。你可以用下面这条命令解析它的结构:

openssl rsa -in server.key -text -noout

你会看到模数、指数、素数等数学参数。我在项目中曾经用这个命令帮同事排查过私钥损坏的问题——输出里如果出现「unable to load Private Key」,基本就是文件坏了。

3.3 创建自签名证书

有了私钥,下一步就是用它生成一张证书。自签名证书,说白了就是自己给自己当 CA,自己签自己。

3.3.1 一步到位法

最省事的做法:

openssl req -new -x509 -key server.key -out server.crt -days 365

这条命令会交互式地让你填一堆信息:国家、省份、城市、组织名、通用名(Common Name)等等。通用名是最重要的,它必须跟你服务器的域名完全一致。比如你的网站是 example.com,这里就填 example.com。填错了,浏览器会报域名不匹配。

我曾经踩过的坑:有一次给内网 Jenkins 配 HTTPS,我随手把通用名填成了 jenkins.local,结果同事用 IP 地址访问时,Chrome 直接拦了。后来我改成 IP 地址重新签了一张才消停。记住:通用名必须匹配客户端实际访问的地址。

3.3.2 非交互式生成(推荐)

我更喜欢用配置文件一次性搞定,省得每次手动输入:

openssl req -new -x509 -key server.key -out server.crt -days 365 \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=example.com"

参数说明:

参数 含义 示例值
C 国家代码 CN
ST 省份 Beijing
L 城市 Beijing
O 组织名称 MyOrg
CN 通用名(域名或IP) example.com

3.3.3 查看证书内容

openssl x509 -in server.crt -text -noout

输出里你会看到:

  • 证书版本(通常是 v3)
  • 序列号
  • 签名算法(SHA256WithRSAEncryption)
  • 颁发者和主题(自签名证书两者相同)
  • 有效期
  • 公钥信息

你想想看,一张证书本质上就是一个绑定了公钥和身份信息的、经过签名的数据结构。你现在看到的这些字段,就是它的全部家当。

3.4 证书格式转换:PEM 与 DER

搞清楚了私钥和证书怎么生成,接下来就是格式转换。这在实际工作中太常见了——Java 那边要 DER,Nginx 要 PEM,Windows 要 PFX。你不学会转换,寸步难行。

3.4.1 两种格式的本质区别

特性 PEM DER
编码方式 Base64 文本 二进制
可读性 可直接用文本编辑器打开 乱码,需用工具查看
文件头尾标记 有(-----BEGIN CERTIFICATE-----) 无
常见扩展名 .pem, .crt, .key .der, .cer
传输友好度 高(纯文本,可复制粘贴) 低(二进制,易损坏)

说白了,PEM 就是 DER 的 Base64 包装版。DER 是 ASN.1 编码的原始二进制,PEM 在它外面套了一层 Base64 和头尾标记,方便人类阅读和传输。

3.4.2 PEM → DER

openssl x509 -in server.crt -outform DER -out server.der

转换完你可以用 file 命令验证一下:

file server.der
# 输出: server.der: data

看到「data」就对了,说明已经是二进制格式。

3.4.3 DER → PEM

openssl x509 -in server.der -inform DER -out server.pem

反过来也一样简单。我当年第一次做这个转换时,死活想不通为什么 DER 转 PEM 要指定 -inform DER,而 PEM 转 DER 不用。后来才明白——OpenSSL 默认输入格式就是 PEM,所以只有输入非 PEM 时才需要显式声明。

3.4.4 私钥的格式转换

私钥也可以转:

# PEM 私钥转 DER
openssl rsa -in server.key -outform DER -out server_key.der

# DER 私钥转 PEM
openssl rsa -in server_key.der -inform DER -out server_key.pem

一个小技巧:如果你不确定一个文件是 PEM 还是 DER,直接用 cat 看一眼。以 -----BEGIN 开头的就是 PEM,一堆乱码就是 DER。或者用 openssl x509 -in file -noout 试一下,能解析就是 PEM,报错可能就是 DER。

3.5 完整流程:一张图看懂

下面这张图把整个流程串起来了。从私钥生成,到自签名证书签发,再到格式转换,每一步的输入输出都很清楚。

自签名证书生成与格式转换流程图 自签名证书生成与格式转换流程 1. 生成 RSA 私钥 2. 创建自签名证书 3. 输出 PEM 格式 格式转换 保持 PEM 转为 DER PEM:文本格式,适合 Nginx/Apache/OpenSSH DER:二进制格式,适合 Java/Windows/.NET 私钥和证书均可独立进行 PEM ↔ DER 转换 转换命令:openssl x509 -in input -outform DER -out output

3.6 常见问题与避坑指南

  • 证书过期:自签名证书默认有效期只有一年。我习惯在生成时用 -days 3650 设成 10 年,省得频繁续签。但生产环境还是建议用短有效期 + 自动续签。
  • 通用名不匹配:浏览器访问时如果提示「证书名称不匹配」,99% 是 CN 填错了。检查一下你填的域名跟地址栏里的是不是完全一致。
  • 私钥权限:私钥文件一定要设置严格的权限。chmod 600 server.key 是基本操作。我曾经见过同事把私钥设成 644,结果被扫描工具扫出来,吓得他连夜换证书。
  • 格式混淆:把 DER 文件当成 PEM 直接发给别人,对方解析失败。记住:DER 是二进制,别用文本编辑器打开它。

重要提醒:自签名证书只适合开发测试环境。生产环境请使用受信任的 CA 签发的证书,否则用户浏览器会弹出安全警告,你的网站可信度直接归零。