OpenSSL

密码学与SSL/TLS工具包

ossl-guide-migration

名称

ossl-guide-migration, migration_guide - OpenSSL指南: 从旧版OpenSSL版本迁移

概要

有关详细信息,请参阅各个手册页。

描述

本指南详细说明了迁移到新版OpenSSL所需的更改。目前,这涵盖了OpenSSL 3.0和3.1。对于早期版本,请参考https://github.com/openssl/openssl/blob/master/CHANGES.md。有关OpenSSL 3.0中引入的一些关键概念的概述,请参见crypto(7).

OPENSSL 3.1

与OpenSSL 3.0的主要更改

OpenSSL 3.1中的FIPS提供程序包含一些未经FIPS验证的算法,因此,对于希望以FIPS批准的方式运行的应用程序来说,属性查询fips=yes是强制性的。这些算法是

三重DES ECB
三重DES CBC
EdDSA

自OpenSSL 3.0以来,没有其他更改需要额外的迁移措施。

OPENSSL 3.0

与OpenSSL 1.1.1的主要更改

主要版本

OpenSSL 3.0是一个主要版本,因此,任何当前使用旧版OpenSSL的应用程序至少都需要重新编译才能与新版本一起使用。我们的目标是让绝大多数应用程序在与OpenSSL 3.0一起使用时保持不变,前提是这些应用程序以前可以与OpenSSL 1.1.1一起使用。但是,这不能保证,在某些情况下可能需要进行一些更改。如果应用程序需要利用OpenSSL 3.0中提供的一些新功能,例如FIPS模块的可用性,也可能需要进行更改。

许可证变更

在以前的版本中,OpenSSL是根据双重OpenSSL和SSLeay许可证(两个许可证都适用)授权的。从OpenSSL 3.0开始,它被Apache License v2取代。

提供程序和FIPS支持

从OpenSSL 1.1.1开始,最关键的更改之一是引入了提供程序的概念。提供程序收集并提供算法实现。使用OpenSSL 3.0,您可以通过编程方式或通过配置文件来指定您想要为任何给定应用程序使用哪些提供程序。OpenSSL 3.0默认情况下附带5个不同的提供程序。随着时间的推移,第三方可能会发布可以插入OpenSSL的附加提供程序。通过提供程序提供的所有算法实现都是通过“高级”API访问的(例如,以EVP为前缀的那些函数)。它们无法使用“低级API”访问。

可用的标准提供程序之一是FIPS提供程序。它提供FIPS验证的加密算法。FIPS提供程序默认情况下处于禁用状态,需要在配置时使用enable-fips选项显式启用。如果启用它,除了其他标准提供程序之外,FIPS提供程序还会被构建并安装。无需单独的安装过程。但是,有一个专用的install_fips make目标,它专门用于将FIPS提供程序安装到现有OpenSSL安装中。

并非所有算法在特定时刻都可能对应用程序可用。如果应用程序代码通过EVP接口使用任何摘要或密码算法,则应用程序应验证EVP_EncryptInit(3)EVP_EncryptInit_ex(3)EVP_DigestInit(3)函数的结果。如果请求的算法不可用,这些函数将失败。

有关遗留提供程序的信息,请参见“遗留算法”

另请参见“完成FIPS模块的安装”“在应用程序中使用FIPS模块”

低级API

OpenSSL历来提供两组用于调用加密算法的API:“高级”API(例如EVP API)和“低级”API。高级API通常旨在跨所有算法类型工作。“低级”API针对的是特定算法实现。例如,EVP API提供函数EVP_EncryptInit_ex(3)EVP_EncryptUpdate(3)EVP_EncryptFinal(3)来执行对称加密。这些函数可与AES、CHACHA、3DES等算法一起使用。另一方面,要使用低级API进行AES加密,您需要调用特定于AES的函数,例如AES_set_encrypt_key(3)AES_encrypt(3)等等。3DES的函数不同。长期以来,OpenSSL开发团队一直不正式地反对使用低级API。但是,在OpenSSL 3.0中,这一点变得更加正式。所有这些低级API都已弃用。您仍然可以在应用程序中使用它们,但您可能会在编译期间开始看到弃用警告(取决于编译器对这方面的支持)。弃用的API可能会从未来的OpenSSL版本中删除,因此强烈建议您更新代码以改用高级API。

这在“低级函数的弃用”中有更详细的描述。

遗留算法

以前通过EVP API提供的某些加密算法(例如MD2DES)现在被认为是遗留算法,强烈建议不要使用它们。这些遗留的EVP算法仍然在OpenSSL 3.0中可用,但不是默认情况下。如果您想使用它们,则必须加载遗留提供程序。这可以像更改配置文件一样简单,也可以通过编程方式完成。有关算法的完整列表,请参见OSSL_PROVIDER-legacy(7)。使用EVP API访问这些算法的应用程序应改用更现代的算法。如果不可能,那么这些应用程序应确保已加载遗留提供程序。可以通过编程方式或通过配置来实现。有关提供程序的更多信息,请参见crypto(7)手册页。

引擎和“METHOD” API

用于支持提供程序的重构在内部与用于支持引擎的API冲突,包括引擎API以及创建或修改自定义“METHOD”的任何函数(例如EVP_MD_meth_new(3)EVP_CIPHER_meth_new(3)EVP_PKEY_meth_new(3)RSA_meth_new(3)EC_KEY_METHOD_new(3)等等)。这些函数在OpenSSL 3.0中被弃用,使用这些API的用户应知道,他们的使用可能会绕过提供程序选择和配置,从而导致意想不到的后果。这对于编写用于使用OpenSSL 3.0 FIPS模块的应用程序尤其重要,如下所述。强烈建议外部引擎的作者和维护人员重构其代码,将引擎转换为使用新提供程序API的提供程序,并避免使用弃用方法。

