You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将EVP_PKEY类型改为EVP_PKEY_RSA_PSS导致C程序段错误

问题分析与解决方案

问题根源

直接调用EVP_PKEY_set_type将密钥类型改为EVP_PKEY_RSA_PSS会触发段错误,核心原因是:
EVP_PKEY_RSA仅包含RSA核心参数(模n、指数e),而EVP_PKEY_RSA_PSS属于带特定配置的RSA变种,需要额外的PSS参数(如MGF1哈希算法、盐长度、签名哈希算法等)。直接修改类型后,密钥结构缺失这些必要参数,后续函数(如PEM_write_PUBKEY)访问不存在的内存时就会崩溃。

正确实现方式

要生成合法的EVP_PKEY_RSA_PSS类型公钥,需在构建密钥时明确初始化PSS相关参数,而非直接修改已有RSA密钥的类型。以下是修正后的代码:

#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <stdio.h>

// 假设bignum_base64_decode是已实现的Base64URL解码函数
BIGNUM* bignum_base64_decode(const char* data);

int generate_pubkey(char* exponent, char* modulus, EVP_PKEY** pubkey) {
    BIGNUM *n = bignum_base64_decode(modulus);
    BIGNUM *e = bignum_base64_decode(exponent);
    int ret = -1;

    if (!e || !n) {
        printf("Error: Invalid encoding for public exponent or modulus\n");
        goto cleanup;
    }

    // 1. 创建普通RSA结构并设置核心参数
    RSA* rsa = RSA_new();
    if (!rsa || !RSA_set0_key(rsa, n, e, NULL)) {
        printf("Error: Failed to set RSA key components\n");
        goto cleanup;
    }
    // 注:RSA_set0_key会接管n和e的所有权,无需手动释放

    // 2. 创建RSA-PSS类型的EVP_PKEY上下文
    EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA_PSS, NULL);
    if (!ctx) {
        printf("Error: Failed to create RSA-PSS context\n");
        goto cleanup_rsa;
    }

    // 3. 初始化上下文并设置PSS参数(这里使用SHA256,可按需修改)
    if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
        EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0 || // 盐长度等于哈希长度
        EVP_PKEY_CTX_set_md(ctx, EVP_sha256()) <= 0) {
        printf("Error: Failed to configure RSA-PSS parameters\n");
        goto cleanup_ctx;
    }

    // 4. 从RSA结构生成RSA-PSS类型的EVP_PKEY
    if (EVP_PKEY_fromdata(ctx, pubkey, EVP_PKEY_PUBLIC_KEY, rsa) <= 0) {
        printf("Error: Failed to create RSA-PSS public key\n");
        goto cleanup_ctx;
    }

    // 5. 写入PEM文件
    FILE* fp = fopen("pubnew.key", "w");
    if (!fp) {
        printf("Failed to open file for writing\n");
        goto cleanup_pubkey;
    }
    if (PEM_write_PUBKEY(fp, *pubkey) <= 0) {
        printf("Error: Failed to write public key to file\n");
    } else {
        ret = 0;
    }
    fclose(fp);

cleanup_pubkey:
    // 写入失败时释放生成的公钥
    if (ret != 0 && *pubkey) {
        EVP_PKEY_free(*pubkey);
        *pubkey = NULL;
    }
cleanup_ctx:
    EVP_PKEY_CTX_free(ctx);
cleanup_rsa:
    RSA_free(rsa); // RSA_free会自动释放n和e
    return ret;
cleanup:
    if (n) BN_free(n);
    if (e) BN_free(e);
    return ret;
}

关键说明

  1. 参数完整性:必须通过EVP_PKEY_CTX配置RSA-PSS的必要参数,否则生成的密钥结构不合法,无法正常使用。
  2. 内存所有权:RSA_set0_key会接管n和e的内存,EVP_PKEY_fromdata会接管rsa的内存,无需重复释放。
  3. 错误处理:所有OpenSSL函数调用都需检查返回值,避免内存泄漏或非法内存访问。

内容的提问来源于stack exchange,提问作者Vijay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:10:28