当前位置: 代码网 > 服务器>网络安全>企业安全 > OpenSSL 3.0.0 设计(三)|FIPS 模块

OpenSSL 3.0.0 设计(三)|FIPS 模块

2024年08月06日 企业安全 我要评论
译|王祖熙 *(花名:金九 )* 蚂蚁集团开发工程师 *负责国产化密码库 Tongsuo 的开发和维护* *专注于密码学、高性能网络、网络安全等领域* **本文 9658 字 阅读 20 分钟** 本文翻译 OpenSSL 官网文档: Tongsuo-8.4.0 是基于 OpenSSL-3.0.3 开发,所以本文对 Tongsuo 开发者同样适用,内容丰富,值得一读! 由于文章篇幅较长,今天带来的是 **《FIPS模块》** 部分内容,已发布文章《介绍、术语与架构》、《Core 和 Provider 设计...

译|王祖熙 (花名:金九 )

蚂蚁集团开发工程师

负责国产化密码库 tongsuo 的开发和维护

专注于密码学、高性能网络、网络安全等领域

本文 9658 字 阅读 20 分钟

本文翻译 openssl 官网文档:https://www.openssl.org/docs/openssl300design.html

tongsuo-8.4.0 是基于 openssl-3.0.3 开发,所以本文对 tongsuo 开发者同样适用,内容丰富,值得一读!

由于文章篇幅较长,今天带来的是 《fips模块》 部分内容,已发布文章《介绍、术语与架构》、《core 和 provider 设计》可看发表记录。后续内容将随每周推送完整发布,请持续关注铜锁

fips 模块

这是一个经过 fips 140-2 验证的加密模块,它是一个只包含经过 fips 验证/批准的加密算法的 provider,非 fips 算法将由默认 provider(而不是 fips 模块)提供。

该模块是可以动态加载的,不支持静态链接。

fips 模块本身不会有 "fips 模式",可以使用 fips provider 的 openssl 将具有与 fips-module-2.0.0 兼容的"模式"概念。

fips 模块版本编号

版本将为 fips-module-3.0。

任何后续的修订版本将以与先前发布类似的方式进行标记,例如 3.0.x。

对于更改通知或重新验证,fips 模块的版本号将更新以匹配当前的 openssl 库版本。

检测 fips 边界内的变更

为了进行验证,我们需要检测是否有任何相关的源代码发生了变化。

可以使用一个脚本来对 c 源代码进行标记化处理,就像 c 预处理器一样,但还要教会它忽略源代码中的某些部分:

  • 系统的#include指令。
  • 在 fips 模式下被条件排除的代码(如下文中所述的条件代码)。

(提醒:c 预处理器可以将所有非换行空白字符合并,并在每个标记之间留下标准的单个空格,对于此目的,注释被视为空白字符)

标记化处理的结果可以通过校验和进行处理,该校验和存储在与源代码文件相对应的文件中,并最终进行版本控制。

该过程大致如下(并非完全相同,这只是一个代码示例,用于展示整个过程):

    for f in $(fips_sources); do
        perl ./util/fips-tokenize $f | openssl sha256 -r
    done | openssl sha256 -hex -out fips.checksum

还会有一些机制来提醒我们有关变化的信息,以便我们可以采取适当的措施。例如:

    git diff --quiet fips.checksum || \
        (git rev-parse head > fips.commit; scream)

关于 scream 的具体操作尚待确定。

更新 fips.checksum 应该作为正常的 make update 的一部分进行,这是通常用于更改和检查版本控制文件的方法,openssl 的持续集成已经运行了此命令,以确保没有遗漏任何内容,并且如果有内容被更改,将中断构建过程,运行make update也是正常的 openssl 发布流程的一部分。

如何对已签名校验和的更改做出反应

尽管发生了变更,但我们仓库中的校验和更改本身并没有什么大不了的,它只是提醒我们需要额外关注 fips 源代码。

