OpenSSL

密码学和SSL/TLS工具包

迁移指南

名称

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 1.1.1一起使用,那么绝大多数应用程序在不进行更改的情况下也可以与OpenSSL 3.0一起使用。但是,这不能保证,在某些情况下可能需要进行一些更改。如果应用程序需要利用OpenSSL 3.0中提供的一些新功能(例如FIPS模块的可用性),也可能需要进行更改。

许可证更改

在以前的版本中,OpenSSL根据双重OpenSSL和SSLeay许可证(两个许可证均适用)授权。从OpenSSL 3.0开始,它被Apache许可证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。

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

旧版算法

一些加密算法(例如MD2DES)以前通过EVP API可用,现在被认为是旧版算法,强烈建议不要使用它们。这些旧版EVP算法在OpenSSL 3.0中仍然可用,但不是默认的。如果您想使用它们,则必须加载旧版提供程序。这可能只需更改配置文件,也可以通过编程方式完成。请参阅OSSL_PROVIDER-legacy(7),获取算法的完整列表。使用EVP API访问这些算法的应用程序应改用更新的算法。如果无法做到这一点,则这些应用程序应确保已加载旧版提供程序。这可以通过编程方式或通过配置来实现。请参阅crypto(7)手册页,了解有关提供程序的更多信息。

引擎和“METHOD”API

支持提供程序的重构在内部与用于支持引擎的API冲突,包括ENGINE 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及以下版本,不同的补丁级别由版本号末尾的字母表示。这将不再使用,而是由版本中的最后一个数字表示补丁级别。第二个(MINOR)数字的更改表示可能已添加了新功能。具有相同主版本的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)PKCS12_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,该 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) 设置参数。

强制执行 512 位的最小 DH 模数大小

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

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 的密钥生成操作将失败。

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

错误代码的函数代码部分现在始终设置为 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,它具有前导零填充。

安装和编译

有关如何构建和安装 OpenSSL 3.0 的说明,请参阅发行版顶部的 INSTALL.md 文件。另请参阅针对您特定平台的各种平台特定 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 后缀)。此外,您必须使用“setter”或“getter”函数来访问这些结构中的字段。

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

    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。本节介绍一些常见的弃用类别。有关这些类别的弃用函数列表,请参阅 “弃用函数映射”

提供程序是引擎和低级方法覆盖的替代方案

任何使用 ENGINE 的访问器都已弃用(例如 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) 中的“迁移”

弃用的低级密钥对象 getter 和 setter

设置或获取低级密钥对象(例如 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)

弃用的低级密钥参数 getter

直接访问低级对象的函数(例如 RSA_get0_n(3))现在已弃用。应用程序应使用 EVP_PKEY_get_bn_param(3)EVP_PKEY_get_int_param(3)、lEVP_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) 返回所有字段。

弃用的低级密钥参数 setter

直接访问低级对象的函数(例如 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 可以通过多种方式创建:另请参阅 “弃用的低级密钥生成函数”“弃用的低级密钥读取和写入函数”“弃用的低级密钥参数 setter”

弃用的低级加密函数

长期以来一直不鼓励使用 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 函数

CMAC_Init(3) 等低级 mac 函数已弃用。应用程序应改用新的 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_EC_gen(3)

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

长期以来一直不鼓励使用低级对象(例如 DSA)。应替换用于读取和写入这些低级对象的函数(例如 PEM_read_DSA_PUBKEY())。应用程序应改用 OSSL_ENCODER_to_bio(3)OSSL_DECODER_from_bio(3)

弃用的低级密钥打印函数

长期以来一直不鼓励使用低级对象(例如 DSA)。应使用等效的 EVP_PKEY 函数替换用于打印这些低级对象的函数(例如 DSA_print())。应用程序应使用 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)

openssl ca 使用的 -crl_lastupdate-crl_nextupdate 允许在生成的 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 调用。这意味着某些性能数字可能无法与以前的版本相比,因为开销更高。这尤其适用于测量较小数据块上的性能。

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

默认设置

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

已弃用的应用程序

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 的一部分设置。

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

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

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

    这导致 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 的可用性。

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

    在 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 中获取副本。