文件
PazeSSH/src/crypto/ecdsa.c
T
JGZYES 6da27731b5 实现 TLS 1.2 握手与版本回退,修复 GCM 记录层 RFC 偏差
- tls_handshake12.c: 完整 TLS 1.2 client/server 状态机(ECDHE-RSA/ECDSA/RSA AES-GCM + CHACHA20-POLY1305),支持 1.3 收到 1.2 ServerHello/ClientHello 后回退
- tls_record.c: 修正 TLS 1.2 AEAD-GCM 两处 RFC 偏差: AAD length 字段应为明文长度 ctlen(RFC 5246 6.2.3.3)原为 ct+16; GCMNonce = fixed_iv(4) || explicit_nonce(8)(RFC 5288 3)原顺序相反
- tls_handshake13.c: CV/Finished transcript 处理、1.3 套件记录版本修正、链式证书构造
- x509.c: AttributeTypeAndValue 补 SEQUENCE; validity 2050 年前用 UTCTime
- apps/pazessl: s_client/s_server 增加 -tls1_2
- 新增 build.ps1、build/run_tls_test.ps1、build/run_openssl_interop.ps1

验证: 自测 4/4(1.2/1.3 双向 + 回退); OpenSSL 互操作 4/4(s_client/s_server 双向 1.2/1.3)
2026-08-13 17:30:31 +08:00

396 行
14 KiB
C

