[AI问答]OpenSSL3.0+上的异步调用

帮我生成一个使用openssl3.0+ provider算法异步调用的示例

关于 OpenSSL 异步框架的"关键认知"

在看代码之前,有一个关于 OpenSSL 异步机制非常重要且容易误解的点需要说明:

仅仅把一个普通的计算函数(比如算 SHA256)塞进 ASYNC_start_job 里,它并不会自动变成异步非阻塞的。

OpenSSL 的异步机制基于协程/线程(Fibers/ucontext)。它的工作原理是:

  1. 主线程调用 ASYNC_start_job 进入协程。
  2. 协程内部的代码开始执行。
  3. 关键点: 只有当协程内部的代码(通常是底层的硬件 Provider)主动调用 ASYNC_pause_job() 时,协程才会挂起,控制权才会返回给主线程(此时 start_job 返回 ASYNC_PAUSE)。
  4. 主线程去干别的事情。
  5. 当硬件完成操作,主线程再次调用 ASYNC_start_job,协程会从上次暂停的地方恢复执行。

默认的纯软件加密算法(如默认 Provider 里的 SHA256)是不会 调用 ASYNC_pause_job() 的。它们会一口气算完,导致 start_job 依然是阻塞的。

为了在这个演示程序中体现出"异步交替执行"的效果,我会在包装函数中人为地调用 ASYNC_p ause_job() 来模拟硬件卸载的延迟。

完整代码 (test_md_async.c)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/async.h>
#include <openssl/err.h>

// 传递给协程的参数结构体
struct async_args {
    EVP_MD_CTX *mdctx;
    unsigned char *digest;
    unsigned int *digest_len;
};

// =========================================================================
// 这是将在 OpenSSL 协程(Fiber)中执行的工作函数
// =========================================================================
static int async_job_wrapper(void *arg) {
    struct async_args *args = (struct async_args *)arg;

    printf("  [Fiber] 协程开始执行...\n");

    // 【模拟异步硬件操作】
    // 真实的异步 Provider (例如 Intel QAT) 会在这里向硬件发送指令,
    // 获取一个文件描述符(fd),并调用 ASYNC_pause_job() 挂起当前协程。
    printf("  [Fiber] 模拟调用外部硬件... 挂起当前协程,将控制权交还主线程。\n");
    
    // 主动挂起协程 (非常重要,否则就变成同步阻塞了)
    ASYNC_pause_job();

    printf("  [Fiber] 协程被唤醒!硬件操作完成,继续执行。\n");

    // 执行实际的加密计算操作 (这里使用软件 SHA256 替代硬件计算)
    int ret = EVP_DigestFinal_ex(args->mdctx, args->digest, args->digest_len);

    printf("  [Fiber] 协程执行完毕。\n");
    return ret; // 这个返回值会被传递给主线程
}

// 辅助打印函数
void print_hex(const char* label, const unsigned char* data, size_t len) {
    printf("%s: ", label);
    for (size_t i = 0; i < len; ++i) {
        printf("%02x", data[i]);
    }
    printf("\n");
}

