调用EVP_PKEY_fromdata将EC私钥存入EVP_PKEY失败求助
问题分析与修复方案
核心问题点
参数构建的条件判断逻辑错误
原代码中判断param_bld创建和group参数入栈的逻辑用了&&,这会导致只有当param_bld为NULL且入栈失败时才报错,实际只要其中任一操作失败就应该终止流程,需要改为||。EVP_PKEY_fromdata的flags参数误用
你传入的EVP_PKEY_KEY_PARAMETERS | OSSL_KEYMGMT_SELECT_PRIVATE_KEY不符合函数预期:EVP_PKEY_KEY_PARAMETERS用于设置密钥参数(如曲线类型),而非构建完整私钥。正确的flags应该直接使用OSSL_KEYMGMT_SELECT_PRIVATE_KEY,或者更简洁的EVP_PKEY_PRIVATE_KEY(两者等价)。缺少OpenSSL错误信息输出
原代码只打印自定义错误,没有输出OpenSSL底层的错误详情,这会导致无法定位具体失败原因。
修正后的完整代码
#include <openssl/evp.h> #include <openssl/param_build.h> #include <openssl/ec.h> #include <openssl/err.h> #include <iostream> using namespace std; /* * Fixed data to represent the private key. */ const unsigned char priv_data[] = { 0xb9, 0x2f, 0x3c, 0xe6, 0x2f, 0xfb, 0x45, 0x68, 0x39, 0x96, 0xf0, 0x2a, 0xaf, 0x6c, 0xda, 0xf2, 0x89, 0x8a, 0x27, 0xbf, 0x39, 0x9b, 0x7e, 0x54, 0x21, 0xc2, 0xa1, 0xe5, 0x36, 0x12, 0x48, 0x5d}; void errMsg(string msg) { cout << msg << endl; // 打印OpenSSL底层错误信息 ERR_print_errors_fp(stderr); exit(1); } int main() { EVP_PKEY_CTX *ctx; EVP_PKEY *key = NULL; OSSL_PARAM_BLD *param_bld; OSSL_PARAM *params = NULL; // 初始化OpenSSL错误处理 ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); param_bld = OSSL_PARAM_BLD_new(); // 修改逻辑判断为||,任一失败则报错 if (param_bld == NULL || OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", "prime256v1", 0) != 1) { errMsg("Setup params failed"); } ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); if (ctx == NULL || EVP_PKEY_fromdata_init(ctx) <= 0) { errMsg("Setup ctx failed"); } // store private key BIGNUM *priv = BN_bin2bn(priv_data, sizeof(priv_data), NULL); if (priv == NULL) { errMsg("Conversion to BIGNUM failed"); } if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv) != 1) { errMsg("Loading private key data to params failed"); } params = OSSL_PARAM_BLD_to_param(param_bld); // 修正flags参数,使用正确的私钥选择标识 if (EVP_PKEY_fromdata(ctx, &key, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, params) <= 0) { errMsg("Setting private key failed"); } else { cout << "Private key is stored inside the EVP_PKEY" << endl; } // 资源释放 BN_free(priv); EVP_PKEY_free(key); // 新增:释放创建的EVP_PKEY EVP_PKEY_CTX_free(ctx); OSSL_PARAM_free(params); OSSL_PARAM_BLD_free(param_bld); // 清理OpenSSL错误栈 ERR_free_strings(); return 0; }
额外说明
- 新增了OpenSSL错误处理的初始化和清理,确保能打印底层错误信息,方便后续调试。
- 补充了
EVP_PKEY_free(key)的资源释放,避免内存泄漏。 - 修正后的代码会正确将给定的EC私钥加载到
EVP_PKEY结构中。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