对遗留引擎的支持

如果openssl不是在没有引擎支持或弃用API支持的情况下构建的,则引擎仍然可以使用。但是,它们的适用性将受到限制。

通过引擎提供的新算法仍然可以使用。

基于引擎的密钥可以通过自定义OSSL_STORE实现加载。在这种情况下,通过ENGINE_load_private_key(3)创建的EVP_PKEY对象将被视为遗留对象,并将继续使用。

为了确保将来的兼容性,引擎应转换为提供程序。为了优先考虑基于提供程序的硬件卸载,您可以指定默认属性以优先考虑您的提供程序。

设置基于引擎或基于应用程序的默认低级加密方法(如RSA_METHODEC_KEY_METHOD)仍然可行,默认提供程序中的密钥将使用基于引擎的实现进行加密操作。但是,通过使用OSSL_DECODERPEM_d2i_ API解码创建的EVP_PKEY将是基于提供程序的。要创建完全遗留的EVP_PKEY,必须使用EVP_PKEY_set1_RSA(3)EVP_PKEY_set1_EC_KEY(3)或类似函数。

版本方案

OpenSSL版本方案已随OpenSSL 3.0版本发布而更改。新的版本方案具有以下格式

MAJOR.MINOR.PATCH

对于OpenSSL 1.1.1及更低版本,不同的修补程序级别由版本号末尾的字母表示。这将不再使用,而是由版本中的最后一个数字表示修补程序级别。第二个(次要)数字的更改表明可能添加了新功能。具有相同主要版本的OpenSSL版本是API和ABI兼容的。如果主要版本发生变化,则API和ABI兼容性不能保证。

有关更多信息,请参见OpenSSL_version(3)

其他主要新功能
证书管理协议(CMP,RFC 4210)

这也涵盖了CRMF(RFC 4211)和HTTP传输(RFC 6712)。请参见openssl-cmp(1)OSSL_CMP_exec_certreq(3)作为起点。

HTTP(S) 客户端

一个支持GET和POST、重定向、纯文本和ASN.1编码内容、代理和超时的适当的HTTP(S)客户端。

密钥派生函数API(EVP_KDF)

这简化了添加新的KDF和PRF实现的过程。

以前,KDF算法被硬塞到使用EVP_PKEY对象中,这并不是一个逻辑映射。使用EVP_PKEY(scrypt、TLS1 PRF和HKDF)使用KDF算法的现有应用程序可能速度较慢,因为它们在内部使用EVP_KDF桥接。所有新的应用程序都应使用新的EVP_KDF(3)接口。另请参见OSSL_PROVIDER-default(7)中的“密钥派生函数(KDF)”OSSL_PROVIDER-FIPS(7)中的“密钥派生函数(KDF)”

消息认证码API(EVP_MAC)

这简化了添加MAC实现的过程。

这包括一个通用的EVP_PKEY到EVP_MAC桥接,以方便通过原始私钥在EVP_DigestSign(3)EVP_DigestVerify(3)等功能中继续使用MAC。

所有新的应用程序都应使用新的EVP_MAC(3)接口。另请参见OSSL_PROVIDER-default(7)中的“消息认证码(MAC)”OSSL_PROVIDER-FIPS(7)中的“消息认证码(MAC)”

算法获取

使用EVP_sha256()和EVP_aes_256_gcm()等便捷函数的调用可能会在使用提供程序时造成性能损失。从提供程序检索算法涉及按名称搜索算法。这比直接访问方法表要慢得多。建议如果多次使用算法,则预取算法。请参见crypto(7)中的“性能”crypto(7)中的“显式获取”crypto(7)中的“隐式获取”

对Linux内核TLS的支持

为了使用KTLS,必须使用enable-ktls配置选项将其编译进去。还必须使用SSL_OP_ENABLE_KTLS选项在运行时启用它。

新算法
  • KDF算法“SINGLE STEP”和“SSH”

    请参见EVP_KDF-SS(7)EVP_KDF-SSHKDF(7)

  • MAC算法“GMAC”和“KMAC”

    请参见EVP_MAC-GMAC(7)EVP_MAC-KMAC(7)

  • KEM算法“RSASVE”

    请参见EVP_KEM-RSA(7)

  • 密码算法“AES-SIV”

    请参见EVP_EncryptInit(3)中的“SIV模式”

  • EVP层支持的AES密钥包装反向密码。

    反向密码使用AES解密进行包装,使用AES加密进行解包。这些算法是:“AES-128-WRAP-INV”、“AES-192-WRAP-INV”、“AES-256-WRAP-INV”、“AES-128-WRAP-PAD-INV”、“AES-192-WRAP-PAD-INV”和“AES-256-WRAP-PAD-INV”。

  • 将CTS密码添加到EVP层。

    算法包括“AES-128-CBC-CTS”、“AES-192-CBC-CTS”、“AES-256-CBC-CTS”、“CAMELLIA-128-CBC-CTS”、“CAMELLIA-192-CBC-CTS”和“CAMELLIA-256-CBC-CTS”。支持 CS1、CS2 和 CS3 变体。

CMS 和 PKCS#7 更新
  • 添加了 CAdES-BES 签名验证支持。

  • 在 CMS API 中添加了 CAdES-BES 签名方案和属性支持(RFC 5126)。

  • 使用 AES_GCM 添加了 AuthEnvelopedData 内容类型结构(RFC 5083)

    这使用 AES-GCM 参数(RFC 5084)用于加密消息语法。它的目的是支持对使用 AES GCM 模式进行身份验证和加密的数字信封进行加密和解密。

  • PKCS7_get_octet_string(3)PKCS7_type_is_other(3) 已公开。

PKCS#12 API 更新