/* ecdsa.c —— ECDSA 签名/验签 (P-256, RFC 6979 确定性 k)
*
* 签名:k 由 RFC 6979 从私钥与消息摘要确定性派生,避免 RNG 重用漏洞。
* 验签:标准 ECDSA,公式 v = (u1*G + u2*Q).x mod n == r。
* 签名编码:DER SEQUENCE { r INTEGER, s INTEGER }。
*
* 依赖:p256 (点运算)、bignum、hmac、hash、asn1。
*/
#include "paze/ecdsa.h"
#include "paze/hmac.h"
#include "paze/hash.h"
#include "paze/asn1.h"
#include "paze/encoding.h"
#include "paze/random.h"
#include "paze/mem.h"
#include "paze/error.h"
#include <stdlib.h>
#include <string.h>
/* ---- 哈希算法选择 ---- */
static const paze_hash_alg_t *hash_alg_of(paze_rsa_hash_t h) {
switch (h) {
case PAZE_RSA_HASH_SHA1: return paze_hash_sha1();
case PAZE_RSA_HASH_SHA256: return paze_hash_sha256();
case PAZE_RSA_HASH_SHA512: return paze_hash_sha512();
default: return NULL; /* SHA-224/384 暂未实现 */
}
}
/* bits2int:取 input 左起 qlen_bits 位作为整数。
* - inlen*8 > qlen: 右移 (inlen*8 - qlen) 位(保留高位)
* - inlen*8 == qlen: 原值
* - inlen*8 < qlen: 左移补零 */
static void bits2int(paze_bn_t *z, const uint8_t *in, size_t inlen, int qlen_bits) {
paze_bn_from_bytes(z, in, inlen);
int blen = (int)inlen * 8;
if (blen > qlen_bits) {
paze_bn_rshift(z, z, blen - qlen_bits);
} else if (blen < qlen_bits) {
paze_bn_lshift(z, z, qlen_bits - blen);
}
}
/* int2octets:x -> qlen_bits/8 字节大端(x 必须已 < q 以保证不溢出) */
static void int2octets(uint8_t *out, size_t outlen, const paze_bn_t *x) {
paze_bn_to_bytes(x, out, outlen);
}
/* ============================================================
* RFC 6979 确定性 k 生成
* 输入:私钥 d(标量), 消息摘要 h1(原始字节), 哈希算法
* 输出:k (1 <= k < n),写入 k_be[32]
* ============================================================ */
static paze_status_t rfc6979_k(uint8_t k_be[32],
const paze_bn_t *d,
const uint8_t *h1, size_t h1len,
paze_rsa_hash_t hash_alg) {
const paze_hash_alg_t *alg = hash_alg_of(hash_alg);
if (!alg) return PAZE_ERR_NOTSUP;
size_t hlen = alg->digest_len;
paze_bn_t n;
paze_p256_load_n(&n);
int qlen_bits = paze_bn_bit_len(&n); /* 256 */
/* int2octets(d): d < n,32 字节 */
uint8_t x_oct[32];
int2octets(x_oct, 32, d);
/* bits2octets(h1): z1 = bits2int(h1); z2 = z1 mod n; int2octets(z2, 32) */
paze_bn_t z1, z2;
bits2int(&z1, h1, h1len, qlen_bits);
paze_bn_mod(&z2, &z1, &n);
uint8_t h1_oct[32];
int2octets(h1_oct, 32, &z2);
/* V = 0x01 * hlen, K = 0x00 * hlen */
uint8_t V[64], K[64];
memset(V, 0x01, hlen);
memset(K, 0x00, hlen);
uint8_t buf[64 + 1 + 32 + 32];
uint8_t T[64];
/* K = HMAC_K(V || 0x00 || x || h1_oct) */
memcpy(buf, V, hlen); buf[hlen] = 0x00;
memcpy(buf + hlen + 1, x_oct, 32);
memcpy(buf + hlen + 1 + 32, h1_oct, 32);
paze_hmac(alg, K, hlen, buf, hlen + 1 + 32 + 32, K);
paze_hmac(alg, K, hlen, V, hlen, V); /* V = HMAC_K(V) */
/* K = HMAC_K(V || 0x01 || x || h1_oct); V = HMAC_K(V) */
memcpy(buf, V, hlen); buf[hlen] = 0x01;
memcpy(buf + hlen + 1, x_oct, 32);
memcpy(buf + hlen + 1 + 32, h1_oct, 32);
paze_hmac(alg, K, hlen, buf, hlen + 1 + 32 + 32, K);
paze_hmac(alg, K, hlen, V, hlen, V);
/* 循环生成 k */
for (int retry = 0; retry < 256; retry++) {
/* T = empty; while len(T) < qlen: V = HMAC_K(V); T = T||V */
size_t tlen = 0;
while (tlen < (size_t)(qlen_bits + 7) / 8) {
paze_hmac(alg, K, hlen, V, hlen, V);
memcpy(T + tlen, V, hlen);
tlen += hlen;
}
/* k = bits2int(T) */
paze_bn_t k;
bits2int(&k, T, tlen, qlen_bits);
if (!paze_bn_is_zero(&k) && paze_bn_cmp(&k, &n) < 0) {
paze_bn_to_bytes(&k, k_be, 32);
return PAZE_OK;
}
/* 否则 K = HMAC_K(V || 0x00); V = HMAC_K(V) */
memcpy(buf, V, hlen); buf[hlen] = 0x00;
paze_hmac(alg, K, hlen, buf, hlen + 1, K);
paze_hmac(alg, K, hlen, V, hlen, V);
}
return PAZE_ERR; /* 极不可能 */
}
/* ============================================================
* 公钥/私钥管理
* ============================================================ */
void paze_ecdsa_priv_set_d(paze_ecdsa_priv_t *k, const uint8_t d_be[32]) {
memcpy(k->d, d_be, 32);
}
paze_status_t paze_ecdsa_pub_from_priv(paze_ecdsa_pub_t *pub, const uint8_t d_be[32]) {
paze_p256_scalar_mult(&pub->Q, d_be, NULL); /* Q = d * G */
return PAZE_OK;
}
paze_status_t paze_ecdsa_gen(paze_ecdsa_priv_t *k) {
paze_bn_t n, d;
paze_p256_load_n(&n);
/* 生成 [1, n-1] 随机 d */
do {
paze_bn_random_range(&d, &n);
} while (paze_bn_is_zero(&d));
paze_bn_to_bytes(&d, k->d, 32);
return paze_p256_scalar_mult(&k->Q, k->d, NULL);
}
/* ============================================================
* DER 签名编解码
* ============================================================ */
static paze_status_t w_integer(paze_asn1_writer_t *w, const paze_bn_t *x) {
if (paze_bn_is_zero(x)) return paze_asn1_w_integer(w, (const uint8_t *)"\x00", 1);
size_t blen = paze_bn_byte_len(x);
uint8_t buf[PAZE_BN_MAX_LIMBS * 4 + 1];
paze_bn_to_bytes(x, buf + 1, blen);
if (buf[1] & 0x80) {
buf[0] = 0x00;
return paze_asn1_w_integer(w, buf, blen + 1);
}
return paze_asn1_w_integer(w, buf + 1, blen);
}
static paze_status_t r_integer(paze_asn1_reader_t *r, paze_bn_t *x) {
uint8_t buf[PAZE_BN_MAX_LIMBS * 4 + 1];
size_t blen = sizeof(buf);
paze_status_t rc = paze_asn1_read_integer(r, buf, &blen);
if (rc != PAZE_OK) return rc;
return paze_bn_from_bytes(x, buf, blen);
}
paze_status_t paze_ecdsa_sig_to_der(const paze_bn_t *r, const paze_bn_t *s,
uint8_t *out, size_t *outlen) {
paze_asn1_writer_t body; paze_asn1_w_init(&body, NULL, 0);
int rc = w_integer(&body, r);
if (rc == PAZE_OK) rc = w_integer(&body, s);
if (rc != PAZE_OK) { paze_asn1_w_free(&body); return rc; }
paze_asn1_writer_t w; paze_asn1_w_init(&w, NULL, 0);
rc = paze_asn1_w_reserve(&w, body.len + 6);
if (rc == PAZE_OK) rc = paze_asn1_w_tag_len(&w, ASN1_SEQUENCE, body.len);
if (rc == PAZE_OK) rc = paze_asn1_w_data(&w, body.buf, body.len);
paze_asn1_w_free(&body);
if (rc != PAZE_OK) { paze_asn1_w_free(&w); return rc; }
if (*outlen < w.len) { *outlen = w.len; paze_asn1_w_free(&w); return PAZE_ERR_SHORT; }
memcpy(out, w.buf, w.len);
*outlen = w.len;
paze_asn1_w_free(&w);
return PAZE_OK;
}
paze_status_t paze_ecdsa_sig_from_der(paze_bn_t *r, paze_bn_t *s,
const uint8_t *der, size_t len) {
paze_asn1_reader_t rd, body;
paze_asn1_r_init(&rd, der, len);
if (paze_asn1_enter_seq(&rd, &body) != PAZE_OK) return PAZE_ERR_FORMAT;
if (r_integer(&body, r) != PAZE_OK) return PAZE_ERR_FORMAT;
if (r_integer(&body, s) != PAZE_OK) return PAZE_ERR_FORMAT;
return PAZE_OK;
}
/* ============================================================
* 签名
* ============================================================ */
paze_status_t paze_ecdsa_sign(const paze_ecdsa_priv_t *k,
paze_rsa_hash_t hash_alg,
const uint8_t *mhash, size_t hlen,
uint8_t *sig, size_t *siglen) {
if (!k || !mhash || !sig || !siglen) return PAZE_ERR_INVALID;
if (!hash_alg_of(hash_alg)) return PAZE_ERR_NOTSUP;
if (hlen != paze_rsa_hash_len(hash_alg)) return PAZE_ERR_INVALID;
paze_bn_t n, d, z;
paze_p256_load_n(&n);
paze_bn_from_bytes(&d, k->d, 32);
/* z = bits2int(mhash) */
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
paze_bn_t r, s;
uint8_t k_be[32];
paze_status_t rc;
/* RFC 6979 生成 k,计算 r = (k*G).x mod n, s = k^-1 (z + r*d) mod n。
* 若 r==0 或 s==0,RFC 6979 继续下一轮 k(理论极罕见)。 */
int got = 0;
for (int round = 0; round < 8 && !got; round++) {
rc = rfc6979_k(k_be, &d, mhash, hlen, hash_alg);
if (rc != PAZE_OK) return rc;
paze_p256_point_t Rpt;
paze_p256_scalar_mult(&Rpt, k_be, NULL); /* R = k*G */
if (paze_p256_is_inf(&Rpt)) continue;
paze_p256_get_x_mod_n(&r, &Rpt);
if (paze_bn_is_zero(&r)) continue;
/* s = k^-1 (z + r*d) mod n */
paze_bn_t k_bn, rd, sum, kinv;
paze_bn_from_bytes(&k_bn, k_be, 32);
paze_bn_modmul(&rd, &r, &d, &n);
paze_bn_modadd(&sum, &z, &rd, &n);
paze_bn_modinv(&kinv, &k_bn, &n);
paze_bn_modmul(&s, &kinv, &sum, &n);
if (paze_bn_is_zero(&s)) continue;
/* low-s 归一化:s > n/2 则 s = n - s (减少签名可延展性) */
paze_bn_t half_n;
paze_bn_rshift(&half_n, &n, 1);
if (paze_bn_cmp(&s, &half_n) > 0) {
paze_bn_sub(&s, &n, &s);
}
got = 1;
}
if (!got) return PAZE_ERR;
return paze_ecdsa_sig_to_der(&r, &s, sig, siglen);
}
/* ============================================================
* 验签
* ============================================================ */
paze_status_t paze_ecdsa_verify(const paze_ecdsa_pub_t *pub,
paze_rsa_hash_t hash_alg,
const uint8_t *mhash, size_t hlen,
const uint8_t *sig, size_t siglen) {
if (!pub || !mhash || !sig) return PAZE_ERR_INVALID;
if (!hash_alg_of(hash_alg)) return PAZE_ERR_NOTSUP;
if (hlen != paze_rsa_hash_len(hash_alg)) return PAZE_ERR_INVALID;
paze_bn_t r, s, n;
if (paze_ecdsa_sig_from_der(&r, &s, sig, siglen) != PAZE_OK) return PAZE_ERR_FORMAT;
paze_p256_load_n(&n);
/* r, s 须在 [1, n-1] */
if (paze_bn_is_zero(&r) || paze_bn_is_zero(&s)) return PAZE_ERR_VERIFY;
if (paze_bn_cmp(&r, &n) >= 0 || paze_bn_cmp(&s, &n) >= 0) return PAZE_ERR_VERIFY;
/* z = bits2int(mhash) */
paze_bn_t z;
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
/* w = s^-1 mod n; u1 = z*w mod n; u2 = r*w mod n */
paze_bn_t w, u1, u2;
paze_bn_modinv(&w, &s, &n);
paze_bn_modmul(&u1, &z, &w, &n);
paze_bn_modmul(&u2, &r, &w, &n);
/* 点1 = u1*G; 点2 = u2*Q; R = 点1 + 点2 */
uint8_t u1_be[32], u2_be[32];
paze_bn_to_bytes(&u1, u1_be, 32);
paze_bn_to_bytes(&u2, u2_be, 32);
paze_p256_point_t P1, P2, Rpt;
paze_p256_scalar_mult(&P1, u1_be, NULL); /* u1 * G */
paze_p256_scalar_mult(&P2, u2_be, &pub->Q); /* u2 * Q */
paze_p256_add(&Rpt, &P1, &P2);
if (paze_p256_is_inf(&Rpt)) return PAZE_ERR_VERIFY;
paze_bn_t v;
paze_p256_get_x_mod_n(&v, &Rpt);
return (paze_bn_cmp(&v, &r) == 0) ? PAZE_OK : PAZE_ERR_VERIFY;
}
/* ---- PEM 包装 ---- */
/* EC 私钥 DER (RFC 5915) 解析:仅支持 P-256 */
static paze_status_t ecdsa_priv_parse_der(paze_ecdsa_priv_t *k,
const uint8_t *der, size_t len) {
if (!k || !der) return PAZE_ERR_INVALID;
paze_asn1_reader_t r, body;
paze_asn1_r_init(&r, der, len);
if (paze_asn1_enter_seq(&r, &body) != PAZE_OK) return PAZE_ERR_FORMAT;
/* version INTEGER(1) */
uint8_t tag; const uint8_t *b; size_t blen;
if (paze_asn1_read_tl(&body, &tag, &b, &blen) != PAZE_OK) return PAZE_ERR_FORMAT;
if (tag != ASN1_INTEGER) return PAZE_ERR_FORMAT;
/* privateKey OCTET STRING */
if (paze_asn1_read_tl(&body, &tag, &b, &blen) != PAZE_OK) return PAZE_ERR_FORMAT;
if (tag != ASN1_OCTETSTRING || blen != 32) return PAZE_ERR_FORMAT;
memcpy(k->d, b, 32);
/* 尝试读可选参数 */
if (!paze_asn1_at_end(&body)) {
paze_asn1_read_tl(&body, &tag, &b, &blen);
if (tag == ASN1_CTX0) {
/* parameters [0]: 跳过(假设就是 P-256 OID) */
if (!paze_asn1_at_end(&body)) {
paze_asn1_read_tl(&body, &tag, &b, &blen);
}
}
}
/* 尝试读可选 publicKey [1] BIT STRING */
if (tag == ASN1_CTX1 && blen >= 1 && b[0] == 0x00) {
const uint8_t *pk = b + 1;
size_t pklen = blen - 1;
if (pklen == 65 && pk[0] == 0x04) {
/* 使用嵌入的公钥点 */
paze_p256_from_affine(&k->Q, pk, 65);
return PAZE_OK;
}
}
/* 无公钥:从私钥推导 Q = d*G */
paze_p256_scalar_mult(&k->Q, k->d, NULL);
return PAZE_OK;
}
paze_status_t paze_ecdsa_priv_from_pem(paze_ecdsa_priv_t *k, const char *pem_text) {
if (!k || !pem_text) return PAZE_ERR_INVALID;
memset(k, 0, sizeof(*k));
size_t dlen = 0;
uint8_t *der = paze_pem_decode(pem_text, "EC PRIVATE KEY", &dlen);
if (!der) return PAZE_ERR_FORMAT;
paze_status_t st = ecdsa_priv_parse_der(k, der, dlen);
free(der);
return st;
}
paze_status_t paze_ecdsa_pub_from_pem(paze_ecdsa_pub_t *pub, const char *pem_text) {
if (!pub || !pem_text) return PAZE_ERR_INVALID;
memset(pub, 0, sizeof(*pub));
size_t dlen = 0;
/* PUBLIC KEY = X.509 SPKI 格式 */
uint8_t *der = paze_pem_decode(pem_text, "PUBLIC KEY", &dlen);
if (!der) return PAZE_ERR_FORMAT;
/* 解析 X.509 SPKI: SEQUENCE { AlgorithmIdentifier, BIT STRING } */
paze_asn1_reader_t r, spki;
paze_asn1_r_init(&r, der, dlen);
paze_status_t st = paze_asn1_enter_seq(&r, &spki);
if (st != PAZE_OK) { free(der); return PAZE_ERR_FORMAT; }
/* 跳过 AlgorithmIdentifier */
uint8_t tag; const uint8_t *b; size_t blen;
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
if (st != PAZE_OK) { free(der); return PAZE_ERR_FORMAT; }
if (tag != ASN1_SEQUENCE) { free(der); return PAZE_ERR_FORMAT; }
/* spki now points past the SEQUENCE content */
/* BIT STRING */
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
if (st != PAZE_OK || tag != ASN1_BITSTRING || blen < 2) {
free(der); return PAZE_ERR_FORMAT;
}
if (b[0] != 0x00) { free(der); return PAZE_ERR_FORMAT; }
const uint8_t *pk = b + 1;
size_t pklen = blen - 1;
if (pklen != 65 || pk[0] != 0x04) { free(der); return PAZE_ERR_FORMAT; }
st = paze_p256_from_affine(&pub->Q, pk, 65);
free(der);
return st;
}