第4章 OpenSSL工具入门:安装、基本命令、生成自签名证书

说到TLS双向认证,OpenSSL是个绕不开的家伙。这工具我用了十几年,从刚开始手忙脚乱敲命令,到现在闭着眼都能写出一套证书签发脚本。说白了,OpenSSL就是密码学领域的瑞士军刀,什么对称加密、非对称加密、证书签发、随机数生成……它全包了。

我见过不少新手上来就找什么“一键生成证书”的GUI工具,结果出了问题不知道根儿在哪儿。OpenSSL虽然命令行看着有点吓人,但一旦你掌握了这几个核心命令,后面的双向认证配置就会特别通透。

4.1 安装OpenSSL

不同操作系统安装方式不同,但核心版本我建议至少用1.1.1以上。现在大部分系统都默认带OpenSSL,不过版本可能偏老。

操作系统安装命令典型路径
Ubuntu/Debiansudo apt install openssl/usr/bin/openssl
CentOS/RHELsudo yum install openssl/usr/bin/openssl
macOS (Homebrew)brew install openssl/usr/local/opt/openssl/bin/openssl
Windows下载安装包或使用WSLC:\Program Files\OpenSSL-Win64\bin\openssl.exe

我个人习惯在Windows上用WSL里的OpenSSL,省去配置环境变量的麻烦。你如果非要用原生Windows版,记得把bin目录加到PATH里,不然每次都得敲全路径。

装完验证一下:

openssl version
# 输出示例:OpenSSL 1.1.1w  11 Sep 2023

嗯,看到版本号就说明装好了。如果你看到的是1.0.2,我建议你升级,因为1.0.2已经停止安全维护,有已知漏洞。

4.2 基本命令速览

OpenSSL的命令结构是 openssl [子命令] [参数]。我挑了几个最常用的,你可以当成“逃生工具包”记下来:

  • 查看帮助:openssl help 或 man openssl
  • 生成RSA私钥:openssl genrsa -out server.key 2048
  • 从私钥提取公钥:openssl rsa -in server.key -pubout -out server.pub
  • 查看证书内容:openssl x509 -in cert.pem -text -noout
  • 计算文件哈希:openssl dgst -sha256 myfile.txt

为什么我特别推荐2048位?因为1024位现在已经不安全了,而4096位性能开销大,对于大多数API场景,2048位是性价比最高的选择。我在一个支付项目中就吃过亏——甲方要求必须用4096位,结果握手延迟多了将近一倍,后来改成2048位才过性能压测。

4.3 生成自签名证书

自签名证书说白了就是自己给自己当CA。虽然浏览器会报不安全,但在开发环境、内网接口、或者双向认证测试中,它是最方便的工具。

我习惯于分三步走,清晰不绕弯:

  1. 生成私钥
  2. 生成证书签名请求(CSR)
  3. 用私钥签名CSR得到自签名证书

下面把这套流程拆开看:

步骤1:生成私钥

openssl genrsa -out server.key 2048
chmod 400 server.key   # 私钥权限必须严格限制

这条命令生成一个RSA私钥,输出文件是PEM格式。你可以用 openssl rsa -in server.key -text -noout 查看私钥的模数、指数等信息。

注意:私钥文件一旦泄露,你的安全体系就全完了。我在某次渗透测试中碰到一个客户,居然把私钥放在Nginx的静态目录下,直接被爬虫下载了……

步骤2:生成CSR

openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=api.example.com"

-subj 这部分直接填就行,省得交互式问答。如果是在双向认证场景,CN 字段很重要——客户端会用它来验证服务端身份。我在一个物联网项目里,就因为CN填了个IP地址,结果客户端证书校验老是失败,折腾了两天才发现是CN和DNS不匹配。

常见的字段含义:

  • C:国家代码,CN是中国
  • ST:省份
  • L:城市
  • O:组织名称
  • CN:公用名,通常填域名

步骤3:生成自签名证书

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

这条命令的意思是:用你自己的私钥去签名你自己的CSR,有效期365天。得到的 server.crt 就是自签名证书。你可以用 openssl x509 -in server.crt -text -noout 看看它里面包含了什么——签发者和主题一模一样,这就是自签名的特征。我曾经在调试时发现证书有效期竟然是1970年,一看忘了加 -days 参数,默认只有30天……

实操小技巧:把三步合成一行脚本,以后用起来方便:

openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/C=CN/O=Dev/CN=localhost"

-nodes 表示不加密私钥,省去每次启动服务输密码的麻烦。生产环境不要用这个参数。

4.4 验证证书

证书生成完,你得确认它没问题:

openssl verify -CAfile server.crt server.crt
# 输出:server.crt: OK

对于自签名证书,-CAfile 填它自己就行,因为CA就是自己。如果是CA签发的证书,要用CA证书去验证。

你还可以检查证书的指纹(SHA256):

openssl x509 -in server.crt -fingerprint -sha256 -noout

这个指纹在双向认证里可以用来做指纹校验,我见过一些高安全场景不信任CA链,直接硬编码指纹在客户端代码里。

4.5 常见避坑指南

  • 私钥格式问题:有些Java应用需要PKCS8格式的私钥,可以用 openssl pkcs8 -topk8 -in server.key -out server.pk8 -nocrypt 转换。
  • 证书编码混淆:PEM是Base64文本格式,DER是二进制格式。用 -outform DER 可以互相转换。我碰过一个Java环境只认DER,折腾了半天。
  • 密钥长度与性能:双向认证场景每建立一个连接就要做一次私钥签名,密钥越长CPU消耗越大。实测RSA 2048和ECDSA P-256相比,后者握手速度快了大概3倍。如果你对性能敏感,可以考虑用ECDSA。
  • 通配符证书:CSR的CN里填 *.example.com 可以匹配所有子域名,但注意浏览器对通配符的限制——只能匹配一级子域名,不能匹配两级。
自签名证书生成流程 步骤1 生成RSA私钥 genrsa -out server.key 2048 步骤2 生成证书请求CSR req -new -key server.key 步骤3 自签名证书 x509 -req -signkey server.key 输出:server.key 私钥(PEM) 输出:server.csr 证书签名请求 输出:server.crt 自签名证书 实际工作中建议直接用一行命令: openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes

这张图把三个步骤串联起来了。你可以看到每个阶段的输入输出是什么。我建议你在第一次做双向认证时,手动敲一遍这三条命令,感受一下证书是怎么从无到有的。相信我,这比任何GUI工具都能帮你理解TLS的信任模型。

另外说个经验:自签名证书的《基本约束》扩展默认是缺失的,这意味着它不能当CA去签发别的证书。如果你要做两级CA体系(根CA+中间CA),记得在生成证书时加上 -extensions v3_ca。不过那是更后面的内容了,咱们先把基础知识扎牢。