int main() {
    OSSL_LIB_CTX *libctx = NULL;
    OSSL_PROVIDER *provider = NULL;
    EVP_MD *sm3 = NULL;
    EVP_MD_CTX *mdctx = NULL;
    
    // 异步相关的变量
    ASYNC_JOB *job = NULL;
    ASYNC_WAIT_CTX *waitctx = NULL;

    const unsigned char message[] = "Hello OpenSSL 3 Async Framework!";
    unsigned char digest[EVP_MAX_MD_SIZE];
    unsigned int digest_len = 0;

    int job_ret = 0;
    int status;
    int ret_code = 1;

    printf("1. 初始化 OpenSSL 3.0 上下文和 Provider\n");
    libctx = OSSL_LIB_CTX_new();
    provider = OSSL_PROVIDER_load(libctx, "default");
    if (!provider) {
        fprintf(stderr, "加载 provider 失败\n");
        goto cleanup;
    }

    // 初始化异步环境 (当前线程)
    if (!ASYNC_init_thread(1, 0)) {
        fprintf(stderr, "初始化异步线程失败\n");
        goto cleanup;
    }

    printf("2. 准备 SM3 摘要操作\n");
    sm3 = EVP_MD_fetch(libctx, "SM3", NULL);
    mdctx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(mdctx, sm3, NULL);
    EVP_DigestUpdate(mdctx, message, strlen((const char *)message));

    // 打包参数
    struct async_args args = { mdctx, digest, &digest_len };

    // 创建等待上下文 (必须有)
    waitctx = ASYNC_WAIT_CTX_new();
    if (!waitctx) goto cleanup;

    printf("3. 启动异步作业 (进入状态机)...\n");
    printf("--------------------------------------------------\n");

    // 【主循环:驱动异步状态机】
    while (1) {
        printf("[Main]  调用 ASYNC_start_job...\n");
        
        // 启动或恢复协程
        status = ASYNC_start_job(&job, waitctx, &job_ret, async_job_wrapper, &args, sizeof(args));

        if (status == ASYNC_PAUSE) {
            // 协程内部调用了 ASYNC_pause_job()
            printf("[Main]  作业已挂起 (ASYNC_PAUSE)。\n");
            printf("[Main]  --> 此时主线程是非阻塞的,可以去处理网络事件或执行其他任务 <--\n");
            
            // 在实际的高性能应用中,这里会通过 epoll 获取 waitctx 中的 FD 并等待。
            // 这里的演示我们直接继续下一次循环(即立即唤醒它)。
            
        } else if (status == ASYNC_FINISH) {
            // 协程内部的函数 return 了
            printf("[Main]  作业已完成 (ASYNC_FINISH)。\n");
            break;
            
        } else if (status == ASYNC_ERR) {
            fprintf(stderr, "[Main]  作业执行出错 (ASYNC_ERR)。\n");
            ERR_print_errors_fp(stderr);
            goto cleanup;
        }
    }
    printf("--------------------------------------------------\n");

    printf("4. 获取最终结果 (协程返回值: %d)\n", job_ret);
    if (job_ret == 1) {
        print_hex("Message", message, strlen((const char *)message));
        print_hex("SM3", digest, digest_len);
        ret_code = 0;
    }

cleanup:
    // 清理资源
    if (waitctx) ASYNC_WAIT_CTX_free(waitctx);
    // ASYNC_JOB 通常会在 FINISH 后自动释放,无需手动 free
    ASYNC_cleanup_thread(); // 清理当前线程的异步环境
    
    if (mdctx) EVP_MD_CTX_free(mdctx);
    if (sm3) EVP_MD_free(sm3);
    if (provider) OSSL_PROVIDER_unload(provider);
    if (libctx) OSSL_LIB_CTX_free(libctx);

    return ret_code;
}

Makefile

cpp 复制代码
CC = gcc -g
CFLAGS = -fPIC -Wall -I/usr/include
LIBS = -lcrypto -L.

all: test_md_async

test_md_async: test_md_async.o
    $(CC) -o $@ $^ $(LIBS) -Wl,-rpath,.

%.o: %.c
    $(CC) $(CFLAGS) -c $<

clean:
    rm -f *.o test_app

运行后结果

bash 复制代码
$ make
$ ./test_md_async 
1. 初始化 OpenSSL 3.0 上下文和 Provider
2. 准备 SM3 摘要操作
3. 启动异步作业 (进入状态机)...
--------------------------------------------------
[Main]  调用 ASYNC_start_job...
  [Fiber] 协程开始执行...
  [Fiber] 模拟调用外部硬件... 挂起当前协程,将控制权交还主线程。
[Main]  作业已挂起 (ASYNC_PAUSE)。
[Main]  --> 此时主线程是非阻塞的,可以去处理网络事件或执行其他任务 <--
[Main]  调用 ASYNC_start_job...
  [Fiber] 协程被唤醒!硬件操作完成,继续执行。
  [Fiber] 协程执行完毕。
[Main]  作业已完成 (ASYNC_FINISH)。
--------------------------------------------------
4. 获取最终结果 (协程返回值: 1)
Message: 48656c6c6f204f70656e53534c2033204173796e63204672616d65776f726b21
SM3: 8c1408025467f1ea3db8b40d4858d9b9df25178bc70bed8c544e2adf409e6cb7
相关推荐
缘友一世6 小时前
PentestGPT V2源码研究之EGATS规划器
网络安全·渗透测试
初九之潜龙勿用8 小时前
C# 解决“因为算法不同,客户端和服务器无法通信”的问题
服务器·开发语言·网络协议·网络安全·c#
0DayHP10 小时前
HTB:DarkZero[WriteUP]
网络安全·内网渗透
一名优秀的码农11 小时前
vulhub系列-52-ICA: 1(超详细)
安全·web安全·网络安全·网络攻击模型·安全威胁分析
大方子12 小时前
【好靶场】某博客存在SQL注入
网络安全·好靶场
heze0914 小时前
sqli-labs-Less-61
数据库·mysql·网络安全
Chockmans15 小时前
春秋云境CVE-2020-25483
web安全·网络安全·春秋云境·cve-2020-25483
菩提小狗16 小时前
每日安全情报报告 · 2026-04-01
网络安全·漏洞·cve·安全情报·每日安全
三七吃山漆16 小时前
BUUCTF[极客大挑战 2019]Http
web安全·网络安全·ctf·极客大挑战