有两种可能的情况:

  1. 当即将发布新版本,并且 fips.checksum 不再包含上一个经过验证的源代码的校验和时,将 fips 源代码发送给实验室,并开始更新验证流程。
  2. 在发布新版本的同时,fips.checksum 不再包含上一个经过验证的源代码的校验和时,将 fips 源代码(包括 diff 文件和变更列表)发送给实验室,并启动相应的更新验证流程。

已验证的校验和列表将在其他地方列出(稍后确定具体位置)。

编译

对于每个 fips provider 的源文件,我们计算该文件的校验和,并将其与 fips.checksum 中收集的校验和进行比对,如果存在不匹配,将拒绝编译。

fips 模式

fips 模块仅包含经过 fips 验证的密码算法,任何 fips 模式的“切换逻辑”将位于 fips 模块边界之外 - 这将由“fips”属性处理。

与 fips 模式相关的条件代码在单独的部分中讨论。

以下的 fips api 将继续可供应用程序使用(为了保持一致性,使用了与 1.1.1 版本中相同的名称):

  • int fips_mode_set(int on)

确保当前全局属性设置中设置了“fips=yes”(当 on != 0 时),或者未设置“fips”(当 on == 0 时)。这还将尝试使用属性“fips=yes”获取 hmac-sha256 算法,并确保它成功返回。

  • int fips_mode(void)

如果当前的全局属性字符串包含属性“fips=yes”(或“fips”),则返回1,否则返回0。

我们可以检查当前是否有提供 fips 算法的 provider 可用,并稍微以不同的方式处理。

  • int fips_self_test(void)

如果 fips_mode() 返回true,则运行 kats。

完整性测试将不在此处涵盖,如果我们决定提供它,它将是一个单独的函数。

成功时返回1,失败或没有 openssl fips provider 时返回0。

注意:这些函数只能在 openssl fips provider 的上下文中运行,而不能在其他任何 fips provider的上下文中运行。这些是过时的遗留接口,应使用evp_set_default_alg_properties()函数进行非遗留配置。

角色和身份认证

有两个隐含的角色 - 密码官(co)和用户。这两个角色都支持相同的服务,唯一的区别是 co 负责安装软件,该模块不应支持用户身份验证(对于1级而言不是必需的),所有这些都可以在安全策略中解释,而无需编写具体的代码。

有限状态模型(fips 140-2第4.4节)

需要定义一个状态机。

我们将需要以下状态:

  • 自检状态 - 初始化、运行、自检、错误、关闭(可能还包括后触发状态)
  • 错误状态 - 如果自检失败,模块应返回该操作的错误。可以尝试清除错误并重复操作,如果失败仍然存在,模块应进入错误状态,这可以是一个硬错误状态,其中所有加密操作都失败,或者是一个功能降级状态,其中失败的组件仅在使用时返回错误。

触发自检失败的方式包括:

    1. 连续测试(生成密钥对的成对测试(签名/验证)和从熵源比较测试中验证输入到 drbg 的随机数不相同)。
    2. drbg 健康测试 - 这可以始终在 rng 中引发错误(而不是设置全局错误状态)。
    3. 安装、启动或按需的 post 完整性测试失败。
    4. 启动或按需的 post kat 失败。

将提供一个内部 api 来设置上述情况的失败状态。

状态机

在状态机中未显示的状态以虚线表示。进入和离开错误状态的边缘以虚线表示,以表明不希望遍历这些边缘。

| 状态模型由这些状态组成:1. 电源关闭(power off):fips 模块未加载到应用程序中,共享库不在内存中。

  1. 电源开启(power on):fips 模块已被应用程序加载,并且共享库在内存中。默认入口点构造函数将被启动。
  2. 初始化(initialisation):调用ossl_provider_init。
  3. 完整性检查(integrity check)(post 完整性):模块对自身进行校验,并验证其是否被恶意更改。(在 fips 提供程序的 ossl_provider_init() 期间运行)。
  4. 自检(self test)(post kat):fips 模块在安装期间执行其自检,或者在通过 api 调用进行按需自检。
  5. 运行(running):fips 模块处于正常运行状态,可以使用所有 api,并进行连续测试。
  6. 错误(error):fips 模块进入错误状态,调用所有加密 api 将返回错误。
  7. 关闭(shutdown):fips 模块正在被终止并从使用应用程序中卸载。

