OpenSSL

密码学和 SSL/TLS 工具包

openssl-threads

名称

openssl-threads - OpenSSL 中线程安全的概述

描述

在本手册页中,我们使用术语 **线程安全** 来表示一个对象或函数可以被多个线程同时使用。

OpenSSL 可以选择支持或不支持线程。这种支持最重要的用途是让 OpenSSL 本身可以使用一个单一的、一致的 API,如 "CRYPTO_THREAD_run_once(3) 中的示例" 中所示。多平台应用程序也可以使用此 API。

特别地,被配置为支持线程并不意味着所有 OpenSSL 对象都是线程安全的。需要强调的是:**大多数对象并不安全,不能被同时使用**。对此的例外情况应在具体的手册页中进行说明,这里提供了一些通用的高级指导。

OpenSSL 线程 API 的一个主要用途是实现引用计数。OpenSSL 中的许多对象都是引用计数的,因此资源只有在最后一个引用被移除后才会被释放。引用通常会自动增加(例如,当一个 **X509** 证书对象被添加到 **X509_STORE** 信任存储中时)。通常有一个 **object_up_ref**() 函数可以用来增加引用计数。如果没有将 **object_up_ref**() 调用与正确的数量的 **object_free**() 调用匹配,那么当程序退出时,内存泄漏是一个常见的来源。

许多对象都有设置和获取 API,用于设置对象中的属性。set0 将所有权从调用者传递给对象,而 get0 返回一个指针,但属性的所有权仍然属于对象,并返回对它的引用。set1get1 函数不会改变所有权,而是更新属性的引用计数,以便对象在调用者和对象之间共享;调用者必须在完成时释放返回的属性。涉及具有自身引用计数的属性的函数,但名称只是 setget 是历史性的;并且文档必须说明引用的处理方式。只要满足所有权要求并且不修改共享对象,获取方法通常是线程安全的。设置方法或修改共享对象通常不是线程安全的,如下所述。

只要调用的 API 不修改对象,对象就是线程安全的;在这种情况下,参数通常在 API 中被标记为 const。并非所有参数都以这种方式标记。请注意,const 声明并不意味着不可变;例如 X509_cmp(3) 接受指向 const 对象的指针,但实现使用 C 转换来移除它,以便它可以锁定对象,生成和缓存 DER 编码等等。

线程安全的另一个实例是,当使用锁更新对象内部状态(如缓存值)时。上面描述的引用计数 API 就是一个例子。

然而,在所有情况下,一个线程一般来说不能在另一个线程使用该对象(如验证签名)时修改该对象,如设置私钥或公钥的元素。

相同的 API 通常可以在不同的对象上同时使用,而不会相互干扰。例如,两个线程可以使用两个不同的 **EVP_PKEY_CTX** 对象来计算签名。

对于隐式全局状态或单例,线程安全取决于设施。CRYPTO_secure_malloc(3) 和相关的 API 有自己的锁,而 CRYPTO_malloc(3) 假设底层平台分配将进行任何必要的锁定。有些 API,如 NCONF_load(3) 及其相关 API 根本没有锁定;这可以被认为是一个错误。

一个单独的,但相关的,问题是,当其他对象从该对象创建时,修改“工厂”对象。例如,由 SSL_CTX_new(3) 创建的 **SSL_CTX** 对象用于通过调用 SSL_new(3) 创建每个连接的 **SSL** 对象。在这种特殊情况下,以及可能对工厂方法的一般情况下,在使用工厂对象创建其他对象之后,修改工厂对象是不安全的。

参见

CRYPTO_THREAD_run_once(3),本地系统线程文档。

错误

此页面显然很不完整。

版权所有 2021 The OpenSSL Project Authors. 保留所有权利。

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