OpenSSL engine

引擎

弃用说明

ENGINE API在OpenSSL 0.9.6版本中作为一种底层接口被引入,用于添加加密原语的替代实现,特别是用于集成硬件加密设备。

ENGINE接口存在一些限制,并已被PROVIDER API所取代,在OpenSSL version 3.0中已被弃用。以下文档被保存,以帮助需要维护或支持现有ENGINE实现的用户。应通过提供者(providers)来添加对新硬件设备或新算法的支持,并尽快将现有引擎转换为提供者(providers)。

内置ENGINE实现

目前已经为以下加密设备内置了ENGINE实现:

  • Microsoft CryptoAPI
  • VIA Padlock
  • nCipher CHIL

此外,现在通过名为"dynamic"的特殊ENGINE提供对外部ENGINE实现的动态绑定。详细信息请参见下面的"DYNAMIC ENGINE"部分。

目前仍需要并正在努力完成以下几个事项:

  1. EVP支持的整合。
  2. 配置支持。
  3. 文档!

EVP支持的整合

关于EVP,这涉及在ENGINE模型中支持加密和摘要,以便ENGINE实现可以提供现有算法/模式的替代实现(或以前未实现的算法/模式)。

配置支持

配置支持目前存在于ENGINE API本身中,以"控制命令"的形式。这些命令允许应用程序向用户/管理员公开给定ENGINE实现支持的命令和参数类型,并且允许应用程序直接向这些ENGINE提供基于字符串的输入,以名称-值对的形式。这是ENGINE定义其自身的专有"配置"机制的可扩展方式(例如,针对特定硬件设备),但应在所有使用该ENGINE的基于OpenSSL的应用程序中保持一致。正在进行(或至少在计划中)的工作是支持从CONF(或NCONF)代码中支持这些控制命令,以便使用OpenSSL现有的配置文件格式的应用程序能够以类似的方式指定ENGINE设置。然而,目前应用程序必须使用ENGINE API本身来提供此类功能。要直接查看各种已编译的ENGINE可用的命令类型(有关动态ENGINE,请参见下文),请使用"engine" openssl实用程序并以全面模式运行,即:

openssl engine -vvvv

文档

文档?欢迎志愿者!源代码本身有一定程度的自我记录说明,但仍需要一些摘要和使用说明,而且它们需要使用现有OpenSSL文档提供的POD格式。任何完整或不完整的贡献都将有助于实现这一目标。

稳定性和错误报告

已有的内容在测试过程中表现比较稳定,但测试基础大部分时间都比较小。在很大程度上,这些ENGINE支持的设备的供应商已经为这些实现贡献了开发和/或测试,并且通常(不保证)具有使用ENGINE支持从常见的基于OpenSSL的应用程序驱动他们设备的经验。对于特定ENGINE实现中的错误和/或不可解释的行为,应该将其发送给该实现的作者(如果在相应的C文件中提到),对于商业硬件设备的实现,在可能的情况下也应通过供应商支持渠道进行报告。如果这些都不可行,或者问题似乎是关于ENGINE API本身的(即不一定是特定于特定ENGINE实现的),那么您应该将完整的详细信息发送到相关的OpenSSL邮件列表。关于"完整详细信息"的定义,请参阅OpenSSL的"README"文件。至于应该发送到哪个列表:

  • openssl-users:如果您在预编译的应用程序中使用ENGINE抽象,或者是在您自己的应用程序代码中使用。

  • openssl-dev:如果您讨论的是OpenSSL源代码的问题。

使用

在执行加密操作时,默认情况下将始终选择"openssl" ENGINE,除非另有说明。您必须积极告诉openssl实用程序命令通过一个名为"-engine"的新命令行开关来使用其他东西。此外,如果您想在自己的代码中使用ENGINE支持进行类似的操作,您也必须明确选择所需的ENGINE实现。

根据硬件类型、系统和配置,可能需要对ENGINE应用"设置",以使其按预期/希望的方式运行。最佳的做法是应用程序支持ENGINE的"控制命令",这样每个ENGINE实现可以提供其可能需要的任何配置基元,并且应用程序可以允许用户/管理员(因此也是硬件供应商的支持台)直接向ENGINE实现提供任何此类输入。这样,应用程序不需要知道任何特定设备的具体信息,它们只需要提供将此类用户/管理员输入传递到相关的ENGINE的手段。也就是说,它将您(和您的支持台)连接到特定的ENGINE实现(和设备),并允许应用程序作者不必为他们知道(和关心)的任意设备提供支持而陷入麻烦。