使用 PKCS12_create() 函数创建 pkcs12 的默认算法已更改为更现代的 PBKDF2 和基于 AES 的算法。默认 MAC 迭代次数已更改为 PKCS12_DEFAULT_ITER,使其与基于密码的加密迭代次数相同。MAC 计算的默认摘要算法已更改为 SHA-256。pkcs12 应用程序现在支持 -legacy 选项,该选项会将以前的默认算法恢复,以支持与传统系统的互操作性。

添加了增强的 PKCS#12 API,这些 API 接受一个库上下文 OSSL_LIB_CTX 和(在相关的情况下)一个属性查询。处理 PKCS#7 和 PKCS#8 对象的其他 API 也已在需要时得到增强。这包括

PKCS12_add_key_ex(3)PKCS12_add_safe_ex(3)PKCS12_add_safes_ex(3)PKCS12_create_ex(3)PKCS12_decrypt_skey_ex(3)PKCS12_init_ex(3)PKCS12_item_decrypt_d2i_ex(3)PKCS12_item_i2d_encrypt_ex(3)PKCS12_key_gen_asc_ex(3)PKCS12_key_gen_uni_ex(3)PKCS12_key_gen_utf8_ex(3)PKCS12_pack_p7encdata_ex(3)PKCS12_pbe_crypt_ex(3)PKCS12_PBE_keyivgen_ex(3)PKCS12_SAFEBAG_create_pkcs8_encrypt_ex(3)PKCS5_pbe2_set_iv_ex(3)PKCS5_pbe_set0_algor_ex(3)PKCS5_pbe_set_ex(3)PKCS5_pbkdf2_set_ex(3)PKCS5_v2_PBE_keyivgen_ex(3)PKCS5_v2_scrypt_keyivgen_ex(3)PKCS8_decrypt_ex(3)PKCS8_encrypt_ex(3)PKCS8_set0_pbe_ex(3)

作为此更改的一部分,EVP_PBE_xxx API 也能接受库上下文和属性查询,并将调用支持这些参数的扩展版本的关键/IV 推导函数。这包括 EVP_PBE_CipherInit_ex(3)EVP_PBE_find_ex(3)EVP_PBE_scrypt_ex(3)

PKCS#12 KDF 与 FIPS

与 1.x.y 中不同,当使用不适用于 FIPS 提供程序的 MAC 创建 PKCS#12 结构时,使用的 PKCS12KDF 算法不起作用,因为 PKCS12KDF 不是 FIPS 可接受的机制。

请参阅 EVP_KDF-PKCS12KDF(7)PKCS12_create(3)openssl-pkcs12(1)OSSL_PROVIDER-FIPS(7)

Windows 线程同步更改

Windows 线程同步在操作系统支持的情况下使用读/写原语 (SRWLock),否则继续使用 CriticalSection。

跟踪 API

添加了一个新的通用跟踪 API,它提供了通过跟踪输出启用检测的支持。此功能主要旨在帮助开发人员,默认情况下处于禁用状态。要使用它,OpenSSL 需要使用 enable-trace 选项进行配置。

如果启用了跟踪 API,则应用程序可以通过将 BIO 注册为多个跟踪和调试类别的跟踪通道来激活跟踪输出。请参阅 OSSL_trace_enabled(3)

密钥验证更新

EVP_PKEY_public_check(3)EVP_PKEY_param_check(3) 现在适用于更多密钥类型。这包括 RSA、DSA、ED25519、X25519、ED448 和 X448。以前(在 1.1.1 中)它们会返回 -2。对于没有参数的密钥类型,EVP_PKEY_param_check(3) 将始终返回 1。

其他值得注意的弃用和更改
OpenSSL 错误代码的函数代码部分不再相关

此代码现在始终设置为零。相关函数已弃用。

STACK 和 HASH 宏已清理

类型安全包装器在所有地方声明,并在一个地方实现。请参阅 DEFINE_STACK_OF(3)DEFINE_LHASH_OF_EX(3)

RAND_DRBG 子系统已删除

新的 EVP_RAND(3) 是部分替代:DRBG 回调框架不存在。RAND_DRBG API 不适合 EVP_RAND 和 EVP_RAND_CTX 实现的新提供程序概念。

已删除 FIPS_mode() 和 FIPS_mode_set()

这些函数是旧版 API,不适用于新的提供程序模型。应用程序应改用 EVP_default_properties_is_fips_enabled(3)EVP_default_properties_enable_fips(3)

密钥生成速度变慢

Miller-Rabin 测试现在使用 64 轮,用于所有素数生成,包括 RSA 密钥生成。这会影响较大密钥大小的时间。

常规 2 素数 RSA 密钥的默认密钥生成方法已更改为 FIPS186-4 B.3.6 方法(基于辅助可能素数的条件的可能素数的生成)。此方法比原始方法慢。

将 PBKDF2 更改为符合 SP800-132,而不是旧的 PKCS5 RFC2898

这会检查盐长度至少为 128 位,派生密钥长度至少为 112 位,迭代次数至少为 1000。为了向后兼容,这些检查默认情况下在默认提供程序中处于禁用状态,但在 FIPS 提供程序中默认情况下处于启用状态。

要启用或禁用检查,请参阅 EVP_KDF-PBKDF2(7) 中的 OSSL_KDF_PARAM_PKCS5。可以使用 EVP_KDF_derive(3) 设置参数。

强制 DH 模数大小最小为 512 位

较小的尺寸现在会导致错误。

SM2 密钥更改

使用 SM2 曲线的 EC EVP_PKEY 已重新设计,以自动变为 EVP_PKEY_SM2,而不是 EVP_PKEY_EC。

与以前的 OpenSSL 版本不同,这意味着应用程序不能调用 EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2) 来获得 SM2 计算。

