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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:15:29