自签名证书生成:从零到一的手工活
说实话,很多人在生产环境里第一次接触证书,都是从自签名证书开始的。我自己刚入行那会儿,被领导丢了个任务——「给内网测试环境配个 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 完整流程:一张图看懂
下面这张图把整个流程串起来了。从私钥生成,到自签名证书签发,再到格式转换,每一步的输入输出都很清楚。
3.6 常见问题与避坑指南
- 证书过期:自签名证书默认有效期只有一年。我习惯在生成时用
-days 3650设成 10 年,省得频繁续签。但生产环境还是建议用短有效期 + 自动续签。 - 通用名不匹配:浏览器访问时如果提示「证书名称不匹配」,99% 是 CN 填错了。检查一下你填的域名跟地址栏里的是不是完全一致。
- 私钥权限:私钥文件一定要设置严格的权限。
chmod 600 server.key是基本操作。我曾经见过同事把私钥设成 644,结果被扫描工具扫出来,吓得他连夜换证书。 - 格式混淆:把 DER 文件当成 PEM 直接发给别人,对方解析失败。记住:DER 是二进制,别用文本编辑器打开它。
重要提醒:自签名证书只适合开发测试环境。生产环境请使用受信任的 CA 签发的证书,否则用户浏览器会弹出安全警告,你的网站可信度直接归零。