新的"openssl"实用程序 “openssl engine” 已经添加,它允许对ENGINE实现进行测试和检查。通过使用"-?"命令行开关可以获得基本的使用说明。

动态引擎

新的“动态”引擎提供了一种低开销的方式来支持没有预编译和链接到基于OpenSSL的应用程序中的引擎实现。这可能是因为现有的编译实现有已知问题,您希望使用较新版本的已有应用程序。同样,这也可能是因为您使用的应用程序(或OpenSSL库)根本不支持您希望使用的引擎,而引擎提供程序(例如硬件供应商)正在以共享库的形式提供自包含的实现。对于希望保持尽可能小的占用空间的应用程序,使用“动态”引擎的另一个用例是不从OpenSSL链接各种引擎实现,而是通过提供以“动态”可加载共享库的形式来提供它们(如果需要)。硬件供应商应该能够提供自己的共享库,以支持任意硬件与基于OpenSSL 0.9.7或更高版本的应用程序配合使用。如果您正在使用基于0.9.7(或更高版本)的应用程序,并且您希望使用的支持仅在您所需版本之后的版本中宣布,请要求供应商将其引擎回溯到您所需的版本。

“动态”引擎是如何工作的?

动态引擎在其实现中具有特殊的标志,以使每次应用程序代码请求“动态”引擎时,实际上都会获得它自己的副本。因此,多线程代码(或以任何方式复用“动态”在单个应用程序中进行多个独立操作的代码)不会因使用“动态”来执行许多独立操作而混淆。其他引擎通常不会这样做,因此只会有1个引擎结构的类型(并使用引用计数来保持顺序)。动态引擎本身不提供任何加密功能,并且任何尝试“初始化”引擎的操作都会自动失败。它唯一提供的是一些“控制命令”,用于控制如何从共享库加载外部引擎实现。要查看这些控制命令,请使用命令行;

openssl engine -vvvv dynamic

应使用“SO_PATH”控制命令来标识包含引擎实现的共享库,“NO_VCHECK”可能在存在次要版本冲突并且您(或供应商帮助台)确信可以安全忽略它时有用。如果共享库实现多个引擎,则可能仅需要“ID”,但是如果您知道要使用的引擎ID,则指定它也没有损害(而且这还提供了一个完整性检查)。如果您实际上希望通过应用程序代码稍后发现已加载的引擎,则需要“LIST_ADD”。对于大多数应用程序来说,这是没有必要的-但是某些应用程序作者可能有使用它的巧妙原因。 "LOAD"命令是唯一一个不带参数的命令,并且该命令使用前面命令的设置从共享库加载实际的引擎实现。如果此命令成功,则(动态副本的)'动态’引擎将自动转变为从共享库加载的引擎。因此,然后可以像正常情况一样执行由已加载的引擎支持的任何控制命令。例如,如果引擎“foo”在共享库“libfoo.so”中实现,并且它支持某些特殊控制命令“CMD_FOO”,则以下代码将加载并使用它(注:显然此代码没有错误检查);

ENGINE *e = ENGINE_by_id("dynamic");
ENGINE_ctrl_cmd_string(e, "SO_PATH", "/lib/libfoo.so", 0);
ENGINE_ctrl_cmd_string(e, "ID", "foo", 0);
ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0);
ENGINE_ctrl_cmd_string(e, "CMD_FOO", "some input data", 0);

对于此类测试,“openssl engine”实用程序可能非常有用。例如,上面的代码节选将实现与以下相似的结果:

openssl engine dynamic \
          -pre SO_PATH:/lib/libfoo.so \
          -pre ID:foo \
          -pre LOAD \
          -pre "CMD_FOO:some input data"

或者只是查看由“foo”引擎支持的命令列表的情况;

openssl engine -vvvv dynamic \
          -pre SO_PATH:/lib/libfoo.so \
          -pre ID:foo \
          -pre LOAD

