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

# 16.8.OpenSSL

OpenSSL 是一款加密工具包，实现了安全套接字层（SSL）和传输层安全性（TLS）协议，并提供许多加密功能。

openssl 程序是一款命令行工具，能通过 shell 使用 OpenSSL 加密库的各种加密功能。它可用于：

* 创建和管理私钥、公钥和参数
* 公钥加密操作
* 创建 X.509 证书、证书签名请求（CSR）和证书撤销列表（CRL）
* 计算消息摘要
* 使用密码算法加密和解密
* SSL/TLS 客户端和服务器测试
* 处理 S/MIME 签名或加密邮件
* 时间戳请求、生成和验证
* 基准测试加密例程

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

## 16.8.1. 生成证书

OpenSSL 支持生成证书，无论是通过 [CA](https://en.wikipedia.org/wiki/Certificate_authority) 验证的证书，还是供自用的证书。

运行命令 [openssl(1)](https://man.freebsd.org/cgi/man.cgi?query=openssl\&sektion=1\&format=html) 来生成一个有效的证书，向 [CA](https://en.wikipedia.org/wiki/Certificate_authority) 请求证书。此命令将在当前目录创建两个文件。证书请求文件 **req.pem** 可发送给 [CA](https://en.wikipedia.org/wiki/Certificate_authority)，该 CA 会验证输入的凭据，签名请求并返回签名后的证书。第二个文件 **cert.key** 是证书的私钥，应存放在安全的地方。如果他人获取此文件，它可用于冒充用户或服务器。

执行以下命令来生成证书：

```sh
# openssl req -new -nodes -out req.pem -keyout cert.key -sha3-512 -newkey rsa:4096
```

输出类似如下：

```sh
Generating a RSA private key
..................................................................................................................................+++++
......................................+++++
writing new private key to 'cert.key'
-----
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]:ES
State or Province Name (full name) [Some-State]:Valencian Community
Locality Name (eg, city) []:Valencia
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:Systems Administrator
Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org
Email Address []:user@FreeBSD.org

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456789
An optional company name []:Another name
```

或者，如果不需要 [CA](https://en.wikipedia.org/wiki/Certificate_authority) 签名，则可创建自签名证书。这样会在当前目录创建两个新文件：一个是私钥文件 **cert.key**，另一个是证书文件 **cert.crt**。这些文件应放置在一个目录中，最好是在 **/etc/ssl/** 下，该目录仅对 `root` 用户可读。将文件的权限设置为 `0700`，可使用 `chmod` 设置。

执行以下命令来生成证书：

```sh
# openssl req -new -x509 -days 365 -sha3-512 -keyout /etc/ssl/private/cert.key -out /etc/ssl/certs/cert.crt
```

输出类似如下：

```sh
Generating a RSA private key
........................................+++++
...........+++++
writing new private key to '/etc/ssl/private/cert.key'
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]:ES
State or Province Name (full name) [Some-State]:Valencian Community
Locality Name (eg, city) []:Valencia
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:Systems Administrator
Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org
Email Address []:user@FreeBSD.org
```

## 16.8.2. 配置 FIPS 提供程序

在 FreeBSD 14 及更高版本中，基本系统中引入了 OpenSSL 3，并且引入了提供程序模块的概念。除了库中内置的默认提供程序模块外，*legacy* 模块实现了现已过时的、可选的加密算法，而 *fips* 模块则将 OpenSSL 的实现限制为符合 [FIPS](https://en.wikipedia.org/wiki/Federal_Information_Processing_Standards) 标准集的加密算法。OpenSSL 中这一部分得到了 [特别关注](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 验证版本的列表](https://www.openssl.org/source/)，以确保用户在使用 OpenSSL 时符合 FIPS 标准。

重要的是，[fips\_module(7)](https://man.freebsd.org/cgi/man.cgi?query=fips_module\&sektion=7\&format=html) 受到额外的安全措施保护，禁止在未通过完整性检查的情况下使用该模块。此检查可由本地系统管理员设置，让每个 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.
00206124D94D0000:error:1C8000D5:Provider routines:SELF_TEST_post:missing config data:crypto/openssl/providers/fips/self_test.c:275:
00206124D94D0000:error:1C8000E0:Provider routines:ossl_set_error_state:fips module entering error state:crypto/openssl/providers/fips/self_test.c:373:
00206124D94D0000:error:1C8000D8:Provider routines:OSSL_provider_init_int:self test post failure:crypto/openssl/providers/fips/fipsprov.c:707:
00206124D94D0000:error:078C0105:common libcrypto routines:provider_init:init fail:crypto/openssl/crypto/provider_core.c:932:name=fips
```

可通过创建 **/etc/ssl/fipsmodule.cnf** 文件来配置检查，然后在 OpenSSL 的主配置文件 **/etc/ssl/openssl.cnf** 中引用该文件。OpenSSL 提供了 [openssl-fipsinstall(1)](https://man.freebsd.org/cgi/man.cgi?query=openssl-fipsinstall\&sektion=1\&format=html) 工具来帮助完成此过程，可按如下方式使用：

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

输出应类似如下：

```sh
INSTALL PASSED
```

然后应该修改 **/etc/ssl/openssl.cnf** 文件，以便：

* 包含上述生成的 **/etc/ssl/fipsmodule.cnf** 文件，
* 暴露 FIPS 模块以供可能使用，
* 并显式激活默认模块。

```ini
[...]
# 对于 FIPS
# 可选地包含一个由 OpenSSL fipsinstall 应用程序生成的文件。该文件包含 OpenSSL fips 提供者所需的配置数据。
# 它包含一个命名的部分，例如 [fips_sect]，该部分在下面的 [provider_sect] 中被引用。
# 有关更多信息，请参阅 OpenSSL 安全策略。
.include /etc/ssl/fipsmodule.cnf

[...]

# 要加载的提供者列表
[provider_sect]
default = default_sect
# fips 部分名称应与包含的 fipsmodule.cnf 中的部分名称匹配。
fips = fips_sect

# 如果没有显式激活提供者，则默认提供者会被隐式激活。
# 有关更多细节，请参见 man 7 OSSL_PROVIDER-default。
#
# 如果显式添加一个部分来激活任何其他提供者，你很可能需要显式激活默认提供者，否则它
# 将在 openssl 中不可用。结果，依赖于 OpenSSL 的应用程序可能无法正常工作，这可能会导致
# 系统出现重大问题，包括无法远程访问系统。
[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:
U2FsdGVkX18idooW6e3LqWeeiKP76kufcOUClh57j8U=
```

每当修改 FIPS 模块时，例如在系统更新或应用影响基本系统中 OpenSSL 的安全修复后，都必须重复此过程。