状态之间的边缘关系如下:

  1. 从电源关闭(power off)到电源开启(power on):此转换由操作系统在将共享库加载到应用程序时执行。
  2. 从电源开启(power on)到初始化(initialisation):当调用共享库的构造函数时发生此转换。
  3. 从电源开启(power on)到关闭(shutdown):如果无法调用构造函数或构造函数失败,将触发此转换。
  4. 从初始化(initialisation)到完整性检查(integrity check):此转换在初始化代码完成后发生,计算模块完整性校验和,并与预期值进行比较。
  5. 从初始化(initialisation)到错误(error):如果初始化代码在启动自测之前遇到错误,将触发此转换。
  6. 从完整性检查(integrity check)到运行(running):对于所有启动过程中完整性检查成功的情况,发生此转换。
  7. 从完整性检查(integrity check)到自测(self test):在安装过程中,如果完整性检查成功,发生此转换。
  8. 从完整性检查(integrity check)到错误(error):如果完整性检查失败,将触发此转换。
  9. 从运行(running)到关闭(shutdown):当 fips 模块最终化时发生此转换。
  10. 从运行(running)到错误(error):如果连续测试中的任何一个失败,将触发此转换。
  11. 从运行(running)到自测(self test):应用程序手动启动自测时触发此转换。不重新运行完整性检查。
  12. 从自测(self test)到运行(running):自测通过时发生此转换。
  13. 从自测(self test)到错误(error):如果自测失败,将触发此转换。
  14. 从关闭(shutdown)到电源关闭(power off):当 fips 模块从应用程序的内存中卸载时发生此转换。
  15. 从错误(error)到关闭(shutdown):当 fips 模块最终化时发生此转换。

如果可能的话,我们应该尽量在运行状态下注册算法,任何进入运行状态的转换都应该允许注册/缓存密码算法,而任何进入错误或关闭状态的转换都应该清除 libcrypto 中的所有缓存算法,通过采用这种方法,我们可以避免在所有密码工厂函数中检查状态,这样可以避免为自我测试(手动启动时)提供特殊情况访问权限,同时阻止外部调用者的访问。

服务

fips模块提供以下服务。

  • 显示状态。如果“运行”状态处于活动状态,则返回1,否则返回0。
  • 密码服务,如hmac、shs、加密。请参阅附录3-算法
  • 自检(按需执行)- libcrypto 中提供了一个名为fips_self_test()的公共 api来访问此方法。所使用的方法必须与初始化时触发的方法相同,安全策略将指明只有在没有其他密码服务运行时才能访问此方法。
  • 密钥清零。请参阅 csp/key 清零

这些服务仅在运行状态下运行,在任何其他状态下尝试访问服务将返回错误,如果自检失败,则任何尝试访问任何服务的操作都应返回错误。

自测试

自测试包括上电自测试(post)和运行时测试(例如,确保熵不会重复作为 rng 的输入)。

post 包括模块完整性检查(每次运行使用 fips 的应用程序时运行)以及算法 kat(可以在安装时运行一次)。

post 测试在调用 fips 模块的ossl_provider_init()入口点时运行。

为了按照正确的顺序实现完整性测试和 kat,模块需要访问以下数据项:

  1. 库的路径;
  2. 库内容的 hmac-sha256(或包含该值的文件的路径);
  3. 指示库已安装并通过 kat 的指示器;
  4. 该指示器的 hmac-sha256。

这些值将成为可以通过ossl_provider对象和相关的ossl_param getter获取的参数的一部分。将使用一个“更安全”的获取值函数来获取这些值,该函数不会展开环境变量等。此外,还需要传递用于访问和返回库内容的函数(可能是基于 bio 的,通过将 core 传递给模块的调度表中的少量 bio 函数来实现),以便模块可以生成自己的库摘要。

新的 openssl“fips” 应用程序将提供安装(运行 kat 并输出配置文件数据)和检查(检查配置文件中的值是否有效)的功能。

