Ubuntu 下 nginx-1.24.0 源码分析 - ngx_ssl_init 函数

#if (NGX_OPENSSL)
    ngx_ssl_init(log);
#endif

 objs/ngx_auto_config.h 中

#ifndef NGX_OPENSSL
#define NGX_OPENSSL  1
#endif

  所以这个条件编译成立


NGX_OPENSSL 是一个宏定义,用于控制与 OpenSSL 相关的功能是否被启用

若用户通过./configure参数(如--with-http_ssl_module)显式启用SSL模块,则NGX_OPENSSL宏会被定义 

OpenSSL 是一个开源的加密库,广泛用于实现安全通信协议(如 HTTPS、TLS/SSL)以及提供各种加密和解密功能

ngx_ssl_init 

声明

在 src/event/ngx_event_openssl.h 中:

ngx_int_t ngx_ssl_init(ngx_log_t *log);

实现

在 src\event\ngx_event_openssl.c 中:

ngx_int_t
ngx_ssl_init(ngx_log_t *log)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100003L

    if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
        return NGX_ERROR;
    }

    /*
     * OPENSSL_init_ssl() may leave errors in the error queue
     * while returning success
     */

    ERR_clear_error();

#else

    OPENSSL_config(NULL);

    SSL_library_init();
    SSL_load_error_strings();

    OpenSSL_add_all_algorithms();

#endif

#ifndef SSL_OP_NO_COMPRESSION
    {
    /*
     * Disable gzip compression in OpenSSL prior to 1.0.0 version,
     * this saves about 522K per connection.
     */
    int                  n;
    STACK_OF(SSL_COMP)  *ssl_comp_methods;

    ssl_comp_methods = SSL_COMP_get_compression_methods();
    n = sk_SSL_COMP_num(ssl_comp_methods);

    while (n--) {
        (void) sk_SSL_COMP_pop(ssl_comp_methods);
    }
    }
#endif

    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);

    if (ngx_ssl_connection_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                         NULL);
    if (ngx_ssl_server_conf_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                           NULL);
    if (ngx_ssl_session_cache_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                         NULL);
    if (ngx_ssl_ticket_keys_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_ocsp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
    if (ngx_ssl_ocsp_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                         NULL);
    if (ngx_ssl_certificate_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
                                                           NULL);
    if (ngx_ssl_next_certificate_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
                                                           NULL);

    if (ngx_ssl_certificate_name_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);

    if (ngx_ssl_stapling_index == -1) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
        return NGX_ERROR;
    }

    return NGX_OK;
}

 这段代码是 Nginx 源码中用于初始化 OpenSSL 库的核心函数 ngx_ssl_init,其主要目的是为 Nginx 的 SSL/TLS 功能提供必要的初始化操作

函数的主要功能

ngx_ssl_init 函数的主要任务是:

  • 初始化 OpenSSL 库,确保其能够正常工作。
  • 配置 SSL/TLS 相关的全局状态。
  • 注册自定义扩展索引(ex_data),以便在后续的 SSL/TLS 上下文中存储和访问 Nginx 特定的数据。

 

主要逻辑分析

(1) OpenSSL 库的初始化
#if OPENSSL_VERSION_NUMBER >= 0x10100003L
    if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
        return NGX_ERROR;
    }
    ERR_clear_error();
#else
    OPENSSL_config(NULL);
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
#endif

条件编译

  • 如果 OpenSSL 版本号大于等于 0x10100003L(即 OpenSSL 1.1.0 及以上版本),使用 OPENSSL_init_ssl 函数进行初始化。
  • 对于较老的 OpenSSL 版本(低于 1.1.0),则通过一系列传统函数(如 OPENSSL_configSSL_library_init 等)进行初始化。

新版本的初始化

if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
    ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
    return NGX_ERROR;
}
ERR_clear_error();
  • 调用 OPENSSL_init_ssl 初始化 OpenSSL,并加载配置文件。
  • 即使 OPENSSL_init_ssl 返回成功,也可能在错误队列中留下未处理的错误信息,因此调用 ERR_clear_error 清除这些潜在的错误。

