Linux下用OpenSSL验证DS28C36的ECDSA签名遇转换与验证异常求助
问题排查与解决步骤
1. BN_bn2hex段错误的根源与修复
段错误几乎都是BIGNUM指针未正确初始化或转换失败导致的空指针访问。DS28C36返回的r、s是32字节的大端序数据,转换时必须严格遵循以下步骤:
// 正确初始化BIGNUM并转换原始字节 BIGNUM *r = BN_new(); BIGNUM *s = BN_new(); if (!r || !s) { // 处理内存分配失败 goto cleanup; } // DS28C36的r、s为32字节大端序,直接用BN_bin2bn转换 if (!BN_bin2bn(raw_r, 32, r) || !BN_bin2bn(raw_s, 32, s)) { // 处理字节转BIGNUM失败(比如数据长度不对) goto cleanup; } // 安全调用BN_bn2hex,记得用完释放内存 char *r_hex = BN_bn2hex(r); char *s_hex = BN_bn2hex(s); if (r_hex && s_hex) { printf("r: %s\n", r_hex); printf("s: %s\n", s_hex); OPENSSL_free(r_hex); OPENSSL_free(s_hex); } cleanup: // 注意:如果后续用ECDSA_SIG_set0接管了r、s,这里不要手动free // 否则会导致双重释放
错误场景:直接用NULL指针调用BN_bin2bn,或者转换失败后未检查就调用BN_bn2hex,都会触发段错误。
2. i2d_ECDSA_SIG返回2字节的问题修复
返回2字节说明生成的ECDSA_SIG结构无效(r或s为空),DER编码仅输出了序列标签0x30和空长度0x00。正确生成DER格式签名的步骤:
// 创建ECDSA_SIG对象并设置r、s ECDSA_SIG *sig = ECDSA_SIG_new(); if (!sig) { goto cleanup; } // ECDSA_SIG_set0会接管r、s的内存,之后不要手动free r、s if (!ECDSA_SIG_set0(sig, r, s)) { goto cleanup; } // 先获取DER编码所需长度 int der_len = i2d_ECDSA_SIG(sig, NULL); if (der_len <= 0) { goto cleanup; } // 分配内存并执行编码 unsigned char *der_sig = OPENSSL_malloc(der_len); if (!der_sig) { goto cleanup; } unsigned char *p = der_sig; i2d_ECDSA_SIG(sig, &p); // p会自动移动到编码后的末尾,无需手动操作 // 此时der_sig就是正确的DER格式签名,长度为der_len // 后续用ECDSA_verify验证时传入der_sig和der_len cleanup: ECDSA_SIG_free(sig); // 会自动释放内部的r、s OPENSSL_free(der_sig);
关键注意点:
- 必须确保
r、s是有效的BIGNUM(转换成功且非空) - 调用
i2d_ECDSA_SIG时,第二个参数要传指向指针的指针,且先通过NULL获取长度,避免缓冲区溢出
3. ECDSA_verify验证失败的额外排查点
除了签名格式问题,还要检查以下常见错误:
- 公钥加载错误:DS28C36的公钥是x、y各32字节,需转换为
EC_KEY对象:EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); // 对应P-256曲线 EC_GROUP *group = EC_KEY_get0_group(ec_key); EC_POINT *pub_point = EC_POINT_new(group); // 把x、y字节转成BIGNUM后,设置到EC_POINT EC_POINT_set_affine_coordinates_GFp(group, pub_point, x_bn, y_bn, NULL); EC_KEY_set_public_key(ec_key, pub_point); - 传入原始数据而非哈希摘要:
ECDSA_verify的第三个参数是原始数据的SHA-256哈希值(DS28C36默认用SHA-256),不是原始数据本身。如果直接传原始数据,验证必然失败。 - 曲线不匹配:必须使用DS28C36对应的NIST P-256曲线(
NID_X9_62_prime256v1),否则公钥和签名的验证逻辑不兼容。
内容的提问来源于stack exchange,提问作者feplooptest
相关产品推荐
相关产品推荐