模块的默认入口点(dep),即 linux 库中的 “.init” 函数,将设置一个模块变量(可能是状态变量),在ossl_provider_init()中将检查此变量,并且如果设置了(通常会设置),则验证文件中的值。这个两步过程满足了 fips 要求,即 dep 确保测试运行,但允许我们在正常运行时初始化模块的其余部分时实现这些测试。

作为构建过程的一部分,必须将 fips 模块的完整性校验和保存到文件中,这可以通过脚本完成,它只是使用已知固定密钥对整个 fips 模块文件进行 hmac_sha256 运算的结果,如果库已签名,则必须在应用签名之后计算校验和。

至少具有112位的固定密钥将嵌入到 fips 模块中,用于所有 hmac 完整性操作,这个密钥也将提供给外部构建脚本。

出于测试目的,即使其中一个或多个测试失败,所有活动的 post 测试也会运行。

完整性校验和的位置

完整性校验和将在安装过程中保存到一个单独的文件中,默认情况下,该文件将与 fips 模块本身位于相同的位置,但可以配置为位于不同的位置。

已知答案测试

kat 的目的是对密码模块进行健康检查,以识别在电源周期之间的模块的严重故障或变化,而不是验证实现是否正确。

fips 140-2 ig 的规则指定了需要测试每个已支持的算法(不是每个模式),如果一个算法作为另一个测试的组成部分进行了测试,则不需要单独的测试,以下是需要进行测试的算法列表:

  • 加密/解密算法

    • aes_128_gcm2
    • tdes_cbc
  • 哈希算法

    • sha1
    • sha256 在其他地方已经要求测试
    • sha512
    • sha3-256
  • 签名/验证测试

    • dsa_2048
    • rsa_sha256(使用pkcs #1 v1.5填充)
    • ecdsa p256
  • 任何支持的 drbg 机制的 drbg 健康测试

    • ctr(aes_128_ctr)
    • hash - sha256
    • hmac - sha256
  • 派生测试(计算z)

    • ecdsa p256
    • ecdh
    • kdf(密钥派生函数)
    • kbkdf(用于 tls 的 hkdf)

注意:完整性测试使用 hmac-sha-256,因此不需要单独进行 hmac 测试。

接口访问

为了方便修改和更改运行的自测试,自测试应该是数据驱动的,post 测试在注册任何方法之前运行,但方法表仍然可以间接使用,仍然需要较低级别的 api 来设置密钥(参数、公钥/私钥),密钥加载代码应该在一个单独的函数中进行隔离。

需要一个初始化方法来为高级函数设置所需的依赖项,例如在执行基本调用之前可能需要调用 set_cpuid。

应为摘要、密码、签名、drbg、kdf、hmac 提供不同类型的自测试 api。

传递给这些测试的参数是 kat 数据。

安全强度

sp 800-131a rev2 在某些日期之后禁止使用特定的算法和密钥长度,这些项目与安全强度相关联。

允许具有至少112位安全强度的算法。

对于签名验证,为了遗留目的,允许使用安全强度至少为80且低于112的算法。

这两个值可以在fips模块中定义和执行,也可以在安全策略文档中更简单地处理。

可以通过公共api定义这些最小值,并允许设置它们。

还应添加目标安全强度的概念,该值将在密钥生成算法中使用,这些算法通过其标准指定了目标安全强度参数。

sp800-56a & 56b

这些标准包含密钥协商协议,为了测试这些协议,加密模块需要包含以下低级原语。

  • 计算密钥方法 - 这些已经存在。(例如 dh_compute_key())。
  • 密钥生成 - (目前缺少 rsa fips 186-4 密钥生成)。
  • 密钥验证 - (大部分已经实现)。

fips 186-4 rsa 密钥生成

尚未完成的工作是将其整合到 fips 模块中,openssl fips provider 将具有强制密钥大小限制的逻辑;

  • 对于 rsa、dsa 和 ecdsa 密钥对生成,需要进行成对一致性测试(条件自检)。由于在密钥生成过程中无法确定密钥的用途,fips 140-2 ig 规定相同的成对测试可以用于签名和加密两种模式;
  • 不允许使用 1024 位的 rsa 密钥生成;
  • 密钥生成算法具有目标安全强度的概念。例如,rsa 的密钥生成代码需要进行以下检查:
if (target_strength < 112
    || target_strength > 256
    || bn_security_bits(nbits) < target_strength)
    return 0;

dh 密钥生成

  • dh 密钥生成 - 可能需要将其拆分为符合标准步骤的形式。目前它是一个相当复杂用时也用于验证的整体函数。

密钥验证

  • rsa sp 800-56b 密钥验证 - 公钥、私钥和密钥对的检查已添加到 pr#6652,符合标准的要求;
  • 需要检查 dh 密钥验证是否符合标准;
  • ec 密钥验证符合标准要求;
  • aes-xts 模式需要进行扭曲密钥检查。

对于kas dh参数,支持两种类型:

  1. 已批准的安全素数群如下:

(其中 g=2,q=(p-1)/2,priv=[1, q-1],pub=[2, p-2])

tls:(ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192)

ike:(modp-2048, modp-3072, modp-4096, modp-6144, modp-8192)

只有上述安全素数可以进行验证-其他任何素数都应该失败。

安全素数可用于至少112位的安全强度,可能需要进行 fips 特定的检查以验证群组。

  1. fips 186-4 参数集仅用于向后兼容性,安全强度仅为112位。群组为 fb (2048, 224) 和 fc (2048, 256)。这需要保存种子和计数器以进行验证。

如果需要同时支持两种类型,则需要不同的密钥验证代码。

现有的dh_check()需要进行 fips 特定的检查来验证批准的类型。

密钥生成对于两者来说是相同的(安全强度和私钥的最大位长度是输入)。

dsa 在 fips 186-4 中定义为 “ffc”,dsa 密钥生成/密钥验证可以重新设计,以更好地匹配标准步骤,这将有助于密钥验证,并且如果需要,可以在 dh 情况下进行重用。

gcm iv 生成

对于 fips 模块,aes gcm 有与唯一密钥/iv 对相关的要求,即:

  • 加密时密钥/iv 对必须是唯一的;
  • iv 必须在 fips 边界内生成;
  • 对于 tls,iv 的计数部分必须由模块设置,模块必须确保当计数用尽时返回错误;
  • 对于给定的密钥(对于任何 iv 长度),认证加密函数的总调用次数必须小于
  • 模块断电不应导致 iv 的重复使用。

iv 生成将使用随机构造方法(来自sp 800-38d),其中包括一个自由字段(将为 null)和一个随机字段,随机字段将使用一个能提供至少96位熵强度的 drbg,该 drbg 需要由模块进行种子生成。

现有代码需要修改,以便在init()阶段未设置 iv 时生成 iv,然后可以使用do_cipher()方法在需要时生成 iv。

int aes_gcm_cipher()
{
    ....
    /* old code just returned -1 if iv_set was zero */
    if (!gctx->iv_set) {
        if (ctx->encrypt) {
           if (!aes_gcm_iv_generate(gctx, 0))
               return -1;
           } else {
               return -1;
           }
        }
    }
}