支持引擎API和更具体地说,支持“控制命令”机制的应用程序将为您提供一种将此类命令传递给引擎的方法。因此,您将选择使用“动态”作为要使用的引擎,并且您传递的参数/命令将控制实际使用的引擎。每个命令实际上是一个名称-值对,有时可以省略值(例如“LOAD”命令)。虽然“openssl engine”中演示的语法使用冒号将命令名称与值分隔开,但是应用程序可以提供自己的语法来进行此分隔(例如,某些应用程序可能使用Win32注册表键值对)。使用“-pre”语法在“openssl engine”实用程序中的原因是,在引擎初始化用于使用之后可能会发出一些命令。例如,如果引擎实现在初始化期间需要插入智能卡(或键入PIN码等),则可能存在一个控制命令,您可以之后发出以“忘记”智能卡以便不再可能进行额外的初始化。对于在同一主机系统上可能运行潜在易变的代码的Web服务器等应用程序,可能提供了一些可争议的安全价值。在这种情况下,命令将在引擎初始化后传递给引擎,因此将使用“-post”开关。应用程序可能提供一种支持此区分的不同语法,而有些应用程序可能根本不提供它(实际上几乎总是使用“-pre”)。

如何构建“动态”引擎?
这个问题有点棘手 - 目前 OpenSSL 捆绑了各种静态构建的引擎实现,任何调用 “ENGINE_load_builtin_engines()” 函数的应用程序将自动拥有所有这些引擎(并且占用内存)。不调用该函数的应用程序将无法使用这样的引擎,必须使用 “dynamic” 来加载任何这样的引擎 - 但另一方面,这样的应用程序只会占用由用户/管理员提供的控制命令显式加载的任何引擎的内存占用。不静态链接引擎,只使用 “dynamic” 来支持硬件的主要优点是,不使用“外部”引擎的任何安装都不会因未使用的引擎而产生不必要的内存占用。同样,需要引擎的安装仅在加载了该引擎之后产生开销。

听起来不错?也许,但目前在 OpenSSL 的构建过程中,构建一个可以被 “dynamic” 加载的引擎实现作为共享库并不是自动化的。然而,可以很容易手动完成。这样的共享库可以使用任何需要的 OpenSSL 代码静态链接,或者如果 OpenSSL 本身构建为共享库,它可以动态链接到 OpenSSL。在每种情况下,说明都是相同的,但是在前者(静态链接到 OpenSSL)中,您必须确保 OpenSSL 是使用“位置无关代码”(PIC)构建的。默认的 OpenSSL 编译可能已经指定了相关的标志,但如果您有任何疑问,应该参考您的编译器文档。

以下示例将以 crypto/engine/ 目录中的 “atalla” 引擎为例,构建一个共享库,以便通过 “dynamic” 引擎使用。

  1. 进入预编译的 OpenSSL 源代码树的 crypto/engine/ 目录。

  2. 重新编译至少一个源文件,以便您可以看到正常构建时使用的所有编译器标志(和语法)。例如;

touch hw_atalla.c ; make

将使用所有这些标志重新构建 “hw_atalla.o”。

  1. 手动输入相同的编译命令行来编译 “hw_atalla.c” 文件,但进行以下两个更改;

    • 在命令行开关中添加" -DENGINE_DYNAMIC_SUPPORT",

    • 将输出文件从 “hw_atalla.o” 更改为新的文件,例如 “tmp_atalla.o”。

  2. 使用顶层 OpenSSL 库将 “tmp_atalla.o” 链接成一个共享库,以解决任何依赖关系。如何执行这个操作的语法取决于您的系统/编译器,这对于以前处理过共享库可移植性的人来说是一个噩梦。例如,在 Linux 上的 ‘gcc’ 可能会使用以下语法;

    gcc -shared -o dyn_atalla.so tmp_atalla.o -L../.. -lcrypto
    
  3. 使用前面章节中解释的 “openssl engine” 工具来测试共享库。例如,从顶层目录开始,您可以尝试下面的命令;

apps/openssl engine -vvvv dynamic \
         -pre SO_PATH:./crypto/engine/dyn_atalla.so -pre LOAD

如果共享库成功加载,您将看到两个 “-pre” 命令标记为 “SUCCESS”,并且(因为使用了 “-vvvv”)显示的控制命令列表将是 atalla 引擎的控制命令(即不是 ‘dynamic’ 引擎的)。如果要测试可能存在的硬件/驱动程序问题,还可以为工具添加 “-t” 开关,让它尝试初始化 atalla 引擎以供测试。

问题

看起来引擎部分在 Win32 上与 CryptoSwift 不太兼容。发布前进行的快速测试显示,尝试 “openssl speed -engine cswift” 会产生错误。如果启用了 DSO,则会尝试写入内存地址 0x00000002。

你可能感兴趣的:(前端,java,服务器)