参数和密钥生成也已重新设计,使其能够生成 EVP_PKEY_SM2 参数和密钥。应用程序现在必须直接生成 SM2 密钥,并且不得先创建 EVP_PKEY_EC 密钥。现在不再能够使用除 SM2 椭圆曲线以外的域参数导入 SM2 密钥。

SM2 密钥的验证已与常规 EC 密钥的验证分离,从而可以改进 SM2 验证过程,以拒绝与 SM2 ISO 标准不符的已加载私钥。特别是,现在会正确拒绝范围 1 <= k < n-1 之外的私有标量 k

已删除 EVP_PKEY_set_alias_type() 方法

此函数使 EVP_PKEY 对象在设置后可变。在 OpenSSL 3.0 中,决定提供的密钥不应该能够更改其类型,因此该函数已被删除。

返回内部密钥的函数应视为只读

诸如 EVP_PKEY_get0_RSA(3) 之类的函数在 OpenSSL 3.0 中的行为略有不同。以前它们返回一个指向 libcrypto 内部使用的低级密钥的指针。从 OpenSSL 3.0 开始,此密钥现在可能保存在提供程序中。调用这些函数只会返回内部密钥的句柄,其中 EVP_PKEY 最初使用此密钥构造,例如使用诸如 EVP_PKEY_assign_RSA(3)EVP_PKEY_set1_RSA(3) 等函数或宏。如果 EVP_PKEY 持有一个提供程序管理的密钥,那么这些函数现在会返回一个缓存的密钥副本。在第一次访问缓存的密钥之后发生的内部提供程序密钥的更改不会反映到缓存的副本中。同样,应用程序代码对缓存副本所做的任何更改都不会反映到内部提供程序密钥中。

由于上述原因,从这些函数返回的密钥通常应视为只读。为了强调这一点,从 EVP_PKEY_get0_RSA(3)EVP_PKEY_get0_DSA(3)EVP_PKEY_get0_EC_KEY(3)EVP_PKEY_get0_DH(3) 返回的值已设为 const。这可能会破坏一些现有代码。应修改受此更改影响的应用程序。首选的解决方案是重构代码,避免使用这些已弃用的函数。如果无法做到这一点,则应修改代码以使用 const 指针。 EVP_PKEY_get1_RSA(3)EVP_PKEY_get1_DSA(3)EVP_PKEY_get1_EC_KEY(3)EVP_PKEY_get1_DH(3) 函数继续返回一个非 const 指针,以使它们能够被“释放”。但是,它们也应视为只读。

公钥检查已从 EVP_PKEY_derive() 移动到 EVP_PKEY_derive_set_peer()

这意味着可能会在 EVP_PKEY_derive_set_peer(3) 中导致错误,而不是在 EVP_PKEY_derive(3) 期间导致错误。要禁用此检查,请使用 EVP_PKEY_derive_set_peer_ex(dh, peer, 0)。

打印格式对某些函数进行了美观上的更改

X509_signature_print(3)X509_print_ex(3)X509_CRL_print_ex(3) 等许多“打印”函数的输出已修改,因此在 1.1.1 和 3.0 中观察到的输出之间可能会存在美观上的差异。这同样适用于 openssl x509openssl crl 应用程序的 -text 输出。

已删除 openssl 程序的交互模式

从现在开始,在不带参数的情况下运行它等效于 openssl help

一些控制调用 (ctrl) 的错误返回值已更改

一项重大更改是,以前对无效输入返回 -2 的控制现在返回 -1,表示一个通用的错误条件。

DH 和 DHX 密钥类型具有不同的可设置参数

以前(在 1.1.1 中)允许这些冲突的参数,但现在会导致错误。请参阅 EVP_PKEY-DH(7) 以获取更多详细信息。这会影响 openssl-genpkey(1) 对 DH 参数生成的执行行为。

EVP_CIPHER_CTX_set_flags() 排序更改

如果使用来自提供程序的密码,则只能在将密码分配给密码上下文 设置 EVP_CIPH_FLAG_LENGTH_BITS 标志。请参阅 EVP_EncryptInit(3) 中的“FLAGS” 以获取更多信息。

操作上下文参数的验证

由于将密码操作的实现移至提供程序,因此可以将各种操作参数的验证推迟到实际执行操作时,而以前是在设置操作参数时立即进行的。

例如,当使用 EVP_PKEY_CTX_set_ec_paramgen_curve_nid() 设置不支持的曲线时,此函数调用不会失败,但稍后使用 EVP_PKEY_CTX 的 keygen 操作将失败。

从错误代码中移除函数代码

错误代码中的函数代码部分现在始终设置为 0。因此,ERR_GET_FUNC() 宏已被移除。应用程序必须仅使用库编号和原因代码来解析错误代码。

ChaCha20-Poly1305 密码不允许使用截断的 IV 长度

在 OpenSSL 3.0 中,将 IV 长度设置为除 12 以外的任何值都会导致错误。在 OpenSSL 3.0 之前,ivlen 可以小于所需的 12 字节长度,使用 EVP_CIPHER_CTX_ctrl(ctx, EVP_CRTL_AEAD_SET_IVLEN, ivlen, NULL)。这会导致 IV 具有前导零填充。

安装和编译

请参考发行版顶部的 INSTALL.md 文件以获取有关如何构建和安装 OpenSSL 3.0 的说明。请还参考各种平台特定的 NOTES 文件,以了解您的特定平台。

从 OpenSSL 1.1.1 升级

在大多数情况下,从 OpenSSL 1.1.1 升级到 OpenSSL 3.0 应该相对简单。您最有可能遇到问题的领域是,如果您的代码中使用了低级 API(如上所述)。在这种情况下,您在编译应用程序时可能会开始看到弃用警告。如果发生这种情况,您有 3 个选项

  1. 忽略警告。它们只是警告。弃用的函数仍然存在,您仍然可以使用它们。但是请注意,它们可能会从 OpenSSL 的未来版本中移除。

  2. 抑制警告。请参考您的编译器文档,了解如何执行此操作。

  3. 移除对低级 API 的使用。在这种情况下,您需要重写您的代码以改用高级 API