生成代码如下所示:

#define aes_gcm_iv_generate(gctx, offset)                   \
    if (!gctx->iv_set) {                                    \
        int sz = gctx->ivlen - offset;                      \
        if (sz <= 0)                                        \
            return -1;                                      \
        /* must be at least 96 bits */                      \
        if (gctx->ivlen < 12)                               \
            return -1;                                      \
        /* use drbg to generate random iv */                \
        if (rand_bytes(gctx->iv + offset, sz) <= 0)         \
            return -1;                                      \
        gctx->iv_set = 1;                                   \
    }

生成的 iv 可以通过evp_cipher_ctx_iv()方法获取,因此不需要使用 ctrl id。

理想情况下,在 fips 模式下尝试设置 gcm iv 参数将导致错误。实际上,可能仍然有一些应用程序需要设置 iv,因此建议将其指定为安全策略项。

安全策略还需要说明以下内容:(参见 fips 140-2 ig a.5)

  • 当电源断开然后恢复时,应建立一个新的用于 aes gcm 加密的密钥;
  • 使用相同密钥的总调用次数必须小于
  • 场景1:iv 生成符合 tls 协议;
  • 场景2:使用 nist sp 800-38d(第8.2.2节)的 iv 生成方法。

csp/key 清零

当不再需要临界安全参数(csp)时,我们必须将其全部设置为零,这可能会在不同的上下文中发生:

  • 临时的 csp 副本可能是栈或堆分配的,并且将在其使用范围内的相关函数中被清零;
  • 一些 csp 将与 openssl 对象(如 evp_pkey 或 evp_cipher_ctx)关联,具有与之相关联的生命周期,在这种情况下,当这些对象被释放时,csp 将在该点被清零。在某些情况下,对象可能会被复用(例如,evp_cipher_ctx 可以用于多个加密操作),在这种情况下,对象中仍存在的任何 csp 将在其重新初始化为新操作时被清零。
  • 一些 csp(例如内部 drbg 状态)可能会在加载 openssl fips 模块的整个时间内存在,在这种情况下,状态将封装在 openssl 对象中。所有 openssl provider(包括 fips 模块 provider)都具有注册“卸载”函数的能力,该函数在关闭 openssl 时(或因其他原因卸载模块)时将被调用,该卸载函数将释放(因此将清零)包含 csp 的对象。
  • 根据 fips 140-2 ig 4.7 的规定:仅用于执行 fips 140-2 第4.9.1节上电测试的密码模块使用的密码密钥不被视为 csp,因此不需要满足 fips 140-2 第4.7.6节的清零要求。

