英文:
validating signature using EC public key in openssl causing crash while freeing ECKey
问题
以下是您提供的代码部分的中文翻译:
// 我有一个 EC 公钥坐标,分别为 "x" 和 "y",它们是 64 字节的字符串。
// 我有一条消息,必须使用我拥有的签名进行验证。
// 我编写了下面显示的函数。在释放密钥时,该函数崩溃,即在使用行 EC_KEY_free(ec_key) 时。
// 如果我注释掉这一行,就不会出现崩溃。请提供您的意见/提示,为什么这一行会导致问题。感谢您的指导。
// 例如,公钥 "x" 和 "y" 的值如下:
// x 为 5CA6D40011278E3FF84FD94DD80E370CD90F2A304E9CEFB946082AB82FF0DBDE
// y 为 C05CA8BC76B1BF49C085672B76D19368394F2EDEF4A11D492BE34F14F3803AD1
// 在使用上述值后,我拥有的 BIGNUM 打印值如下:
// BIGNUM x 坐标:0x5CA6D40011278E3FF84FD94DD80E370CD90F2A304E9CEFB946082AB82FF0DBDE
// BIGNUM y 坐标: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;
// 解析公钥
BIGNUM* x = BN_new();
BIGNUM* y = BN_new();
if (!BN_hex2bn(&x, public_key_x)) {
perror("解析公钥 x 坐标时出错");
return -1;
}
printBN("BIGNUM x 坐标:", x);
if (!BN_hex2bn(&y, public_key_y)) {
perror("解析公钥 y 坐标时出错");
return -1;
}
printBN("BIGNUM y 坐标:", y);
/*
EC_KEY 代表公钥和(可选的)相关私钥。
可以通过调用 EC_KEY_new 来构建一个新的 EC_KEY(没有关联的曲线)。
新创建的 EC_KEY 的引用计数最初设置为 1。
可以通过调用 EC_KEY_set_group 来将曲线与 EC_KEY 关联起来。
或者,可以通过调用 EC_KEY_new_by_curve_name 来构建一个新的 EC_KEY,
并提供关联曲线的 nid(命名标识符)。
运行 "openssl ecparam -list_curves" 查看曲线名称。
该函数简单地包装了对 EC_KEY_new 和 EC_GROUP_new_by_curve_name 的调用。
*/
// 使用曲线 SECP256R1 创建 EC 密钥。
if ((ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) {
fprintf(stderr, "创建 EC 密钥时出错\n");
goto end;
}
// 创建 EC 点。EC_KEY_get0_group 返回与 EC_KEY 关联的 EC_GROUP。
if ((ec_point = EC_POINT_new(EC_KEY_get0_group(ec_key))) == NULL) {
fprintf(stderr, "创建 EC 点时出错\n");
goto end;
}
// 设置点的 x 和 y 坐标
if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(ec_key), ec_point, x, y, NULL)) {
fprintf(stderr, "设置 EC 点坐标时出错\n");
goto end;
}
// 设置 EC 密钥的公钥
if (!EC_KEY_set_public_key(ec_key, ec_point)) {
fprintf(stderr, "设置 EC 公钥时出错\n");
goto end;
}
// 将 EC 密钥分配给 EVP_PKEY
if ((public_key = EVP_PKEY_new()) == NULL) {
fprintf(stderr, "创建 EVP_PKEY 时出错\n");
goto end;
}
if (!EVP_PKEY_assign_EC_KEY(public_key, ec_key)) {
fprintf(stderr, "将 EC 密钥分配给 EVP_PKEY 时出错\n");
goto end;
}
// 创建消息摘要上下文
if ((md_ctx = EVP_MD_CTX_new()) == NULL) {
fprintf(stderr, "创建消息摘要上下文时出错\n");
goto end;
}
// 使用 SHA-256 和公钥初始化消息摘要上下文
if (!EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL, public_key)) {
fprintf(stderr, "初始化消息摘要上下文时出错\n");
goto end;
}
// 使用消息更新消息摘要上下文
if (!EVP_DigestVerifyUpdate(md_ctx, message, message_len)) {
fprintf(stderr, "更新消息摘要上下文时出错\n");
goto end;
}
// 验证签名
result = EVP_DigestVerifyFinal(md_ctx, signature, signature_len);
printf("结果:%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);
// 如果 (ec_key != NULL) 则释放 EC_KEY(FIXME: 这里导致崩溃)
if (ec_key != NULL) EC_KEY_free(ec_key);
return result;
}
请注意,我只翻译了您提供的代码部分,没有包含其他内容。如果您需要进一步的帮助或解释,请随时提问。
英文:
I have EC Public key coordinates "x" and "y" which are 64 bytes string. I have a message which has to be validated with signature I have. I have written a function as shown below. Below function is crashing while freeing the key using line EC_KEY_free(ec_key). If I comment this line no crash is observed. Require your inputs/hints why this line is causing a problem. Thanks for your guidance.
For example public key "x" and "y" values are
x is 5CA6D40011278E3FF84FD94DD80E370CD90F2A304E9CEFB946082AB82FF0DBDE
y is C05CA8BC76B1BF49C085672B76D19368394F2EDEF4A11D492BE34F14F3803AD1
After using BIGNUM with above values. I have BN print values as shown below
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 (optionaly) 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);
> if (ec_key != NULL) EC_KEY_free(ec_key); // FIXME: here it crashes
return result;
}
答案1
得分: 3
如果您查看EVP_PKEY_assign_EC_KEY函数的文档:
> EVP_PKEY_assign_RSA(),EVP_PKEY_assign_DSA(),EVP_PKEY_assign_DH(),
> EVP_PKEY_assign_EC_KEY(),EVP_PKEY_assign_POLY1305()和
> EVP_PKEY_assign_SIPHASH()将引用的密钥设置为key,但是在内部使用提供的密钥,因此在释放父pkey时,key将被释放。
这意味着通过调用EVP_PKEY_assign_EC_KEY,您正在将EC_KEY的“所有权”转让给了EVP_PKEY,当您释放EVP_PKEY(EVP_PKEY_free调用)时,它将为您释放它。因此,调用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; // public_key现在拥有ec_key,因此我们放弃了对它的控制
英文:
If you look at the documentation for the EVP_PKEY_assign_EC_KEY function:
> EVP_PKEY_assign_RSA(), EVP_PKEY_assign_DSA(), EVP_PKEY_assign_DH(),
> EVP_PKEY_assign_EC_KEY(), EVP_PKEY_assign_POLY1305() and
> EVP_PKEY_assign_SIPHASH() set the referenced key to key however these
> use the supplied key internally and so key will be freed when the
> parent pkey is freed.
This means that by calling EVP_PKEY_assign_EC_KEY you are transfering "ownership" of the EC_KEY to the EVP_PKEY and it will free it for you when you free the EVP_PKEY (EVP_PKEY_free call). So the call to EC_KEY_free is freeing it for a second time causing the crash.
So a fix would be:
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; // public_key now owns ec_key so we give up control of it
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论