- 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)
396 行
14 KiB
C
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;
|
|
}
|