openssl fips 模块将包含其自己的标准openssl_cleanse()函数的副本来执行清零操作,这是使用特定于平台的汇编语言实现的。

drbg

在旧的 fips 模块中存在以下 api,可能需要重新添加:

  • fips_drbg_health_check:按需运行 drbg kat 测试,我们需要使其可用。
  • fips_drbg_set_check_interval:设置运行 drbg kat 测试之间的间隔(生成调用的次数)。这似乎不是必需的,这些测试在上电时运行,但后续不需要运行,但这个调用对于故障测试很有用。

推导函数

根据 fips 140-2 ig 14.5 中的第2点要求,ctr drbg 将无条件支持派生函数,如果禁用派生函数,当前的代码在重新生成种子时会出现问题。此外,如果没有派生函数,需要从实验室获得额外的理由支持。

测试要求

  • uninstantiate()函数中需要证明内部状态已被清零;
  • 故障测试需要一个函数,使 drbg 始终产生相同的输出。

其他需要考虑的事项

除了下面描述的熵之外,还需要考虑以下几点:

  • 应考虑实施 nist sp 800-90c 10.1.2 中的熵扩展;
  • 需要更好的 drbg 选择机制,以在可用的 drbg 之间进行选择;
  • 支持预测抵抗,即在请求时尝试从我们的来源收集更多熵。
  • 我们需要弄清楚 drbg 层将是什么样子,代码的很大一部分需要放在 fips 模块内。目前,此代码访问 evp 功能,而这些功能可能不会在模块内部公开。例如,drbg_ctr_init() 从 nid 解析 evp_cipher,然后设置一个 evp_cipher_ctx。

对于所有平台,操作系统将提供熵。对于某些平台,还可以使用内置的硬件随机数生成器,但这将引入额外的验证需求。

对于类 unix 系统,将使用系统调用getrandomgetentropy或随机设备/dev/random作为熵源,优先考虑使用系统调用。可以替代/dev/random的其他强随机设备包括:/dev/srandom/dev/hwrng。请注意,/dev/urandom/dev/prandom/dev/wrandom/dev/arandom在没有额外的证明的情况下不能用于 fips 操作。

在 windows 上,将使用bcryptgenrandomcryptgenrandom作为熵源。

在 vms 上,将使用各种系统状态信息作为熵源。请注意,这将需要证明和分析以证明源的质量。

对于 ios,将使用 secrandomcopybytes 生成具有密码学安全性的随机字节

