OpenSSL中EC公钥验签时释放EC_KEY引发崩溃问题求助
EC验签函数
EC_KEY_free崩溃问题排查 我拥有64字节字符串格式的EC公钥x、y坐标,需使用已有签名验证指定消息。编写了如下验签函数,但执行EC_KEY_free(ec_key)行时发生崩溃,注释该行则无崩溃现象。恳请提供问题原因提示或建议。
示例公钥x、y值
x is 5CA6D40011278E3FF84FD94DD80E370CD90F2A304E9CEFB946082AB82FF0DBDE y is C05CA8BC76B1BF49C085672B76D19368394F2EDEF4A11D492BE34F14F3803AD1
转换为BIGNUM后的打印值
BIGNUM x coordinate: 0x5CA6D40011278E3FF84FD94DD80E370CD90F2A304E9CEFB946082AB82FF0DBDE BIGNUM y coordinate: 0xC05CA8BC76B1BF49C085672B76D19368394F2EDEF4A11D492BE34F14F3803AD1
验签函数代码
int verifySignature(const unsigned char* message, size_t message_len, const unsigned char* signature, size_t signature_len, const char* public_key_x, const char* public_key_y) { int result = 0; EC_KEY* ec_key = NULL; EC_POINT* ec_point = NULL; EVP_PKEY* public_key = NULL; EVP_MD_CTX* md_ctx = NULL; // parse public key BIGNUM* x = BN_new(); BIGNUM* y = BN_new(); if (!BN_hex2bn(&x, public_key_x)) { perror("Error parsing public key x coordinate"); return -1; } printBN("BIGNUM x coordinate: ", x); if (!BN_hex2bn(&y, public_key_y)) { perror("Error parsing public key y coordinate"); return -1; } printBN("BIGNUM y coordinate: ", y); /* An EC_KEY represents a public key and (optionally) an associated private key. A new EC_KEY (with no associated curve) can be constructed by calling EC_KEY_new. The reference count for the newly created EC_KEY is initially set to 1. A curve can be associated with the EC_KEY by calling EC_KEY_set_group. Alternatively a new EC_KEY can be constructed by calling EC_KEY_new_by_curve_name and supplying the nid of the associated curve. Run "openssl ecparam -list_curves" for curve names. This function simply wraps calls to EC_KEY_new and EC_GROUP_new_by_curve_name. */ // Create the EC key with the curve SECP256R1. if ((ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) { fprintf(stderr, "Error creating EC key\n"); goto end; } // Create the EC point. EC_KEY_get0_group returns the EC_GROUP associated with the EC_KEY. if ((ec_point = EC_POINT_new(EC_KEY_get0_group(ec_key))) == NULL) { fprintf(stderr, "Error creating EC point\n"); goto end; } // Set the x and y coordinates of the point if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), ec_point, x, y, NULL)) { fprintf(stderr, "Error setting EC point coordinates\n"); goto end; } // Set the public key for the EC key if (!EC_KEY_set_public_key(ec_key, ec_point)) { fprintf(stderr, "Error setting EC public key\n"); goto end; } // Assign the EC key to the EVP_PKEY if ((public_key = EVP_PKEY_new()) == NULL) { fprintf(stderr, "Error creating EVP_PKEY\n"); goto end; } if (!EVP_PKEY_assign_EC_KEY(public_key, ec_key)) { fprintf(stderr, "Error assigning EC key to EVP_PKEY\n"); goto end; } // Create the message digest context if ((md_ctx = EVP_MD_CTX_new()) == NULL) { fprintf(stderr, "Error creating message digest context\n"); goto end; } // Initialize the message digest context with SHA-256 and the public key if (!EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL, public_key)) { fprintf(stderr, "Error initializing message digest context\n"); goto end; } // Update the message digest context with the message if (!EVP_DigestVerifyUpdate(md_ctx, message, message_len)) { fprintf(stderr, "Error updating message digest context\n"); goto end; } // Verify the signature result = EVP_DigestVerifyFinal(md_ctx, signature, signature_len); printf("Result: %d\n", result); end: if (result != 1) { ERR_print_errors_fp(stderr); } if (md_ctx != NULL) EVP_MD_CTX_free(md_ctx); if (public_key != NULL) EVP_PKEY_free(public_key); if (ec_point != NULL) EC_POINT_free(ec_point); // FIXME: here it crashes if (ec_key != NULL) EC_KEY_free(ec_key); return result; }
问题原因与修复方案
核心原因
EVP_PKEY_assign_EC_KEY函数会接管ec_key的所有权,当调用EVP_PKEY_free(public_key)时,OpenSSL会自动释放关联的ec_key对象。此时再执行EC_KEY_free(ec_key)属于重复释放内存,直接触发崩溃。
修复方式(二选一)
- 删除
EC_KEY_free(ec_key)行:既然EVP_PKEY_free已经负责释放ec_key,无需手动重复释放。 - 赋值后清空
ec_key指针:在调用EVP_PKEY_assign_EC_KEY后,立即将ec_key置为NULL,这样后续的EC_KEY_free判断会跳过:if (!EVP_PKEY_assign_EC_KEY(public_key, ec_key)) { fprintf(stderr, "Error assigning EC key to EVP_PKEY\n"); goto end; } ec_key = NULL; // 新增这一行
额外内存泄漏修复
代码中创建的BIGNUM* x和BIGNUM* y没有释放,会导致内存泄漏,需要在end块中添加释放逻辑:
end: if (result != 1) { ERR_print_errors_fp(stderr); } // 新增:释放BIGNUM对象 if (x != NULL) BN_free(x); if (y != NULL) BN_free(y); if (md_ctx != NULL) EVP_MD_CTX_free(md_ctx); if (public_key != NULL) EVP_PKEY_free(public_key); if (ec_point != NULL) EC_POINT_free(ec_point); // 已修复:要么删除该行,要么确保ec_key为NULL if (ec_key != NULL) EC_KEY_free(ec_key); return result;
内容的提问来源于stack exchange,提问作者venkysmarty
相关产品推荐
相关产品推荐

