首页/我的作品/密码学/8.4 动手实验:用OpenSSL生成自己的证书
密码学:守护数字世界的秘密

8.4 动手实验:用OpenSSL生成自己的证书

第 47 / 78 篇 · Crazy Boy

理论说再多,不如亲手做一遍。在这一节,我们将用 OpenSSL——一个开源的密码学工具箱——来生成自己的数字证书。你会看到证书的完整生命周期:从私钥生成,到证书签名请求,再到签发证书,最后验证证书内容。做完这一课,你就能理解HTTPS背后那些证书文件到底是什么样子的了。

准备工作:安装OpenSSL

OpenSSL几乎预装在所有的Linux和macOS系统上,Windows用户可以从 OpenSSL官网 下载安装包,或者使用Windows Subsystem for Linux (WSL)。打开终端,输入以下命令检查是否已安装:

openssl version

如果显示版本号(如 OpenSSL 1.1.1f 31 Mar 2020),就表示已经安装好了。如果没有,请先安装(Linux使用apt或yum,macOS使用brew)。

第一步:生成私钥

证书的核心是公钥和私钥。我们先生成一个2048位的RSA私钥。执行:

openssl genrsa -out private.key 2048

这个命令会生成一个名为private.key的文件,内容是以PEM格式编码的私钥。你可以用文本编辑器打开它,会看到类似这样的内容:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...
...
-----END PRIVATE KEY-----

注意:私钥必须严格保密,绝不能泄露给任何人。在生产环境中,私钥的权限通常设置为600(只有所有者可读)。

第二步:生成证书签名请求(CSR)

接下来,我们需要向证书颁发机构(CA)申请一张证书,这个申请文件就是证书签名请求(Certificate Signing Request, CSR)。CSR里包含了我们的公钥和一些身份信息(比如域名、组织名称等)。执行:

openssl req -new -key private.key -out request.csr

系统会交互式地询问一些信息,如:

  • Country Name (2 letter code) [AU]: CN(国家代码)
  • State or Province Name (full name) [Some-State]: Beijing(省份)
  • Locality Name (eg, city) []: Beijing(城市)
  • Organization Name (eg, company) [Internet Widgits Pty Ltd]: Example Inc(组织名)
  • Organizational Unit Name (eg, section) []: IT(部门)
  • Common Name (eg, your name or your server’s hostname) []: www.example.com(域名,关键!)
  • Email Address []: admin@example.com(邮箱)

你可能会被问额外选项,比如挑战密码,直接回车跳过即可。

完成后,会生成request.csr文件。你可以用cat request.csr查看内容,它同样是PEM格式,以-----BEGIN CERTIFICATE REQUEST-----开头。

第三步:生成自签名证书(自己当CA)

在实际生产环境中,你会把CSR发给CA,CA签发证书后返回给你。但这里我们模拟CA,用自己的私钥给自己签发一张自签名证书。这样你就不需要找第三方CA,可以用来测试或内部使用。执行:

openssl x509 -req -in request.csr -signkey private.key -out certificate.crt -days 365

解释一下参数:

  • -req:表示输入是CSR。
  • -in request.csr:指定CSR文件。
  • -signkey private.key:用自己的私钥签名(因为是自签名)。
  • -out certificate.crt:输出证书文件。
  • -days 365:证书有效期为365天。

运行后会生成certificate.crt,这就是你的数字证书。查看它:

openssl x509 -in certificate.crt -text -noout

你会看到证书的详细信息,包括版本、序列号、签名算法、颁发者、有效期、公钥信息等。特别注意颁发者(Issuer)和主体(Subject)是相同的——因为这是自签名证书。

第四步:模拟HTTPS服务器验证

现在我们来模拟一个简单的HTTPS服务器,用这个证书测试一下。

首先,创建一个简单的HTTP服务器配置,比如使用Python的http.server模块,但它不支持HTTPS。我们可以用openssl s_server命令来快速搭建一个测试服务端:

openssl s_server -accept 4433 -cert certificate.crt -key private.key -www

这个命令会在本地的4433端口启动一个简易的TLS服务器,任何访问都会显示“CONNECTED”信息和客户端信息。在另一个终端中,用curl测试:

curl -k https://localhost:4433

-k参数让curl忽略证书验证(因为我们的证书是自签名的,没有第三方CA背书)。你会看到服务器返回的信息。

如果不加-k,curl会报错,提示证书不被信任。这正是浏览器访问自签名网站时的警告。这说明,只有被信任的CA签发的证书才能被大众浏览器自动接受。

第五步:模拟CA签发证书(创建信任链)

为了真正理解信任链,我们来模拟一个根CA,然后用它给刚才的证书签名。换句话说,我们不要自签名,而是用另一个私钥(根CA的私钥)来签名我们的证书。

  1. 生成根CA私钥和自签名根证书:

    openssl genrsa -out ca.key 2048
    openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -subj "/CN=My Root CA"
  2. 用根CA签发我们的证书:

    openssl x509 -req -in request.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out certificate_signed.crt -days 365

    参数-CAcreateserial会生成一个序列号文件。

现在,certificate_signed.crt就是由根CA签名过的证书。如果你把根证书ca.crt安装到系统的受信任根证书列表,那么浏览器就会信任certificate_signed.crt。由于我们没有安装,curl仍然会报错,但我们可以用curl --cacert ca.crt来告诉curl信任这个根证书:

curl --cacert ca.crt https://localhost:4433

这次就不会报错了,因为curl使用了我们指定的根证书来验证服务器证书。

你学会了什么?

通过这个实验,你应该直观地理解了:

  • 私钥是身份的证明,必须保密。
  • CSR是向CA申请证书的请求文件。
  • 数字证书由CA私钥签名,包含了公钥和身份信息。
  • 自签名证书适合测试,但不被公开信任。
  • 信任链依赖根证书,它必须预先安装在系统中。

现在,你已经亲自动手走过了一遍数字证书的完整流程。这不仅是理论知识,更是你在未来配置HTTPS、开发安全应用时,随时可以拿来的技能。

动手试试:试着修改证书的域名(Common Name),看看浏览器访问时有什么不同。也可以生成椭圆曲线(ECC)的密钥和证书,对比一下文件大小。

恭喜你,数字证书的大门已经为你打开!