fips 仅允许将一个熵源归因于模块,因此 fips 模块将完全依赖于前述的操作系统源,不会使用其他来源,例如 egd、硬件设备等。

完成熵解决方案的工作

需要将 drbg 健康检测添加到随机框架中,以检查输入到 drbg 的种子材料,检查的目的是确保没有连续的两个种子材料块是相同的,该检查在所有熵源被合并在一起后进行,如果检查失败,则 drbg 的种子重新生成操作将永远失败。我们可以定义使用的块大小为64位,这是在意外接收到重复块的概率()和从操作系统中获取过多熵量之间的平衡(因为第一个块会被丢弃),其他明显可用的块大小包括128位和256位。

使用后,初始数据块必须被清零和丢弃。

gcm的初始化向量(iv)

fips 140-2 ig a.5 的最新更新指出,如果模块声称为 gcm 生成随机 iv,则需要提供证明,我们需要证明模块能够从操作系统获取所需的96位熵,如果使用阻塞调用操作系统的随机性源,并且至少使用这么多熵素材作为 drbg 的种子材料,那么这应该不是无法解决的问题。

fips 模块边界

一旦进入 fips 模块提供的算法,在任何其他的加密操作中我们必须仍然保持在 fips 模块内部。根据 fips 规则,允许一个 fips 模块使用另一个 fips 模块。然而,在3.0设计中,为了简化起见,我们假设不允许这样做。例如,evp_digestsign*实现同时使用签名算法和摘要算法,我们不允许其中一个算法来自 fips 模块,另一个来自其他 provider。

所有 provider 在初始化时都被分配一个唯一的ossl_provider对象,当 fips 模块被要求使用某个算法时,它会验证该算法的实现ossl_provider对象是否与自己的ossl_provider对象相同 (即传递给ossl_provider_init的对象),例如,考虑使用 rsa 和 sha256 的evp_digestsign*的情况,两个算法都会通过 core 在 fips 模块外部进行查找,rsa 签名算法是第一个入口点,"init" 调用将被传递给要使用的 sha256 算法的引用,fips 模块的实现将检查与其被要求使用的 sha256 实现关联的ossl_provider对象是否也在 fips 模块边界内,如果不是,则 "init" 操作将失败。下面的图示从 fips 模块的角度说明了这个操作。

请注意,在 fips 模块内部,我们使用了evp的概念(如evp_md_ctxevp_pkey_ctx等)来实现这一点,这些是 libcrypto 中 evp 实现的副本,fips 模块没有与 libcrypto 进行链接,这是为了确保完整的操作都在 fips 模块的边界内进行,而不调用外部的代码。

asn.1 代码

asn.1 der (distinguished encoding rules) 用于:

  • 序列化密钥参数
  • 序列化由两个值 r 和 s 组成的 dsa 和 ecdsa 签名
  • 编码放置在 rsa pkcs#1 填充中的签名摘要 object identifier(oid)
  • 序列化 x.509 证书和证书撤销列表(crl)
  • 其他 pdu,如 pkcs #7/cms、ocsp、pkcs #12 等。

fips 模块不会包含 asn.1 der 编码器/解析器的副本,也不会要求任何 provider 对由 openssl 实现的算法执行 asn.1 序列化/反序列化。

所有 asn.1 序列化/反序列化操作将在 libcrypto 中执行,复合值的密钥参数和签名结构将作为项数组越过 core/provider 边界,使用 附录 2 - 参数传递 中定义的公共数据结构进行传递。

用于 rsa pkcs#1 填充的编码摘要 oid 将预先生成(与旧 fips 模块使用 sha_data 宏相同)或根据需要使用简单函数生成,这个函数仅为 pkcs #1 填充支持的小型摘要集合生成编码的 oid,这些摘要 oid 在“oid 树”下的一个公共节点下,验证填充时将获取预期摘要的编码 oid,并将其字节与填充中的字节进行比较;不需要进行 der 解析/解码。

下周我们将带来 "代码维护、fips 测试" 部分内容,等不及的小伙伴,可以戳下方“阅读原文”,查看铜锁语雀中的全篇文档哦!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com