旧版本的初始化

OPENSSL_config(NULL);
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
  • OPENSSL_config 加载 OpenSSL 配置文件。
  • SSL_library_init 初始化 SSL 库。
  • SSL_load_error_strings 加载错误字符串,方便调试。
  • OpenSSL_add_all_algorithms 注册所有加密算法。
(2) 禁用压缩(针对旧版本 OpenSSL)
#ifndef SSL_OP_NO_COMPRESSION
{
    int                  n;
    STACK_OF(SSL_COMP)  *ssl_comp_methods;
    ssl_comp_methods = SSL_COMP_get_compression_methods();
    n = sk_SSL_COMP_num(ssl_comp_methods);
    while (n--) {
        (void) sk_SSL_COMP_pop(ssl_comp_methods);
    }
}
#endif
  • 在 OpenSSL 1.0.0 之前的版本中,没有 SSL_OP_NO_COMPRESSION 宏来禁用压缩。
  • 压缩可能导致内存消耗增加(每连接约 522KB),因此手动禁用压缩:
    • 获取当前支持的压缩方法列表。
    • 遍历并移除所有压缩方法。
(3) 创建扩展索引

Nginx 使用 OpenSSL 的扩展机制来存储自定义数据。以下是创建的几个扩展索引及其用途:

1.连接级别的扩展索引

ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
  • 用于在 SSL 连接对象中存储 Nginx 的自定义数据。

2.上下文级别的扩展索引

ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);

用于在 SSL 上下文对象中存储服务器配置信息

3.会话缓存扩展索引

ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
  • 用于管理 SSL 会话缓存。

4.其他扩展索引

ngx_ssl_ticket_keys_index:用于存储会话票据密钥。

ngx_ssl_ocsp_index:用于存储 OCSP(在线证书状态协议)相关数据。

ngx_ssl_certificate_indexngx_ssl_next_certificate_index:用于管理证书链。

ngx_ssl_stapling_index:用于 OCSP Stapling(证书状态绑定)。

每个扩展索引的创建都检查返回值是否为 -1,如果失败则记录错误日志并返回 NGX_ERROR

意图

1 兼容性
  • 代码通过条件编译兼容了不同版本的 OpenSSL(1.1.0 及以上版本与旧版本)。
  • 旧版本中手动禁用压缩的逻辑体现了对性能优化的关注。
2 扩展性
  • 使用 OpenSSL 的扩展机制(SSL_get_ex_new_indexSSL_CTX_get_ex_new_index)为 Nginx 提供了灵活的自定义数据存储能力。
  • 这些扩展索引使得 Nginx 能够在 SSL/TLS 层面上集成更多的功能(如会话缓存、OCSP Stapling 等)。
3 错误处理
  • 每个关键步骤都有详细的错误检查和日志记录。
  • 例如,OPENSSL_init_sslSSL_get_ex_new_index 等函数的返回值都被严格验证,确保初始化失败时能够及时发现问题。
4 性能优化
  • 禁用压缩是为了减少内存消耗,提升性能。
  • 通过扩展索引管理自定义数据,避免了全局变量的使用,提高了模块化程度和可维护性。

详解 

gcc -E src/event/ngx_event_openssl.c \
	-I src/core \
	-I src/event \
	-I src/event/modules \
	-I src/os/unix \
	-I objs \
	> ngx_event_openssl_preprocessed.c

使用以上命令处理条件编译

在输出文件 ngx_event_openssl_preprocessed.c 中 查找 ngx_ssl_init

