> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-27-zhang-an-quan/di-27.5-jie-openssl.md).

# 27.5 OpenSSL

OpenSSL 3 自 FreeBSD 14 起纳入基本系统，引入提供者模块（provider module）架构。本节介绍自签证书生成（自签 CA）、FIPS 合规配置（fips\_module 完整性检查与 openssl fipsinstall）和已弃用算法加载。

```sh
OpenSSL 3 提供者模块架构：

  应用程序（openssl 命令 / 第三方程序）
     │
     │  调用 libcrypto
     ▼
  libcrypto（核心加密库）
     │
     │  按需加载提供者模块
     ▼
  提供者模块
     │
     ├── default：默认算法集（活跃）
     │     含 AES、SHA、RSA、ECDSA 等现代算法
     │
     ├── legacy：已弃用算法（按需加载）
     │     含 MD2、MD4、RC4、DES 等旧算法
     │
     └── fips：FIPS 140 合规算法集（按需加载）
           严格限定于 FIPS 标准允许的密码算法
           须经 fipsinstall 完整性检查方可使用
```

## 概述

OpenSSL 是加密工具包，实现安全套接字层（SSL）和传输层安全（TLS）网络协议，并提供丰富的加密例程。

`openssl` 程序是该工具包的命令行入口，用户可在 Shell 中调用 OpenSSL 加密库的各类功能，包括：

* 私钥、公钥和参数的创建与管理
* 公钥加密操作
* X.509 证书、CSR 和 CRL 的创建
* 消息摘要与消息认证码的计算
* 使用密码进行加密和解密
* SSL/TLS 客户端和服务器测试
* S/MIME 签名或加密邮件的处理
* 时间戳请求、生成和验证
* 加密例程的性能测试