错误代码更改

由于 OpenSSL 3.0 为处理广泛使用的文件格式提供了一种全新的编码器/解码器机制,因此在密钥加载失败时检查特定错误原因代码的应用程序代码可能需要更新。

受密码保护的密钥可能需要特别注意。如果仅将某些错误视为用户应再次被询问密码的指示,则值得测试这些场景并处理新相关的代码。

根据调用应用程序代码,可能需要特殊处理更多情况。

从 OpenSSL 1.0.2 升级

从 OpenSSL 1.0.2 升级到 OpenSSL 3.0 可能要困难得多。除了上述关于 "从 OpenSSL 1.1.1 升级" 部分中讨论的问题之外,主要需要注意的是

  1. 构建和安装过程已发生重大变化。

    检查安装顶部的 INSTALL.md 文件,以获取有关如何为您的平台构建和安装 OpenSSL 的说明。还需要阅读相同目录中的各种 NOTES 文件(如果适用于您的平台)。

  2. 在 OpenSSL 3.0 中,许多结构已变为不透明。

    结构定义已从公共头文件中移除,并移至内部头文件。实际上,这意味着您不再可以堆栈分配某些结构。相反,它们必须通过某种函数调用进行堆分配(通常,这些函数名称以 _new 后缀结尾)。此外,您必须使用“设置器”或“获取器”函数来访问这些结构中的字段。

    例如,以前看起来像这样的代码

    EVP_MD_CTX md_ctx;
    
    /* This line will now generate compiler errors */
    EVP_MD_CTX_init(&md_ctx);

    需要修改代码以使其看起来像这样

    EVP_MD_CTX *md_ctx;
    
    md_ctx = EVP_MD_CTX_new();
    ...
    ...
    EVP_MD_CTX_free(md_ctx);
  3. 已添加对 TLSv1.3 的支持。

    这对 SSL/TLS 应用程序有许多影响。有关更多详细信息,请参阅 TLS1.3 页面

有关 OpenSSL 版本 1.0.2 和 1.1.0 之间重大更改的更多详细信息,请参阅 OpenSSL 1.1.0 更改页面

从 OpenSSL 2.0 FIPS 对象模块升级

OpenSSL 2.0 FIPS 对象模块是一个单独的下载文件,必须单独构建,然后集成到您的主 OpenSSL 1.0.2 构建中。在 OpenSSL 3.0 中,FIPS 支持已完全集成到 OpenSSL 的主线版本中,不再是一个单独的下载文件。有关更多信息,请参阅 "完成 FIPS 模块的安装"

函数调用 FIPS_mode() 和 FIPS_mode_set() 已从 OpenSSL 3.0 中移除。您应该重写您的应用程序,使其不再使用它们。有关详细信息,请参阅 fips_module(7)OSSL_PROVIDER-FIPS(7)

完成 FIPS 模块的安装

如果已配置 FIPS 支持,则 FIPS 模块将自动构建并安装。当前文档可以在 README-FIPS 文件中找到。

编程

为与 OpenSSL 1.1.1 协同工作而编写的应用程序在大多数情况下可以直接与 OpenSSL 3.0 协同工作。但是,如果您想利用 OpenSSL 3.0 提供的一些新功能,则需要进行更改。为此,您需要了解 OpenSSL 3.0 中引入的一些新概念。有关更多信息,请阅读 "库上下文",位于 crypto(7) 中

库上下文

库上下文允许复杂应用程序的不同组件分别使用不同的库上下文,并加载具有不同配置设置的不同提供程序。有关更多信息,请参阅 "库上下文",位于 crypto(7) 中

如果用户通过 OSSL_LIB_CTX_new(3) 创建一个 OSSL_LIB_CTX,则许多函数可能需要更改为传递额外的参数来处理库上下文。

使用库上下文 - 应更改的旧函数

如果需要库上下文,则所有返回 const EVP_MD * 的 EVP_* 摘要函数(例如 EVP_sha256())都应替换为对 EVP_MD_fetch(3) 的调用。请参阅 "算法获取",位于 crypto(7) 中

如果需要库上下文,则所有返回 const EVP_CIPHER * 的 EVP_* 密码函数(例如 EVP_aes_128_cbc())都应替换为对 EVP_CIPHER_fetch(3) 的调用。请参阅 "算法获取",位于 crypto(7) 中

某些函数可以传递一个已使用库上下文设置的对象,例如 d2i_X509(3)d2i_X509_CRL(3)d2i_X509_REQ(3)d2i_X509_PUBKEY(3)。如果改为传递 NULL,则创建的对象将使用默认库上下文进行设置。如果需要库上下文,请使用 X509_new_ex(3)X509_CRL_new_ex(3)X509_REQ_new_ex(3)X509_PUBKEY_new_ex(3)

下面列出的所有带有 NAME 的函数都具有一个替换函数 NAME_ex,该函数将 OSSL_LIB_CTX 作为附加参数。具有其他映射的函数将与相应的名称一起列出。

使用库上下文的新的函数

以下函数可以在需要时传递库上下文。传递 NULL 将使用默认库上下文。

提供者

提供者在此处详细说明 crypto(7) 中的“提供者”。另见 crypto(7) 中的“OPENSSL 提供者”

获取算法和属性查询

隐式和显式获取在此处详细说明 crypto(7) 中的“算法获取”

将 EVP 控制和标志映射到提供者 OSSL_PARAM(3) 参数

