升级到 OpenSSL 3.x 后,很多老系统生成的证书无法验证通过,错误提示类似 error:0308010C:digital envelope routines。这通常是因为 OpenSSL 3.0 默认禁用了遗留算法(MD5、SHA-1、DES、RC4 等)。本文介绍如何配置 Legacy Provider 来处理这些遗留证书。

问题背景

OpenSSL 3.0 引入了 Provider 架构,密码学算法的实现被分离到独立的 Provider 中:

  • Default Provider:提供现代安全算法(AES、SHA-2、ChaCha20 等)
  • FIPS Provider:提供 FIPS 140-2 认证的算法
  • Legacy Provider:提供遗留算法(MD5、SHA-1、DES、RC4、CAST 等)

默认情况下,只有 Default Provider 启用,因此使用遗留算法的操作会失败。

验证问题现象

1. DES 加密失败

1
2
3
4
5
$ echo -n "test" | openssl enc -des-ede3-cbc
enc: Unknown cipher: des-ede3-cbc
error:0308010C:digital envelope routines:inner_evp_generic_fetch:unsupported:
../crypto/evp/evp_fetch.c:386:Global default library context, Algorithm (des-ede3-cbc : 27), 
Properties (<null>)

2. MD5 摘要失败

1
2
3
4
5
$ echo -n "test" | openssl dgst -md5
Error setting digest algorithm
00809DBE847F0000:error:13000084:HL routines:EVP_MD_fetch:unknown digest:
../crypto/evp/evp_fetch.c:386:Global default library context, Algorithm (MD5), 
Properties (<null>)

3. SHA-1 签名证书验证

创建测试证书(仅用于演示,生产环境勿用 SHA-1):

1
2
3
$ openssl req -x509 -newkey rsa:2048 \
  -keyout /tmp/test-key.pem -out /tmp/test-cert.pem \
  -days 365 -sha1 -nodes -subj "/CN=test.example.com"

查看证书签名算法:

1
2
$ openssl x509 -in /tmp/test-cert.pem -noout -text | grep "Signature Algorithm"
    Signature Algorithm: sha1WithRSAEncryption

尝试验证自签名证书:

1
2
$ openssl verify -CAfile /tmp/test-cert.pem /tmp/test-cert.pem
/tmp/test-cert.pem: OK

注意:自签名证书验证通常不会失败,因为 OpenSSL 仍然支持 SHA-1 用于签名验证,但使用 SHA-1 签名的证书链验证可能失败。

4. 查看当前 Provider 状态

1
2
3
4
5
6
$ openssl list -providers
Providers:
  default
    name: OpenSSL Default Provider
    version: 3.0.20
    status: active

可以看到只有 default Provider 处于 active 状态。

解决方案

方法一:命令行临时启用 Legacy Provider

对于单次操作,可以通过 -provider-propquery 参数临时启用 Legacy Provider:

使用 MD5 摘要

1
2
$ echo -n "test" | openssl dgst -md5 -provider legacy
MD5(stdin)= 098f6bcd4621d373cade4e832627b4f6

使用 DES 加密

1
2
$ echo -n "test" | openssl enc -des-ede3-cbc -provider legacy -pbkdf2 -salt -pass pass:password | base64
Salted__9'test encrypted data...=

验证 SHA-1 签名证书

1
2
$ openssl verify -CAfile /tmp/test-cert.pem -provider legacy /tmp/test-cert.pem
/tmp/test-cert.pem: OK

方法二:环境变量全局启用

设置环境变量让所有 OpenSSL 操作默认使用 Legacy Provider:

1
2
3
4
5
# 方式1:设置 Provider 路径
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules

# 方式2:通过 openssl.cnf 配置
# 见下文"方法三"

方法三:配置文件全局启用

编辑 OpenSSL 配置文件(通常是 /etc/ssl/openssl.cnf~/.openssl.cnf):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1
module = /usr/lib/x86_64-linux-gnu/ossl-modules/legacy.so

配置完成后,验证 Provider 加载:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ openssl list -providers
Providers:
  default
    name: OpenSSL Default Provider
    version: 3.0.20
    status: active
  legacy
    name: OpenSSL Legacy Provider
    version: 3.0.20
    status: active

现在 DES、MD5 等遗留算法可以正常使用:

1
2
3
4
5
$ echo -n "test" | openssl dgst -md5
MD5(stdin)= 098f6bcd4621d373cade4e832627b4f6

$ echo -n "test" | openssl enc -des-ede3-cbc -pbkdf2 -salt -pass pass:password | base64
U2FsdGVkX18+test encrypted output

方法四:针对特定算法使用 Property Query

可以使用 -propquery 参数精确控制使用哪个 Provider:

1
2
3
4
5
# 强制使用 legacy provider 的 MD5
echo -n "test" | openssl dgst -md5 -propquery "provider=legacy"

# 优先使用 default provider,fallback 到 legacy
echo -n "test" | openssl dgst -md5 -propquery "provider=default,provider=legacy"

Legacy Provider 包含的算法

Legacy Provider 提供以下遗留算法(请勿在生产环境使用):

摘要算法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ openssl list -digest-algorithms -provider legacy | grep -E "MD5|MD4|SHA1"
MD5
MD5-SHA1
MD4
RSA-MD4 => MD4
RSA-MD5 => MD5
sha1WithRSAEncryption => SHA1
SHA1
ssl3-md5 => MD5
ssl3-sha1 => SHA1

对称加密算法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ openssl list -cipher-algorithms -provider legacy | grep -E "DES|RC4|CAST"
DES-CBC
DES-CFB
DES-ECB
DES-EDE
DES-EDE-CBC
DES-EDE3-CBC
RC4
RC4-40
CAST5-CBC
...

签名算法

1
2
3
4
5
6
$ openssl list -signature-algorithms -provider legacy | grep -E "MD5|SHA1"
ecdsa-with-SHA1
sha1WithRSAEncryption
md5WithRSAEncryption
md5WithRSA
...

安全警告

⚠️ 重要提示:Legacy Provider 中的算法存在严重安全风险:

  • MD5:存在碰撞攻击,已被弃用
  • SHA-1:存在碰撞攻击,不推荐使用
  • DES:密钥空间太小(56 位),可暴力破解
  • RC4:存在多个安全漏洞,已被禁用

使用建议

  • 仅用于兼容旧系统
  • 尽快迁移到现代安全算法
  • 迁移完成后禁用 Legacy Provider
  • 切勿在生产环境新增使用这些算法

完整配置示例

以下是生产环境中处理遗留系统的推荐配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# /etc/ssl/openssl.cnf

openssl_conf = openssl_init

# 默认启用 default provider
[openssl_init]
providers = provider_sect
ssl_conf = ssl_sect

[provider_sect]
default = default_sect
# legacy 仅在需要时手动启用
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 0  # 默认禁用,手动启用
module = /usr/lib/x86_64-linux-gnu/ossl-modules/legacy.so

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
# 启用遗留协议兼容(可选)
# CipherString = DEFAULT:@SECLEVEL=1

启用 Legacy Provider:

1
2
3
4
# 临时启用
openssl genrsa -provider legacy 2048

# 或修改配置将 legacy 的 activate 改为 1

总结

  1. 问题根源:OpenSSL 3.x 默认只启用 Default Provider,遗留算法不可用
  2. 临时方案:使用 -provider legacy 命令行参数
  3. 全局方案:在 openssl.cnf 中配置 Legacy Provider
  4. 安全建议:仅用于兼容旧系统,尽快升级到现代安全算法

参考来源