更多信息请参阅免费的 [OpenSSL Cookbook](https://www.feistyduck.com/books/openssl-cookbook/)。

## 生成证书

OpenSSL 支持生成证书，可提交 CA 验证，也可以自行使用。具体而言：

### 需要 CA 签署的证书签名请求

执行 openssl 搭配以下参数，可生成供 CA 签署的证书：

```sh
# openssl req -new -noenc -out req.pem -keyout cert.key -sha512 -newkey rsa:4096
```

解释命令选项：

| 选项                 | 解释                                        |
| ------------------ | ----------------------------------------- |
| `openssl req`      | 生成证书签名请求（CSR，Certificate Signing Request） |
| `-new`             | 创建新的证书签名请求                                |
| `-noenc`           | 不为私钥设置密码，生成的私钥不会加密保护                      |
| `-out req.pem`     | 指定生成的证书签名请求文件的输出文件名，这里是 `req.pem`         |
| `-keyout cert.key` | 指定生成的私钥文件的输出路径，这里是 `cert.key`             |
| `-sha512`          | 使用 SHA-512 哈希算法进行签名请求的哈希计算                |
| `-newkey rsa:4096` | 生成新的 RSA 密钥对，使用 4096 位的 RSA 加密算法。         |

输出应类似于以下内容：

```sh
...+......+.......+.....+.+.....+....+...+..+++++++++++++++++++++++++++++++++++++++++++++*.........+++++++++++++++++++++++++++++++++++++++++++++*..+................+....+......+.....+++++

……省略部分输出……

-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
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]:Chinese FreeBSD Community (CFC) # 组织名称
Organizational Unit Name (eg, section) []:Systems Administrator	# 组织单位名称
Common Name (e.g. server FQDN or YOUR name) []:bsdcn.org # 公用名
Email Address []:ykla@bsdcn.org	# 电子邮件

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:1234 # 密码不少于四位数
An optional company name []:1234
```

上述命令生成的是证书签名请求（CSR），**需提交给 CA 签署后方可获得证书**。

该命令在当前目录创建了两个文件：

```sh
req.pem		cert.key
```

将证书请求文件 **req.pem** 递交至 CA，由 CA 验证凭据、签署后返回已签名证书；

另一文件 **cert.key** 为证书私钥，务必妥善保管。私钥一旦泄露，他人即可冒充用户或服务器。

```sh
CSR 申请签署流程：

  申请人本地
     │
     │  生成密钥对（openssl req -new）
     ▼
  req.pem（证书签名请求） + cert.key（私钥，本地保管）
     │
     │  将 req.pem 提交至 CA
     ▼
  CA 机构
     │
     │  验证申请人凭据
     │  使用 CA 私钥签署
     ▼
  已签名证书（cert.crt）
     │
     │  返回给申请人
     ▼
  申请人本地
     │
     │  cert.crt 与 cert.key 配对
     ▼
  部署至服务（HTTPS 等）
```

### 自签名证书

如果无需 CA 签署，可自行创建自签名证书。

> **警告**
>
> 以下命令将证书和私钥直接写入 **/etc/ssl/** 系统目录。若该路径下已有证书文件，将被覆盖且无法恢复。请先备份现有证书。

执行以下命令生成 X.509 格式的自签名证书：

```sh
# openssl req -new -x509 -days 365 -sha512 -newkey rsa:4096 -keyout /etc/ssl/cert.key -out /etc/ssl/certs/cert.crt
```

输出应类似于以下内容：

```sh
.+.+...........+.........+......+...+....+..+.+...+..+.........+...+...+............+.......+.....+...+............+.+..+.+............+..+...+....+.........+.....+++++++++++++++++++++++++++++++++++++++++++++*............+...+...+....+.....+++++++++++++++++++++++++++++++++++++++++++++*.....

……省略部分输出……

Enter PEM pass phrase: # 设置密码
Verifying - Enter PEM pass phrase: # 再次输入密码
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
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]:Chinese FreeBSD Community (CFC)
Organizational Unit Name (eg, section) []:Systems Administrator
Common Name (e.g. server FQDN or YOUR name) []:bsdcn.org
Email Address []:ykla@bsdcn.org
```

此命令将在目录 **/etc/ssl/certs** 下创建证书文件 **cert.crt**。

```sh
-rw-r--r--  1 root wheel 2228 May 22 13:18 /etc/ssl/certs/cert.crt
```

可执行如下命令进行验证：

```sh
# openssl x509 -in /etc/ssl/certs/cert.crt -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            36:78:41:ef:1a:ba:e0:61:85:7e:af:1e:c3:08:58:95:af:5e:95:51
        Signature Algorithm: sha512WithRSAEncryption
        Issuer: C=CN, ST=Beijing, L=Beijing, O=Chinese FreeBSD Community (CFC), OU=Systems Administrator, CN=bsdcn.org, emailAddress=ykla@bsdcn.org
        Validity
            Not Before: May 22 05:18:09 2026 GMT
            Not After : May 22 05:18:09 2027 GMT
        Subject: C=CN, ST=Beijing, L=Beijing, O=Chinese FreeBSD Community (CFC), OU=Systems Administrator, CN=bsdcn.org, emailAddress=ykla@bsdcn.org

……省略部分输出……
```

证书私钥 **cert.key** 位于 **/etc/ssl/** 目录：

```sh
-rw-------  1 root wheel 1886 Apr 16 11:53 /etc/ssl/cert.key
```

验证私钥：

```sh
# openssl x509 -noout -modulus -in /etc/ssl/certs/cert.crt | openssl sha256
SHA2-256(stdin)= 2246982ddf52bdbe15cb4df06df58f8e3c5ff075e6aa08bc564caf965ee75203
# openssl rsa -noout -modulus -in /etc/ssl/cert.key | openssl sha256
Enter pass phrase for /etc/ssl/cert.key: # 输入之前设置的密码
SHA2-256(stdin)= 2246982ddf52bdbe15cb4df06df58f8e3c5ff075e6aa08bc564caf965ee75203
```

如果 SHA-256 值相同，则说明私钥与证书匹配。

建议将上述文件存放于 **/etc/ssl/** 目录，使用 `chmod` 命令设置权限：证书（`.crt`）为公开信息应设为 `0644`，私钥（`.key`）应设为 `0600`。

```sh
# cp /etc/ssl/certs/cert.crt /etc/ssl/
# chmod 0644 /etc/ssl/cert.crt
# chmod 0600 /etc/ssl/cert.key
```

## 配置 FIPS 提供者

OpenSSL 3 自 FreeBSD 14 起纳入基本系统，随之而来的还有全新的提供者模块（provider module）概念。

除内置默认提供者外，`legacy` 模块负责实现现已可选、已弃用的加密算法，`fips` 模块则严格限定于 FIPS 标准允许的密码算法集。

OpenSSL 的 FIPS 相关部分受到[重点关注](https://www.openssl.org/docs/fips.html)，附有[已知安全问题列表](https://www.openssl.org/news/fips-cve.html)，并定期接受 [FIPS 140 验证流程](https://github.com/openssl/openssl/blob/master/README-FIPS.md)审查。这些措施使用户得以确保满足 FIPS 合规要求。

fips\_module 还受额外安全机制保护，未通过完整性检查则无法使用。本地系统管理员可按需配置此检查，继而允许每个 OpenSSL 3 用户加载该模块。如果配置不当，FIPS 模块报错如下：

```sh
# echo test | openssl aes-128-cbc -a -provider fips -pbkdf2
```

输出应类似于以下内容：

```sh
aes-128-cbc: unable to load provider fips
Hint: use -provider-path option or OPENSSL_MODULES environment variable.
1090A56510220000:error:12800067:DSO support routines:dlfcn_load:could not load the sharedlibrary:/usr/src/crypto/openssl/crypto/dso/dso_dlfcn.c:115:filename(/usr/lib/ossl-modules/fips.so): Cannot open "/usr/lib/ossl-modules/fips.so"
1090A56510220000:error:12800067:DSO support routines:DSO_load:could not load the shared library:/usr/src/crypto/openssl/crypto/dso/dso_lib.c:147:
1090A56510220000:error:07880025:common libcrypto routines:provider_init:reason(37):/usr/src/crypto/openssl/crypto/provider_core.c:1026:name=fips
```

可通过创建 **/etc/ssl/fipsmodule.cnf** 来配置完整性检查，并在 OpenSSL 主配置文件 **/etc/ssl/openssl.cnf** 中引用。

需要通过 Ports 参照 [FIPS 已验证版本清单](https://www.openssl.org/source/)安装经过认证的 OpenSSL 版本。随后将 **fips.so** 库复制到对应位置。

> **警告**
>
> **FIPS 模块跨大版本混用风险**：以下操作将 Ports 中的 OpenSSL **3.0** FIPS 模块复制到基本系统路径，与基本系统的 OpenSSL **3.5** 混用。这种跨大版本（3.0 至 3.5）混用存在以下严重风险：
>
> * **ABI 不兼容**：不同大版本的 OpenSSL 内部数据结构与函数接口可能不兼容，导致程序崩溃或行为异常。
> * **FIPS 认证失效**：FIPS 140 验证针对特定版本组合颁发，跨大版本混用将导致 FIPS 合规性在法律和技术层面均不成立。
> * **安全隐患**：旧版 FIPS 模块可能缺失新版 OpenSSL 的安全修复，混用后可能引入已知漏洞。
>
> 若要合规使用 FIPS 模块，应确保 FIPS 模块与 OpenSSL 库版本严格匹配。**若不确定版本兼容性，请勿执行以下操作。**

OpenSSL 提供了 `openssl fipsinstall` 辅助此过程。用法如下：

```sh
# cp /usr/local/lib/ossl-modules/fips.so /usr/lib/ossl-modules/
# openssl fipsinstall -module /usr/lib/ossl-modules/fips.so -out /etc/ssl/fipsmodule.cnf
```

输出应类似于以下内容（版本号取决于 Ports 中安装的 OpenSSL 版本）：

```sh
	name:     	OpenSSL FIPS Provider
	version:  	3.0.20
	build:    	3.0.20
INSTALL PASSED
```

接下来应修改 **/etc/ssl/openssl.cnf**，加入以下三项配置：

* 引入上面生成的 **/etc/ssl/fipsmodule.cnf** 文件，
* 导出 FIPS 模块以供调用，
* 并显式激活默认模块。

```ini
……省略其他内容……

# For FIPS
# Optionally include a file that is generated by the OpenSSL fipsinstall
# application. This file contains configuration data required by the OpenSSL
# fips provider. It contains a named section e.g. [fips_sect] which is
# referenced from the [provider_sect] below.
# Refer to the OpenSSL security policy for more information.
.include /etc/ssl/fipsmodule.cnf

……省略其他内容……

# List of providers to load
[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect

# If no providers are activated explicitly, the default one is activated implicitly.
# See man 7 OSSL_PROVIDER-default for more details.
#
# If you add a section explicitly activating any other provider(s), you most
# probably need to explicitly activate the default provider, otherwise it
# becomes unavailable in openssl.  As a consequence applications depending on
# OpenSSL may not work correctly which could lead to significant system
# problems including inability to remotely access the system.
[default_sect]
activate = 1
```

以上步骤完成后，即可确认 FIPS 模块确实可用且正常工作：

```sh
# echo test | openssl aes-128-cbc -a -provider fips -pbkdf2
```

输出应类似于以下内容：

```sh
enter AES-128-CBC encryption password: # 输入密码
Verifying - enter AES-128-CBC encryption password: # 重复输入密码
U2FsdGVkX1+cIAxHqRAhBgFQdCjTDU2sGevQ152Gw74=
```

查看当前 OpenSSL 提供者状态：

```sh
# openssl list -providers
Providers:
  default
    name: OpenSSL Default Provider
    version: 3.5.6
    status: active
  fips
    name: OpenSSL FIPS Provider
    version: 3.0.20
    status: active
```

以上输出中，default 提供者的版本号取决于系统使用的 OpenSSL 版本（基本系统或 Ports），FIPS 提供者的版本号取决于 Ports 中安装的 OpenSSL 版本。

FIPS 模块发生变动时（如系统更新后，或基本系统 OpenSSL 应用安全修复后），均需要重复上述过程。

## 课后习题

1. 使用 `openssl speed` 命令在本地 FreeBSD 系统上分别测试 AES-128-CBC、AES-256-GCM 和 ChaCha20-Poly1305 三种加密算法的吞吐量，分析结果差异的原因。
2. 用 `openssl s_client -connect` 连接一个公网 HTTPS 站点，从输出中提取证书链、协议版本和协商的密码套件，绘制证书的信任链结构图。
3. 使用 `openssl req -x509` 生成一个自签名证书，随后配置 FreeBSD 上的 Nginx 或 Apache 使用该证书提供 HTTPS 服务。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-27-zhang-an-quan/di-27.5-jie-openssl.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