用于控制的现有函数(如 EVP_CIPHER_CTX_ctrl(3))和操作标志(如 EVP_MD_CTX_set_flags(3))在内部使用 OSSL_PARAMS 将信息传递给/从提供者对象。有关参数的更多信息,请参见 OSSL_PARAM(3)

对于密码,请参见 EVP_EncryptInit(3) 中的“控制”EVP_EncryptInit(3) 中的“标志”EVP_EncryptInit(3) 中的“参数”

对于摘要,请参见 EVP_DigestInit(3) 中的“控制”EVP_DigestInit(3) 中的“标志”EVP_DigestInit(3) 中的“参数”

弃用低级函数

OpenSSL 3.0 中已弃用大量 API。本节介绍一些常见的弃用类别。有关引用这些类别的弃用函数的列表,请参见 “弃用函数映射”

提供者是引擎和低级方法覆盖的替代品

任何使用引擎的访问器都已弃用(例如 EVP_PKEY_set1_engine())。使用引擎的应用程序应改为使用提供者。

在添加提供者之前,算法通过更改算法使用的代码来覆盖。所有这些方法(如 RSA_new_method() 和 RSA_meth_new())现在已弃用,可以改为使用提供者。

弃用低级密钥类型的 i2d 和 d2i 函数

任何 i2d 和 d2i 函数(如 d2i_DHparams())都已弃用,它们采用低级密钥类型。应用程序应改为使用 OSSL_DECODER(3)OSSL_ENCODER(3) API 来读取和写入文件。有关更多详细信息,请参见 d2i_RSAPrivateKey(3) 中的“迁移”

弃用低级密钥对象获取器和设置器

设置或获取低级密钥对象(如 EVP_PKEY_set1_DH() 或 EVP_PKEY_get0())的应用程序应改为使用 OSSL_ENCODER(请参见 OSSL_ENCODER_to_bio(3))或 OSSL_DECODER(请参见 OSSL_DECODER_from_bio(3))API,或者使用 EVP_PKEY_fromdata(3)EVP_PKEY_todata(3)

弃用低级密钥参数获取器

直接访问低级对象的函数(如 RSA_get0_n(3))现已弃用。应用程序应使用 EVP_PKEY_get_bn_param(3)EVP_PKEY_get_int_param(3)、l<EVP_PKEY_get_size_t_param(3)>、EVP_PKEY_get_utf8_string_param(3)EVP_PKEY_get_octet_string_param(3)EVP_PKEY_get_params(3) 来访问 EVP_PKEY 中的字段。可获取的参数列于 EVP_PKEY-RSA(7) 中的“通用 RSA 参数”EVP_PKEY-DH(7) 中的“DH 参数”EVP_PKEY-DSA(7) 中的“DSA 参数”EVP_PKEY-FFC(7) 中的“FFC 参数”EVP_PKEY-EC(7) 中的“通用 EC 参数”EVP_PKEY-X25519(7) 中的“通用 X25519、X448、ED25519 和 ED448 参数” 中。应用程序也可以使用 EVP_PKEY_todata(3) 来返回所有字段。

弃用低级密钥参数设置器

直接访问低级对象的函数(如 RSA_set0_crt_params(3))现已弃用。应用程序应使用 EVP_PKEY_fromdata(3) 从用户提供的密钥数据创建新密钥。密钥创建后应为不可变,因此,如果需要,用户可以使用 EVP_PKEY_todata(3)OSSL_PARAM_merge(3)EVP_PKEY_fromdata(3) 来创建修改后的密钥。有关更多信息,请参见 EVP_PKEY-DH(7) 中的“示例”。有关使用参数生成密钥的信息,请参见 “弃用低级密钥生成函数”

弃用低级对象创建

低级对象是使用 RSA_new(3)RSA_up_ref(3)RSA_free(3) 等方法创建的。应用程序应改为使用高级 EVP_PKEY API,例如 EVP_PKEY_new(3)EVP_PKEY_up_ref(3)EVP_PKEY_free(3)。另请参见 EVP_PKEY_CTX_new_from_name(3)EVP_PKEY_CTX_new_from_pkey(3)

EVP_PKEY 可以通过多种方式创建:另请参见 “弃用低级密钥生成函数”“弃用低级密钥读取和写入函数”“弃用低级密钥参数设置器”

弃用低级加密函数

长时间以来,低级加密函数(如 AES_encrypt(3)AES_decrypt(3))一直被非正式地不建议使用。应用程序应改为使用高级 EVP API EVP_EncryptInit_ex(3)EVP_EncryptUpdate(3)EVP_EncryptFinal_ex(3)EVP_DecryptInit_ex(3)EVP_DecryptUpdate(3)EVP_DecryptFinal_ex(3)

弃用低级摘要函数

长时间以来,低级摘要函数(如 SHA1_Init(3))一直被非正式地不建议使用。应用程序应改为使用高级 EVP API EVP_DigestInit_ex(3)EVP_DigestUpdate(3)EVP_DigestFinal_ex(3),或快速的一次性 EVP_Q_digest(3)

请注意,函数 SHA1(3)SHA224(3)SHA256(3)SHA384(3)SHA512(3) 已更改为使用 EVP_Q_digest(3) 的宏。

弃用低级签名函数

长时间以来,低级签名函数(如 DSA_sign(3))一直被非正式地不建议使用。应用程序应改为使用 EVP_DigestSign(3)EVP_DigestVerify(3)。另请参见 EVP_SIGNATURE-RSA(7)EVP_SIGNATURE-DSA(7)EVP_SIGNATURE-ECDSA(7)EVP_SIGNATURE-ED25519(7)

弃用低级 MAC 函数