ngx_int_t
ngx_ssl_init(ngx_log_t *log)
{


    if (OPENSSL_init_ssl(
# 148 "src/event/ngx_event_openssl.c" 3 4
                        0x00000040L
# 148 "src/event/ngx_event_openssl.c"
                                                , 
# 148 "src/event/ngx_event_openssl.c" 3 4
                                                  ((void *)0)
# 148 "src/event/ngx_event_openssl.c"
                                                      ) == 0) {
        ngx_ssl_error(2, log, 0, "OPENSSL_init_ssl() failed");
        return -1;
    }






    ERR_clear_error();
# 189 "src/event/ngx_event_openssl.c"
    ngx_ssl_connection_index = 
# 189 "src/event/ngx_event_openssl.c" 3 4
                              CRYPTO_get_ex_new_index(0, 
# 189 "src/event/ngx_event_openssl.c"
                              0
# 189 "src/event/ngx_event_openssl.c" 3 4
                              , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
# 189 "src/event/ngx_event_openssl.c"
                                                                             ;

    if (ngx_ssl_connection_index == -1) {
        ngx_ssl_error(2, log, 0, "SSL_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_server_conf_index = 
# 196 "src/event/ngx_event_openssl.c" 3 4
                               CRYPTO_get_ex_new_index(1, 
# 196 "src/event/ngx_event_openssl.c"
                               0
# 196 "src/event/ngx_event_openssl.c" 3 4
                               , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                              
# 197 "src/event/ngx_event_openssl.c"
                                                             ;
    if (ngx_ssl_server_conf_index == -1) {
        ngx_ssl_error(2, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_session_cache_index = 
# 204 "src/event/ngx_event_openssl.c" 3 4
                                 CRYPTO_get_ex_new_index(1, 
# 204 "src/event/ngx_event_openssl.c"
                                 0
# 204 "src/event/ngx_event_openssl.c" 3 4
                                 , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                                
# 205 "src/event/ngx_event_openssl.c"
                                                               ;
    if (ngx_ssl_session_cache_index == -1) {
        ngx_ssl_error(2, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_ticket_keys_index = 
# 212 "src/event/ngx_event_openssl.c" 3 4
                               CRYPTO_get_ex_new_index(1, 
# 212 "src/event/ngx_event_openssl.c"
                               0
# 212 "src/event/ngx_event_openssl.c" 3 4
                               , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                              
# 213 "src/event/ngx_event_openssl.c"
                                                             ;
    if (ngx_ssl_ticket_keys_index == -1) {
        ngx_ssl_error(2, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_ocsp_index = 
# 220 "src/event/ngx_event_openssl.c" 3 4
                        CRYPTO_get_ex_new_index(1, 
# 220 "src/event/ngx_event_openssl.c"
                        0
# 220 "src/event/ngx_event_openssl.c" 3 4
                        , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
# 220 "src/event/ngx_event_openssl.c"
                                                                           ;
    if (ngx_ssl_ocsp_index == -1) {
        ngx_ssl_error(2, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_certificate_index = 
# 227 "src/event/ngx_event_openssl.c" 3 4
                               CRYPTO_get_ex_new_index(1, 
# 227 "src/event/ngx_event_openssl.c"
                               0
# 227 "src/event/ngx_event_openssl.c" 3 4
                               , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                              
# 228 "src/event/ngx_event_openssl.c"
                                                             ;
    if (ngx_ssl_certificate_index == -1) {
        ngx_ssl_error(2, log, 0,
                      "SSL_CTX_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_next_certificate_index = 
# 235 "src/event/ngx_event_openssl.c" 3 4
                                    CRYPTO_get_ex_new_index(3, 
# 235 "src/event/ngx_event_openssl.c"
                                    0
# 235 "src/event/ngx_event_openssl.c" 3 4
                                    , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                                
# 236 "src/event/ngx_event_openssl.c"
                                                               ;
    if (ngx_ssl_next_certificate_index == -1) {
        ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_certificate_name_index = 
# 242 "src/event/ngx_event_openssl.c" 3 4
                                    CRYPTO_get_ex_new_index(3, 
# 242 "src/event/ngx_event_openssl.c"
                                    0
# 242 "src/event/ngx_event_openssl.c" 3 4
                                    , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
                                                                
# 243 "src/event/ngx_event_openssl.c"
                                                               ;

    if (ngx_ssl_certificate_name_index == -1) {
        ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");
        return -1;
    }

    ngx_ssl_stapling_index = 
# 250 "src/event/ngx_event_openssl.c" 3 4
                            CRYPTO_get_ex_new_index(3, 
# 250 "src/event/ngx_event_openssl.c"
                            0
# 250 "src/event/ngx_event_openssl.c" 3 4
                            , ((void *)0), ((void *)0), ((void *)0), ((void *)0))
# 250 "src/event/ngx_event_openssl.c"
                                                                            ;

    if (ngx_ssl_stapling_index == -1) {
        ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");
        return -1;
    }

    return 0;
}

可以看出

新版本的初始化

if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
    ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");
    return NGX_ERROR;
}
ERR_clear_error();

这个分支成立


 在 Ubuntu 环境下 使用:

openssl version

也可以查看 openssl 的版本 

可以知道 我这里属于 OpenSSL 1.1.0 及以上版本

OPENSSL_init_ssl 

在 OpenSSL 1.1.0 及以上版本中,OPENSSL_init_ssl 函数的声明位于以下头文件中:

#include <openssl/ssl.h>

OPENSSL_init_ssl 是 OpenSSL 1.1.0 引入的一个函数,用于初始化 SSL/TLS 库。它的主要作用是替代旧版本中多个独立的初始化函数(如 SSL_library_initSSL_load_error_strings 等),提供一个统一的接口来完成 SSL/TLS 的初始化工作。

函数原型如下:

int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
  • opts

    • 这是一个位掩码参数,用于指定初始化选项。
    • 常见的选项包括:
      • OPENSSL_INIT_LOAD_CONFIG:加载 OpenSSL 配置文件(通常是 openssl.cnf)。
      • OPENSSL_INIT_LOAD_SSL_STRINGS:加载 SSL/TLS 相关的错误字符串。
      • OPENSSL_INIT_ADD_ALL_CIPHERSOPENSSL_INIT_ADD_ALL_DIGESTS:注册所有加密算法和摘要算法。
      • OPENSSL_INIT_NO_LOAD_CONFIG:禁用配置文件加载。
      • 更多选项可以参考 OpenSSL 文档。
  • settings

    • 这是一个指向 OPENSSL_INIT_SETTINGS 结构的指针,用于传递更高级的初始化设置。
    • 在大多数情况下,可以传入 NULL,表示使用默认设置。
2.3 返回值
  • 成功时返回 1
  • 失败时返回 0

需要注意的是,即使 OPENSSL_init_ssl 返回成功,也可能在错误队列中留下未处理的错误信息。

因此,通常会在调用后清除错误队列:

ERR_clear_error();

ngx_ssl_error 

Ubuntu 下 nginx-1.24.0 源码分析 -ngx_ssl_error 函数-CSDN博客

NGX_ERROR

定义在 src/core/ngx_core.h 中

#define  NGX_OK          0
#define  NGX_ERROR      -1

初始化失败,函数返回 -1

ERR_clear_error

OpenSSL 使用一个线程安全的错误队列来记录操作过程中发生的错误信息。这些错误信息可以通过以下函数访问:

  • ERR_get_error():从错误队列中获取一个错误代码。
  • ERR_peek_error():查看错误队列中的第一个错误代码,但不移除它。
  • ERR_clear_error():清空当前线程的错误队列。

ERR_clear_error() 的主要作用是清空当前线程的错误队列。具体来说:

  • 它会移除所有当前线程中累积的错误信息。
  • 调用后,错误队列将变为空状态。

在多线程环境中,每个线程都有独立的错误队列,因此调用 ERR_clear_error() 不会影响其他线程的错误状态


通过调用 ERR_clear_error(),可以确保错误队列在初始化完成后处于干净的状态。这样,后续的 OpenSSL 操作如果产生错误,错误队列中的信息将是与当前操作直接相关的,而不是之前残留的无关错误

ngx_ssl_connection_index

ngx_ssl_connection_index 是一个全局变量,

它的作用是为每个 SSL 连接分配一个唯一的索引值。

这个索引值用于在 OpenSSL 的 SSL 结构体中存储和检索与该连接相关的自定义数据。


ngx_ssl_connection_index 是通过调用 SSL_get_ex_new_index() 创建的一个全局索引值

  1. 为每个 SSL 连接关联 Nginx 的特定数据

    • 在 Nginx 中,每个 SSL 连接都需要存储一些与 Nginx 相关的上下文信息(例如连接对象、会话状态等)。
    • 通过 ngx_ssl_connection_index,可以将这些数据存储到 OpenSSL 的 SSL 结构体中,并在需要时快速检索。
  2. 避免全局变量或复杂的数据结构

    • 如果没有扩展数据机制,Nginx 可能需要维护一个额外的映射表(例如哈希表或链表)来管理 SSL 连接和 Nginx 数据之间的关系。
    • 使用 ngx_ssl_connection_index,可以直接将数据附加到 SSL 结构体中,简化了数据管理。

SSL 连接

SSL 连接-CSDN博客


SSL 结构体中的扩展数据数组(ex_data)不仅仅用于存储用户自定义数据,它还可以被 OpenSSL 内部或其他模块使用。

ngx_ssl_connection_index 是通过 SSL_get_ex_new_index() 分配的一个索引值,指向数组中某个特定的位置,而该位置之前的内容可能已经被其他模块或 OpenSSL 内部使用

该位置是 用户自定义数据

SSL 结构体中的扩展数据数组是一个固定大小的数组

void *ex_data[SSL_MAX_EX_DATA];
  • SSL_MAX_EX_DATA :表示数组的最大长度,通常是 32 或更大的一个固定值。
  • 每个数组元素是一个指针,可以存储任意类型的数据
  • 数组的每个槽位由一个整数索引标识。
  • 索引值从 0 开始,依次递增。
  • 不同的模块或功能可以通过调用 SSL_get_ex_new_index() 分配自己的索引值,并将数据存储到对应的槽位中

SSL_CTX_get_ex_new_index

SSL_CTX_get_ex_new_index() 用于为 SSL_CTX(SSL 上下文)结构体 分配一个扩展数据索引。它的主要作用是:

  • SSL_CTX 中存储自定义数据 :例如全局配置、证书链、私钥等。
  • 支持模块化设计 :允许不同模块将自定义数据附加到 SSL_CTX 中,而无需修改 OpenSSL 的内部实现
返回值
  • 成功时返回一个非负整数,表示新分配的索引值。
  • 失败时返回 -1

SSL_get_ex_new_index 的作用

SSL_get_ex_new_index() 用于为 SSL(SSL 连接)结构体 分配一个扩展数据索引。它的主要作用是:

  • SSL 中存储自定义数据 :例如每个连接的上下文信息。
  • 支持连接级别的扩展数据管理 :允许开发者为每个 SSL 连接附加独立的数据
返回值
  • 成功时返回一个非负整数,表示新分配的索引值。
  • 失败时返回 -1

两者的区别

特性

SSL_CTX_get_ex_new_index

SSL_get_ex_new_index

目标结构体

SSL_CTX(SSL 上下文)

SSL(SSL 连接)

数据范围

全局数据,适用于所有 SSL 连接

每个连接独立的数据

典型用途

存储服务器配置、证书链、会话缓存等全局信息

存储每个连接的上下文信息(如 Nginx 的连接对象)

生命周期

SSL_CTX生命周期一致

与单个SSL实例的生命周期一致

分配的索引值是否共享

不同模块可以分配独立的索引值

不同模块可以分配独立的索引值 

 
  • SSL_CTX_get_ex_new_index :用于为 SSL_CTX 分配扩展数据索引,适用于存储全局数据(如服务器配置)。
  • SSL_get_ex_new_index :用于为 SSL 分配扩展数据索引,适用于存储每个连接的独立数据(如连接上下文)。
  • 核心区别 :两者的目标结构体不同,分别对应全局的 SSL_CTX 和每个连接的 SSL

X509_get_ex_new_index

X509_get_ex_new_index() 是 OpenSSL 提供的一个函数,用于为 X509(证书)结构体 分配扩展数据索引。它的主要作用是:

  • X509 结构体中存储自定义数据 :例如与证书相关的上下文信息或元数据。
  • 支持模块化设计 :允许不同模块将自定义数据附加到 X509 证书对象中,而无需修改 OpenSSL 的内部实现

返回值
  • 成功时返回一个非负整数,表示新分配的索引值。
  • 失败时返回 -1

X509 是 OpenSSL 库中用于表示 数字证书 的核心数据结构。它在 SSL/TLS 协议中扮演着至关重要的角色,主要用于身份验证、加密和信任链的建立


数字证书的核心概念

数字证书是一种电子文档,用于证明某个实体(如服务器或客户端)的身份,并包含该实体的公钥。数字证书通常由受信任的第三方机构(称为 证书颁发机构,CA )签发。

数字证书的主要内容
  • 主体信息(Subject) :证书持有者的身份信息(如域名、组织名称等)。
  • 公钥(Public Key) :证书持有者的公钥。
  • 签发者信息(Issuer) :签发证书的 CA 的身份信息。
  • 有效期(Validity Period) :证书的有效时间范围。
  • 签名(Signature) :CA 使用其私钥对证书内容进行签名,以确保证书的完整性和真实性

X509 结构体的作用

在 OpenSSL 中,X509 是一个复杂的数据结构,用于表示和操作数字证书。它的主要作用包括以下几个方面:

1. 身份验证
  • 在 SSL/TLS 握手过程中,服务器会向客户端发送其数字证书(X509 对象),以证明自己的身份。
  • 客户端通过验证证书的签名和有效期,确认服务器是否可信。
2. 公钥分发
  • 数字证书中包含了服务器的公钥,客户端可以使用该公钥与服务器进行加密通信。
  • 例如,在 RSA 密钥交换中,客户端使用服务器的公钥加密预主密钥(Pre-Master Secret)。
3. 建立信任链
  • 数字证书通常形成一个信任链(Certificate Chain),从服务器证书到根证书。
  • X509 提供了操作证书链的功能,例如验证证书链的完整性。
4. OCSP 和 CRL 验证
  • X509 支持在线证书状态协议(OCSP)和证书吊销列表(CRL),用于检查证书是否已被吊销。

数字证书在逻辑上和现实中的证件(如身份证、护照或驾照)非常相似。它们的作用都是用来证明某个实体的身份,并且依赖于一个可信的第三方机构来验证和签发

数字证书与现实证件的核心功能对比

功能

现实中的证件(如身份证)

数字证书

身份证明

证明持证人的身份(如姓名、照片、出生日期等)。

证明某个实体(如服务器或客户端)的身份。

签发机构

由政府或权威机构签发(如公安局)。

由受信任的 CA(证书颁发机构)签发。

有效期

证件有明确的有效期(如 10 年)。

证书有明确的有效期(如 1 年)。

防伪机制

使用防伪技术(如水印、芯片)防止伪造。

使用加密算法(如签名)防止篡改和伪造。

信任链

公众信任签发机构(如政府),从而信任证件。

用户信任 CA,从而信任其签发的证书。 

 

类比:现实中的身份证 vs 数字证书

1. 身份证明
  • 现实中的身份证
    • 身份证上的信息(如姓名、照片、身份证号)用于证明持证人的身份。
    • 当你出示身份证时,其他人可以通过检查这些信息确认你是谁。
  • 数字证书
    • 数字证书中的信息(如主体名称、公钥)用于证明某个实体的身份。
    • 当服务器向客户端发送证书时,客户端可以通过检查证书内容确认服务器的身份。
2. 签发机构
  • 现实中的身份证
    • 身份证由政府机构(如公安局)签发,公众信任政府,因此也信任身份证的真实性。
  • 数字证书
    • 数字证书由受信任的 CA(如 Let's Encrypt、DigiCert)签发,用户信任 CA,因此也信任其签发的证书。
3. 防伪机制
  • 现实中的身份证
    • 身份证可能包含防伪技术,例如水印、全息图或芯片,以防止伪造。
  • 数字证书
    • 数字证书使用加密算法(如 RSA 或 ECC)生成签名,CA 使用其私钥对证书内容进行签名,确保证书未被篡改。
4. 有效期
  • 现实中的身份证
    • 身份证通常有一个有效期(如 10 年),过期后需要重新申请。
  • 数字证书
    • 数字证书也有一个有效期(如 1 年或 2 年),过期后需要续签或重新申请。
5. 信任链
  • 现实中的身份证
    • 公众信任签发机构(如政府),因此信任其签发的身份证。
    • 如果有人伪造身份证,公众可以通过查询政府数据库验证其真实性。
  • 数字证书
    • 用户信任 CA,因此信任其签发的证书。
    • 如果证书被篡改或吊销,用户可以通过 CRL(证书吊销列表)或 OCSP(在线证书状态协议)验证其状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970965.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pandas(13 Caveats Gotchas和SQL比较)

前面内容&#xff1a;pandas(12 IO工具和稀松数据) 目录 一、Caveats警告 & Gotchas预见 1.1 在Pandas中使用if/Truth语句 1.2 位运算布尔 1.3 isin操作 1.4 重新索引reindex和 loc&iloc 使用注意事项 1.5 loc和iloc 二、Python Pandas 与SQL的比较 2.1 数…

MongoDB 7 分片副本集升级方案详解(下)

#作者&#xff1a;任少近 文章目录 1.4 分片升级1.5 升级shard11.6 升级shard2,shard31.7 升级mongos1.8重新启用负载均衡器1.9 推荐MongoDB Compass来验证数据 2 注意事项&#xff1a; 1.4 分片升级 使用“滚动”升级从 MongoDB 7.0 升级到 8.0&#xff0c;即在其他成员可用…

洛谷 P2894 USACO08FEB Hotel 题解

题意 第一行输入 n , m n,m n,m&#xff0c; n n n 代表有 n n n 个房间 ( 1 ≤ n ≤ 50 , 000 ) (1\leq n \leq 50,000) (1≤n≤50,000)&#xff0c;编号为 1 ∼ n 1 \sim n 1∼n&#xff0c;开始都为空房&#xff0c; m m m 表示以下有 m m m 行操作 ( 1 ≤ m < 50…

VS2022中.Net Api + Vue 从创建到发布到IIS

VS2022中.Net Api Vue 从创建到发布到IIS 前言一、先决条件二、创建项目三、运行项目四、增加API五、发布到IIS六、设置Vue的发布 前言 最近从VS2019 升级到了VS2022,终于可以使用官方的.Net Vue 组合了,但是使用过程中还是有很多问题,这里记录一下. 一、先决条件 Visual …

BGP分解实验·18——BGP选路原则之权重

在本地对进入的NLRI做权重设置&#xff0c;从而对过滤特定的路由进行优选。严格来说&#xff0c;权重值并不能算是路径属性&#xff0c;因为它并处传递&#xff0c;所能影响的仅仅限于本地路由器。 实验拓扑如下&#xff1a; 完成实验拓扑的基础实验&#xff0c;R1的配置如下…

正点原子ESP32S3系列开发板全面支持小智AI

什么是小智AI? 小智AI项目是由虾哥发起并开源的一个项目。该项目能帮助更多人入门AI硬件开发&#xff0c;了解如何将当下飞速发展的大语言模型应用到实际的硬件设备中。 小智AI功能如下&#xff1a; WiFi / ML307 Cat.1 4G BOOT键唤醒和打断&#xff0c;支持点击和长按两种触…

【2025最新计算机毕业设计】基于SpringBoot+Vue高校社团管理系统 【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

探寻性能优化:如何衡量?如何决策?

目录 一、衡量指标说明 &#xff08;一&#xff09;响应时间&#xff08;Response Time&#xff09; 平均响应时间&#xff08;Average Response Time&#xff09; 百分位数响应时间&#xff08;Percentile Response Time&#xff09; &#xff08;二&#xff09;吞吐量&a…

YOLO11环境搭建CUDA12.6

1.安装CUDA和cuDNN 1.1安装CUDA 1.1.1查看当前你的电脑显卡支持的最高CUDA版本,后面的安装不能超过它 通过命令的方式查看 输入nvidia-smi 1.1.2 下载CUDA 官网地址:CUDA Toolkit Archive | NVIDIA Developer 选择cuda_12.6.3 下载完成后,如下: 安装,一直下一步即可:…

Java多线程——性能与可伸缩性

可伸缩性 当增加计算资源时&#xff08;如CPU、内存、存储容量或I/O带宽&#xff09;&#xff0c;程序的吞吐量或处理能力能相应的增加 Amdahl定理 F为必须被串行执行的部分&#xff0c;在N个处理器的机器中&#xff0c;在增加计算资源所能达到的最高加速比是 N趋于无穷大时…

Spring Boot 项目启动报错 “找不到或无法加载主类” 解决笔记

一、问题描述 在使用 IntelliJ IDEA 开发基于 Spring Boot 框架的 Java 程序时&#xff0c;原本项目能够正常启动。但在后续编写代码并重建项目后&#xff0c;再次尝试运行却出现了 “错误&#xff1a;找不到或无法加载主类 com.example.springboot.SpringbootApplication” 的…

snort3.0-ubuntu18.04 64入侵检测安装与使用

在日常生活中&#xff0c;很多人怀疑自己的手机、电脑被监控了&#xff0c;担心自己的隐私泄漏&#xff0c;实际上最佳的检测方式就是终端检测&#xff0c;也就是EDR&#xff0c;但是就是有那么多的人在网上大放厥词&#xff0c;说任何EDR杀毒软件都检测不到监控&#xff0c;毕…

Spring Cloud-Sentinel

Sentinel服务熔断与限流 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。 官网地址&#xff1a;home | Sentinelhttps://sen…

蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)

题目&#xff1a;给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&#xff…

安卓设备调试h5页面(调试)

1、在chrome浏览器中输入网址&#xff1a;chrome://inspect/#devices 2、设备连接usb&#xff0c;打开对应app 3、点击inspect fallback&#xff0c;打开对应调试页面

第1章大型互联网公司的基础架构——1.6 RPC服务

你可能在1.1节的引言中注意到业务服务层包括HTTP服务和RPC服务&#xff0c;两者的定位不一样。一般来说&#xff0c;一个业务场景的核心逻辑都是在RPC服务中实现的&#xff0c;强调的是服务于后台系统内部&#xff0c;所谓的“微服务”主要指的就是RPC服务&#xff1b;而HTTP服…

【NLP251】BertTokenizer 的全部 API 及 使用案例

BertTokenizer 是 Hugging Face 的 transformers 库中用于处理 BERT 模型输入的分词器类。它基于 WordPiece 分词算法&#xff0c;能够将文本分割成词汇单元&#xff08;tokens&#xff09;&#xff0c;并将其转换为 BERT 模型可以理解的格式。BertTokenizer 是 BERT 模型的核心…

SOCKET建立简单的tcp服务端与客户端通信

socket是什么 socket可以使两台机子建立连接&#xff0c;就像连接风扇与电源的插座一样&#xff0c;socket可以使服务端与客户端建立连接&#xff0c;服务端就像供电厂&#xff0c;而客户端就像用电器&#xff0c;而socket就是连接二者的插座。 建立简单的连接 如果我们想在客…

机试刷题_字符串的排列【python】

题目&#xff1a;字符串的排列 from os import dup # # 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可 # # # param str string字符串 # return string字符串一维数组 # class Solution:def backtrack(self,res,state,choi…

PostgreSQL有undo表空间吗?

PostgreSQL有undo表空间吗 PostgreSQL 没有单独的 Undo 表空间&#xff0c;其事务回滚和多版本并发控制&#xff08;MVCC&#xff09;机制与 Oracle 等数据库有显著差异。 一 PostgreSQL 的 MVCC 实现 PostgreSQL 通过 多版本并发控制&#xff08;MVCC&#xff09; 管理事务…