低级 mac 函数(如 CMAC_Init(3))已弃用。应用程序应改为使用新的 EVP_MAC(3) 接口,使用 EVP_MAC_CTX_new(3)EVP_MAC_CTX_free(3)EVP_MAC_init(3)EVP_MAC_update(3)EVP_MAC_final(3),或使用一次性 MAC 函数 EVP_Q_mac(3)。有关更多信息,请参见 EVP_MAC(3)EVP_MAC-HMAC(7)EVP_MAC-CMAC(7)EVP_MAC-GMAC(7)EVP_MAC-KMAC(7)EVP_MAC-BLAKE2(7)EVP_MAC-Poly1305(7)EVP_MAC-Siphash(7)

请注意,一次性方法 HMAC() 仍然可用以确保兼容性,但如果需要库上下文,也可以用 EVP_Q_MAC 替换。

弃用低级验证函数

长时间以来,低级验证函数(如 DH_check(3))一直被非正式地不建议使用。应用程序应改为使用高级 EVP_PKEY API,例如 EVP_PKEY_check(3)EVP_PKEY_param_check(3)EVP_PKEY_param_check_quick(3)EVP_PKEY_public_check(3)EVP_PKEY_public_check_quick(3)EVP_PKEY_private_check(3)EVP_PKEY_pairwise_check(3)

弃用低级密钥交换函数

长时间以来,许多低级函数一直被非正式地不建议使用。应用程序应改为使用 EVP_PKEY_derive(3)。请参见 EVP_KEYEXCH-DH(7)EVP_KEYEXCH-ECDH(7)EVP_KEYEXCH-X25519(7)

弃用低级密钥生成函数

长时间以来,许多低级函数一直被非正式地不建议使用。应用程序应改为使用 EVP_PKEY_keygen_init(3)EVP_PKEY_generate(3),如 EVP_PKEY-DSA(7)EVP_PKEY-DH(7)EVP_PKEY-RSA(7)EVP_PKEY-EC(7)EVP_PKEY-X25519(7) 中所述。也可以使用“快速”一次性函数 EVP_PKEY_Q_keygen(3) 和最常见情况的宏:<EVP_RSA_gen(3)> 和 EVP_EC_gen(3)

弃用低级密钥读取和写入函数

长时间以来,低级对象(如 DSA)一直被非正式地不建议使用。用于读取和写入这些低级对象的函数(如 PEM_read_DSA_PUBKEY())应被替换。应用程序应改为使用 OSSL_ENCODER_to_bio(3)OSSL_DECODER_from_bio(3)

弃用低级密钥打印函数

长期以来,一直不鼓励使用低级对象(如 DSA)。用于打印这些低级对象的函数,例如 DSA_print(),应该被等效的 EVP_PKEY 函数替换。应用程序应使用以下函数之一:EVP_PKEY_print_public(3)EVP_PKEY_print_private(3)EVP_PKEY_print_params(3)EVP_PKEY_print_public_fp(3)EVP_PKEY_print_private_fp(3)EVP_PKEY_print_params_fp(3)。请注意,在内部,这些函数使用 OSSL_ENCODER_to_bio(3)OSSL_DECODER_from_bio(3)

已弃用函数映射

以下函数在 3.0 中已弃用。

为提供的密钥和算法处理 NID

用于处理 NID(数字 ID)的以下函数已更改语义。

  • EVP_PKEY_id()、EVP_PKEY_get_id()

    此函数以前用于可靠地返回 EVP_PKEY 对象的 NID,例如,通过调用 OBJ_nid2sn(3) 来查找此类 EVP_PKEY 的算法名称。随着 provider(7) 的引入,EVP_PKEY_id() 或其新的等效项 EVP_PKEY_get_id(3) 现在也可能返回值 -1 (EVP_PKEY_KEYMGMT),表示使用提供程序来实现 EVP_PKEY 对象。因此,建议使用 EVP_PKEY_get0_type_name(3) 来检索 EVP_PKEY 算法的名称。

在应用程序中使用 FIPS 模块

有关详细信息,请参阅 fips_module(7)OSSL_PROVIDER-FIPS(7)

OpenSSL 命令行应用程序更改

新应用程序

openssl kdf 使用新的 EVP_KDF(3) API。 openssl kdf 使用新的 EVP_MAC(3) API。

添加的选项

-provider_path-provider 可用于所有应用程序,并且可以多次使用以加载任何提供程序,例如“legacy”提供程序或第三方提供程序。如果使用,则还需要指定“default”提供程序(如果需要)。-provider_path 必须在 -provider 选项之前指定。

list 应用程序有许多新选项。有关更多信息,请参阅 openssl-list(1)

-crl_lastupdate-crl_nextupdateopenssl ca 使用,允许显式设置生成的 CRL 中的字段。

移除的选项

交互模式不再可用。

openssl passwd 使用的 -crypt 选项。openssl x509openssl dhparamopenssl dsaparamopenssl ecparam 使用的 -c 选项。

其他更改

命令行应用程序的输出可能会有细微变化。这些主要是大小写和空格方面的更改。但是,在某些情况下,还存在其他差异。例如,openssl dhparam 输出的 DH 参数现在列出“P”、“Q”、“G”和“pcounter”,而不是分别列出“prime”、“generator”、“subgroup order”和“counter”。

读取密钥、证书和 CRL 的 openssl 命令现在会自动检测输入文件的 PEM 或 DER 格式,因此不再需要显式指定输入格式。但是,如果使用输入格式选项,则需要指定格式。

openssl speed 不再使用低级 API 调用。这意味着由于开销较高,某些性能指标可能与以前版本不可比。这尤其适用于测量较小数据块上的性能。

b<openssl dhparam>、openssl dsaopenssl gendsaopenssl dsaparamopenssl genrsaopenssl rsa 已修改为使用 PKEY API。openssl genrsaopenssl rsa 现在默认写入 PKCS #8 密钥。

默认设置

“SHA256”现在是 openssl ts 使用的 TS 查询的默认摘要。

已弃用的应用程序

openssl rsautl 已弃用,请改用 openssl pkeyutlopenssl dhparamopenssl dsaopenssl gendsaopenssl dsaparamopenssl genrsaopenssl rsaopenssl genrsaopenssl rsa 现在处于维护模式,不会向其中添加新功能。

TLS 更改

  • 添加了 TLS 1.3 FFDHE 密钥交换支持

    这使用名为 DH 安全素数的组。

  • 支持完全“可插拔”的 TLSv1.3 组。

    这意味着提供程序可以提供自己的组实现(使用“密钥交换”或“密钥封装”方法),这些实现将被 libssl 自动检测和使用。

  • SSL 和 SSL_CTX 选项现在是 64 位而不是 32 位。

    用于获取和设置 SSL 和 SSL_CTX 对象上的选项的函数签名已从“unsigned long”更改为“uint64_t”类型。

    这可能需要更改源代码。例如,不再可以在预处理器 #if 条件中使用 SSL_OP_ 宏值。但是,仍然可以测试这些宏是否已定义。

    请参阅 SSL_CTX_get_options(3)SSL_CTX_set_options(3)SSL_get_options(3)SSL_set_options(3)

  • SSL_set1_host() 和 SSL_add1_host() 更改

    这些函数现在接受 IP 文字地址以及实际主机名。

  • 添加了 SSL 选项 SSL_OP_CLEANSE_PLAINTEXT

    如果设置了该选项,openssl 会在将明文字节传递给应用程序后清理(清零)内部缓冲区中的明文字节。注意,应用程序仍然负责清理其他副本(例如:通过 SSL_read(3) 接收的数据)。

  • 默认情况下禁用客户端发起的重新协商。

    要允许重新协商,请使用 -client_renegotiation 选项、SSL_OP_ALLOW_CLIENT_RENEGOTIATION 标志或 ClientRenegotiation 配置参数(视情况而定)。

  • 安全重新协商现在是 TLS 连接的默认要求

    现在默认要求支持 RFC 5746 安全重新协商,才能成功建立 SSL 或 TLS 连接。需要连接到旧版对等方的应用程序需要显式设置 SSL_OP_LEGACY_SERVER_CONNECT。因此,SSL_OP_LEGACY_SERVER_CONNECT 不再作为 SSL_OP_ALL 的一部分设置。

  • 组合配置选项 no-ec 和 no-dh 不再禁用 TLSv1.3

    通常,如果 OpenSSL 没有 EC 或 DH 算法,则它无法支持使用 TLSv1.3 的连接。但是,OpenSSL 现在通过提供程序支持“可插拔”组。因此,第三方提供程序即使在没有内置组的情况下也可以提供组实现。尝试在这样的构建中创建 TLS 连接而没有在运行时禁用 TLSv1.3 或使用第三方提供程序组,可能会导致握手失败。可以使用“no-tls1_3”配置选项在编译时禁用 TLSv1.3。

  • SSL_CTX_set_ciphersuites() 和 SSL_set_ciphersuites() 更改。

    这些方法现在会忽略未知密码。

  • 安全回调更改。

    安全回调(可由应用程序代码自定义)支持安全操作 SSL_SECOP_TMP_DH。它被定义为在“other”参数中接受 EVP_PKEY。在大多数情况下,这就是传递的内容。所有这些情况都发生在服务器端。但是,有一个客户端调用此安全操作,它传递了一个 DH 对象而不是 EVP_PKEY。这与 SSL_SECOP_TMP_DH 的定义不符,并且与所有其他位置不一致。因此,此客户端调用已更改为改为传递 EVP_PKEY。

  • 新的 SSL 选项 SSL_OP_IGNORE_UNEXPECTED_EOF

    引入了 SSL 选项 SSL_OP_IGNORE_UNEXPECTED_EOF。如果设置了该选项,则会忽略意外 EOF,它会假装收到一个关闭通知,因此返回的错误将变为 SSL_ERROR_ZERO_RETURN。

  • 已降低 TLS 中基于 SHA1 和 MD5 的签名的安全强度。

    这导致 SSL 3、TLS 1.0、TLS 1.1 和 DTLS 1.0 在默认安全级别 1 下不再工作,而是需要安全级别 0。可以使用带有 @SECLEVEL 的密码字符串或调用 SSL_CTX_set_security_level(3) 来更改安全级别。这也意味着,如果 ClientHello 中缺少签名算法扩展,则握手将在 TLS 1.2 的安全级别 1 下失败。这是因为,虽然此扩展是可选的,但没有提供此扩展意味着 OpenSSL 将回退到一组默认的签名算法。此默认集需要 SHA1 的可用性。

  • 安全级别 1 及以上不再允许使用 SHA1 签名的 X509 证书。

    在 TLS/SSL 中,默认安全级别为 1。可以使用带有 @SECLEVEL 的密码字符串或调用 SSL_CTX_set_security_level(3) 来设置安全级别。如果叶证书使用 SHA-1 签名,则如果安全级别没有先降低,则调用 SSL_CTX_use_certificate(3) 会失败。在 TLS/SSL 之外,默认安全级别为 -1(实际上为 0)。可以使用 X509_VERIFY_PARAM_set_auth_level(3) 或使用命令的 -auth_level 选项来设置安全级别。

另请参阅

fips_module(7)

历史记录

迁移指南是为 OpenSSL 3.0 创建的。

版权所有 2021-2024 OpenSSL 项目作者。版权所有。

根据 Apache 许可证 2.0 版(“许可证”)授权使用。 除非遵守许可证,否则您不得使用此文件。 您可以在源代码分发中的 LICENSE 文件或 https://www.openssl.org/source/license.html 中获取副本。