diff --git a/AGENT.MD b/AGENT.MD index e47cb40..f4773bf 100644 --- a/AGENT.MD +++ b/AGENT.MD @@ -27,16 +27,37 @@ STATUS.md 完成度总表 AGENT.md 本文件 8. **Git**:中文提交信息;不主动推送,用户要求才推(parlz=gitea、origin=GitHub);无 push 权限/网络问题时如实报告。 9. **文档**:改功能同步更新 STATUS.md;不建多余 .md。 +## 已实现功能要点 + +### 0-RTT / HRR(TLS 1.3,RFC 8446) +- 状态机(`src/ssl/tls_handshake13.c`): + - 客户端:`paze_tls13_client_send_ch`(抽出的 CH 发送,幂等)、`client_handle_hrr`(识别 HRR 魔数 → `paze_tls_tr_reset_to_synthetic` 合成 MessageHash → CH2 仅选定组 share)、`client_rebuild_transcript`、EndOfEarlyData 在 client Finished **之前**用 early_write 发送 + - 服务端:`server_try_psk`(ticket MAC+binder 验证)、`ch_ext_cb`/`ks_lookup_cb`(supported_groups 首组 vs key_share 查找决定 HRR)、`sent_hrr` 分支发送 HRR(random=魔数 `CF21AD74E58690691115AEDE1F40DFC9C4504D46C174A12E8B4A6F1346F84A4F`)、early_read 解密早数据入 `early_buf`、跳过 EndOfEarlyData 后切 handshake_read +- key schedule(`src/ssl/tls_keys.c`):`paze_tls13_derive_early_key`(PSK 关联 hash 直哈希最终 CH,client_early_traffic_secret → early_write/early_read)、`paze_tls13_psk_early_secret` +- 扩展(`src/ssl/tls_extensions.c`):`paze_tls_ext_write/parse_early_data`(type 42)、`key_share_client(…only_group)` +- 内部字段(`src/ssl/tls_internal.h`):`hrr_raw/ch2/had_hrr/hrr_group/sent_hrr`、`early_offer/early_sent/early_accepted/early_accept`、`early_read/early_write` +- 公共 API(`include/paze/tls.h` + `tls_conn.c`):`paze_tls_config_enable_early_data`、`paze_tls_early_write`(握手前发早数据)、`paze_tls_early_data_accepted`、`paze_tls_early_data_len`(服务端早数据缓冲)、`paze_tls_hrr_occurred` +- CLI(`apps/pazessl/main.c`):`s_client -early -sess_in/-sess_out -key_share X25519|P-256`;`s_server -early -reuse` +- 已知约束:0-RTT 仅在同进程会话复用(ticket_key 内存态)时可用;跨进程重启服务端会拒绝 PSK → early 记录解密失败(预期行为) +- 验证:`s_server -reuse 2 -early` + 两次 `s_client`(首次 `-sess_out`、二次 `-sess_in -early`)→ `early data received` + `early accepted`;`-key_share P-256` → `hrr=YES` + ## 待办(按优先级) -### 1. 0-RTT / HRR — TLS 1.3 数据路径(✅ 已完成 2026-08-13) -- 服务端:CH 无 key_share → 发 HRR(random=魔数 `CF21AD74...F84A4F`)→ 等 CH2;`sent_hrr` 标记 -- 客户端:识别 HRR 魔数 → `paze_tls_tr_reset_to_synthetic` → 生成 CH2(仅选定组 share)→ 放弃 0-RTT -- 0-RTT:客户端 CH 带 early_data 扩展 + 发 early 数据(early_write);服务端解密(early_read);EndOfEarlyData 用 client_early_traffic_secret -- 验证:`pazessl s_client -early -sess_in ...` / `s_server -early` 端到端通过(同进程会话复用);`-key_share P-256` 触发 HRR 通过 +### 1. 0-RTT / HRR — TLS 1.3 数据路径(✅ 已完成 2026-08-13,详见上文要点) -### 2. TLS secp384r1 -实现 P-384 点运算(bignum 已有),加曲线 + 套件,中等偏繁。 +### 2. TLS secp384r1(✅ 已完成 2026-08-13) + +已实现 P-384 完整链路: +- 曲线:`src/crypto/p384.c` + `include/paze/p384.h`(Jacobian 点运算、常量时间标量乘、仿射编解码,结构对齐 p256) +- ECDSA:`ecdsa.c/h` 新增 `paze_ecdsa_p384_sign/verify`(RFC 6979 确定性 k)、`paze_ecdsa_p384_priv_from_pem/der`(RFC 5915,secp384r1) +- X.509:`x509.c/h` 支持 secp384r1 证书解析(`pk_kind==ECDSA_P384`)、验签(ecdsa-with-SHA384,及 SHA256 配 P-384)、`paze_x509_build_spki384`、签发(`signer.ecdsa_d384`) +- TLS:`tls.h` 增 `PAZE_TLS_GROUP_SECP384R1(0x0018)` / `PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384(0x0503)`;`tls_internal.h` `kex` 增 `P384` 与 `p384_priv[48]/p384_pub[97]`;`tls_handshake13.c` `kex_generate/ecdh`、sign_cv/verify_cv、HRR、服务端 key_share 支持 P-384(ECDH 按 SEC1 x 坐标 48 字节);`tls_extensions.c` supported_groups/signature_algorithms/key_share;TLS 1.2 ECDHE 亦支持 +- CLI:`s_client -key_share P-384` +- 验证:P-384 曲线(n·G=∞、3G=2G+G)、ECDSA 双向(OpenSSL 验我的签名 + 我验 OpenSSL 签名)、X.509 P-384 自签名证书 OpenSSL `verify=OK`、TLS 端点 P-384 密钥交换(hrr=YES)+证书链/主机名验证全部通过;既有自测无回归 + +附带修复: +- `ecdsa.c` `bits2int`:输入短于群阶 qlen 时应右对齐而非左移(否则 P-384+SHA-256 验签错误) +- `tls_conn.c` 新增 `paze_tls_store_peer_cert`:对端证书 DER 拷贝到自有缓冲,避免 issuer/subject 指针指向被记录层复用的 `app_buf` 导致链验证失败(TLS 1.3 与 1.2 均在 Certificate 解析处使用) ### 3. SSH ProxyJump 客户端连接管理(经跳板机转发),中等。 diff --git a/STATUS.md b/STATUS.md index 47bc904..2463d5f 100644 --- a/STATUS.md +++ b/STATUS.md @@ -2,7 +2,6 @@ > PazeSSL / PazeSSH:从零实现、仅依赖 libc 的 OpenSSL / OpenSSH 平替(纯 C, ISO C17)。 > 按层推进,本文件汇总当前各层完成度(2026-08-13 更新)。 - ## 总体 | 层 | 模块 | 状态 | @@ -17,7 +16,7 @@ - 哈希:SHA-1 / SHA-256 / SHA-512 / MD5 / HMAC / HKDF / PBKDF2 - 对称:AES-128/192/256、AES-CBC/GCM、ChaCha20、Poly1305、ChaCha20-Poly1305 AEAD -- 曲线:X25519、Ed25519、P-256、ECDSA(大数运算自研:模幂、模逆、Montgomery) +- 曲线:X25519、Ed25519、**P-256、P-384(secp384r1)**、ECDSA(大数运算自研:模幂、模逆、Montgomery) - 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码 - 其他:ASN.1 DER、base64、hex、常量时间准则 @@ -32,6 +31,8 @@ - ✅ TLS 1.3 SHA-384 密码套件(TLS_AES_256_GCM_SHA384)服务端/客户端握手(含 PSK 恢复的 resumption_master_secret) - ✅ **0-RTT 数据路径**(RFC 8446 §4.2.10/§4.5/§8):early_data 扩展、client_early_traffic_secret 密钥派生、握手前早数据收发、EndOfEarlyData(early key 加密且计入 transcript);`pazessl s_client/s_server -early` 端到端验证(早数据接收 + early accepted) - ✅ **HRR(HelloRetryRequest)**(RFC 8446 §4.1.3/§4.1.4):服务端 key_share 不匹配时发 HRR(随机数=固定魔数)、transcript 合成 MessageHash 重放、客户端 CH2(仅选定组 share)响应、HRR 后放弃 0-RTT;`-key_share` 选项触发,`hrr=YES` 互操作验证通过 +- ✅ **secp384r1(TLS P-384)**:新增 P-384 曲线点运算(`p384.c`,Jacobian,常量时间标量乘);ECDSA 支持 P-384 签名/验签(RFC 6979 确定性 k,`paze_ecdsa_p384_*`);X.509 支持 secp384r1 证书解析/验签/签发(含 ecdsa-with-SHA384 与 P-384 公钥,`paze_x509_build_spki384`);TLS 1.3 支持 secp384r1 组(key_share/supported_groups/ECDH 按 SEC1 x 坐标)、签名算法 ECDSA_SECP384R1_SHA384;TLS 1.2 ECDHE 亦支持 P-384。`s_client -key_share P-384` 端到端验证(含 HRR 触发与 P-384 证书链/主机名验证);曲线与 ECDSA 经 OpenSSL 双向交叉验证 +- ✅ **修复**:ECDSA `bits2int` 输入短于群阶时错误左移(影响 P-384+SHA-256 验签);TLS 1.3/1.2 对端证书 `issuer_dn/subject_dn` 等指针指向被记录层复用缓冲导致的链验证失败(`paze_tls_store_peer_cert` 拷贝 DER) ## PazeSSH — SSH-2(✅ 完成) diff --git a/apps/pazessl/main.c b/apps/pazessl/main.c index 31cd78d..a8fcf1e 100644 --- a/apps/pazessl/main.c +++ b/apps/pazessl/main.c @@ -72,7 +72,7 @@ static int usage(void) { "PazeSSL v0.1 (libc-only TLS 1.3 + 1.2)\n" "Usage:\n" " pazessl s_client -connect host:port [-CAfile roots.pem] [-servername SNI] [-tls1_2]\n" - " [-sess_in file] [-sess_out file] [-msg text] [-early] [-key_share X25519|P-256]\n" + " [-sess_in file] [-sess_out file] [-msg text] [-early] [-key_share X25519|P-256|P-384]\n" " pazessl s_server -accept port -cert cert.pem -key key.pem [-tls1_2] [-reuse N] [-early]\n" " pazessl verify -CAfile roots.pem cert.pem\n" " pazessl genrsa -out key.pem [2048]\n" @@ -163,7 +163,8 @@ int main(int argc, char **argv) { uint16_t g = 0; if (strcmp(key_share, "X25519") == 0) g = PAZE_TLS_GROUP_X25519; else if (strcmp(key_share, "P-256") == 0) g = PAZE_TLS_GROUP_SECP256R1; - else { fprintf(stderr, "bad -key_share (X25519|P-256)\n"); return 1; } + else if (strcmp(key_share, "P-384") == 0) g = PAZE_TLS_GROUP_SECP384R1; + else { fprintf(stderr, "bad -key_share (X25519|P-256|P-384)\n"); return 1; } if (paze_tls_config_set_kex_group(cfg, g) != PAZE_OK) return 1; } if (sni) paze_tls_config_set_sni(cfg, sni); diff --git a/include/paze/ecdsa.h b/include/paze/ecdsa.h index db03a73..2aff97d 100644 --- a/include/paze/ecdsa.h +++ b/include/paze/ecdsa.h @@ -60,6 +60,29 @@ paze_status_t paze_ecdsa_priv_from_pem(paze_ecdsa_priv_t *k, const char *pem_tex /* PEM 包装:从 PEM 文本中加载公钥("PUBLIC KEY" / X.509 SPKI label) */ paze_status_t paze_ecdsa_pub_from_pem(paze_ecdsa_pub_t *pub, const char *pem_text); +/* ============================================================ + * P-384 (secp384r1) 签名/验签 + * 输入为原始字节而非结构体,便于 P-384 证书/TLS 直接使用: + * d_bytes = 私钥标量,48 字节大端 (< n) + * pub_affine = 未压缩公钥点,97 字节 (0x04 || X || Y) + * 哈希:配 ecdsa_secp384r1_SHA384 用 PAZE_RSA_HASH_SHA384。确定性 k (RFC 6979)。 + * 签名输出 DER (SEQUENCE { r INTEGER, s INTEGER }),长度不超过 siglen。 + * ============================================================ */ +paze_status_t paze_ecdsa_p384_sign(const uint8_t d_bytes[48], + paze_rsa_hash_t hash_alg, + const uint8_t *mhash, size_t hlen, + uint8_t *sig, size_t *siglen); +paze_status_t paze_ecdsa_p384_verify(const uint8_t pub_affine[97], + paze_rsa_hash_t hash_alg, + const uint8_t *mhash, size_t hlen, + const uint8_t *sig, size_t siglen); + +/* P-384 (RFC 5915) EC PRIVATE KEY 解析:校验 named curve 为 secp384r1, + * 写 48 字节私钥标量到 d384。 */ +paze_status_t paze_ecdsa_p384_priv_from_der(uint8_t d384[48], + const uint8_t *der, size_t len); +paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_text); + #ifdef __cplusplus } #endif diff --git a/include/paze/p384.h b/include/paze/p384.h new file mode 100644 index 0000000..d4bf492 --- /dev/null +++ b/include/paze/p384.h @@ -0,0 +1,68 @@ +/* p384.h —— NIST P-384 (secp384r1) 椭圆曲线 + * + * 域算术复用 bignum (mod p),点运算用 Jacobian 坐标。 + * 曲线参数: y^2 = x^3 - 3x + b (mod p) + * p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + * n = G 的阶 + * + * 用于 ECDSA 签名 (TLS 证书) 与 ECDH (TLS 密钥交换)。 + * 与 p256.h 结构/接口保持一致;标量 48 字节,仿射点 97 字节。 + */ +#ifndef PAZE_P384_H +#define PAZE_P384_H + +#include "paze/paze_types.h" +#include "paze/bignum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Jacobian 坐标点:(X:Y:Z),仿射 x = X/Z^2, y = Y/Z^3。 + * Z=0 表示无穷远点(单位元)。 */ +typedef struct { + paze_bn_t X, Y, Z; +} paze_p384_point_t; + +/* 域/群阶常量访问(大端字节流,48 字节) */ +extern const uint8_t paze_p384_p_be[48]; /* 域素数 p */ +extern const uint8_t paze_p384_n_be[48]; /* 群阶 n */ +extern const uint8_t paze_p384_gx_be[48]; /* 基点 x */ +extern const uint8_t paze_p384_gy_be[48]; /* 基点 y */ + +/* 加载常量为 bignum */ +void paze_p384_load_p(paze_bn_t *p); +void paze_p384_load_n(paze_bn_t *n); +void paze_p384_load_generator(paze_p384_point_t *G); + +/* 点初始化 */ +void paze_p384_set_inf(paze_p384_point_t *P); /* 无穷远点 */ +int paze_p384_is_inf(const paze_p384_point_t *P); /* 1=无穷远 */ +void paze_p384_copy(paze_p384_point_t *dst, const paze_p384_point_t *src); + +/* 仿射点解码:in 为 97 字节 (0x04 || X || Y) 或 49 字节压缩(暂不支持压缩)。 + * 成功返回 PAZE_OK,并校验点在曲线上。 */ +paze_status_t paze_p384_from_affine(paze_p384_point_t *P, const uint8_t *in, size_t len); +/* 仿射编码:输出 97 字节 (0x04 || X || Y)。要求 P 非无穷远。 */ +paze_status_t paze_p384_to_affine(const paze_p384_point_t *P, uint8_t *out, size_t len); + +/* 点加 R = P + Q (Jacobian,非侧信道安全;供 ECDSA verify 等公开路径用)。 */ +paze_status_t paze_p384_add(paze_p384_point_t *R, + const paze_p384_point_t *P, + const paze_p384_point_t *Q); +/* 点倍 R = 2P */ +paze_status_t paze_p384_double(paze_p384_point_t *R, const paze_p384_point_t *P); + +/* 标量乘 R = k * P。k 为大端 48 字节(< n)。常量时间(double-and-add)。 + * 若 P 为 NULL,使用基点 G。 */ +paze_status_t paze_p384_scalar_mult(paze_p384_point_t *R, + const uint8_t k_be[48], + const paze_p384_point_t *P); + +/* 取点的仿射 x 坐标(归约到 mod n 所需范围)供 ECDSA 用 */ +paze_status_t paze_p384_get_x_mod_n(paze_bn_t *x, const paze_p384_point_t *P); + +#ifdef __cplusplus +} +#endif +#endif /* PAZE_P384_H */ diff --git a/include/paze/tls.h b/include/paze/tls.h index e0acbb9..e7eaa08 100644 --- a/include/paze/tls.h +++ b/include/paze/tls.h @@ -49,10 +49,12 @@ extern "C" { /* 命名组 (NamedGroup, key exchange) */ #define PAZE_TLS_GROUP_SECP256R1 0x0017 +#define PAZE_TLS_GROUP_SECP384R1 0x0018 #define PAZE_TLS_GROUP_X25519 0x001D /* 签名算法 (SignatureScheme) */ #define PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256 0x0403 +#define PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 0x0503 #define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256 0x0804 #define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384 0x0805 #define PAZE_TLS_SIG_RSA_PKCS1_SHA256 0x0401 diff --git a/include/paze/x509.h b/include/paze/x509.h index 0b36e86..f1b3c44 100644 --- a/include/paze/x509.h +++ b/include/paze/x509.h @@ -33,7 +33,8 @@ extern "C" { typedef enum { PAZE_X509_PK_UNKNOWN = 0, PAZE_X509_PK_RSA = 1, - PAZE_X509_PK_ECDSA_P256 = 2 + PAZE_X509_PK_ECDSA_P256 = 2, + PAZE_X509_PK_ECDSA_P384 = 3 } paze_x509_pk_kind_t; /* 证书签名算法 */ @@ -43,7 +44,8 @@ typedef enum { PAZE_X509_SIG_SHA256_RSA = 2, PAZE_X509_SIG_SHA384_RSA = 3, PAZE_X509_SIG_SHA512_RSA = 4, - PAZE_X509_SIG_ECDSA_SHA256 = 5 /* P-256 */ + PAZE_X509_SIG_ECDSA_SHA256 = 5, /* P-256 */ + PAZE_X509_SIG_ECDSA_SHA384 = 6 /* P-384 */ } paze_x509_sig_alg_t; #define PAZE_X509_SAN_MAX 8 @@ -65,6 +67,8 @@ typedef struct { paze_x509_pk_kind_t pk_kind; /* 主体公钥类型 */ paze_rsa_pub_t rsa_pub; /* pk_kind==RSA 时有效 */ paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */ + /* pk_kind==ECDSA_P384 时,主体公钥为未压缩点 0x04||X||Y (97 字节) */ + uint8_t ecdsa_p384_pub[97]; /* 签名值(BIT STRING 内容,已去掉 unused-bits 前导 0x00) */ const uint8_t *signature; size_t signature_len; @@ -133,6 +137,7 @@ typedef struct { paze_x509_pk_kind_t kind; paze_rsa_priv_t rsa; /* kind==RSA 时有效 */ uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */ + uint8_t ecdsa_d384[48]; /* kind==ECDSA_P384 时,私钥标量大端 */ } paze_x509_signer_t; /* 构造 SubjectPublicKeyInfo DER。 @@ -141,6 +146,10 @@ paze_status_t paze_x509_build_spki(uint8_t *out, size_t *outlen, paze_x509_pk_kind_t kind, const paze_rsa_pub_t *rsa_pub, const paze_ecdsa_pub_t *ec_pub); +/* 构造 secp384r1 的 SubjectPublicKeyInfo DER: + * ecPublicKey + secp384r1 + pub_affine(97 字节 0x04||X||Y) */ +paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen, + const uint8_t pub_affine[97]); /* 构造仅含 commonName 的 Name DER (UTF8String)。 */ paze_status_t paze_x509_build_dn_cn(uint8_t *out, size_t *outlen, const char *cn); diff --git a/src/crypto/ecdsa.c b/src/crypto/ecdsa.c index 4b5e1c7..c3d2a44 100644 --- a/src/crypto/ecdsa.c +++ b/src/crypto/ecdsa.c @@ -1,12 +1,17 @@ -/* ecdsa.c —— ECDSA 签名/验签 (P-256, RFC 6979 确定性 k) +/* ecdsa.c —— ECDSA 签名/验签 (P-256 / P-384, 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。 + * 依赖:p256/p384 (点运算)、bignum、hmac、hash、asn1。 + * + * 曲线支持:P-256 (secp256r1) 与 P-384 (secp384r1)。 + * 既有 P-256 API (paze_ecdsa_*) 保持字节兼容;新增 paze_ecdsa_p384_* + * 供 P-384 证书/签名用(直接以原始私钥标量/公钥点字节为输入)。 */ #include "paze/ecdsa.h" +#include "paze/p384.h" #include "paze/hmac.h" #include "paze/hash.h" #include "paze/asn1.h" @@ -23,97 +28,179 @@ 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_SHA384: return paze_hash_sha384(); case PAZE_RSA_HASH_SHA512: return paze_hash_sha512(); - default: return NULL; /* SHA-224/384 暂未实现 */ + default: return NULL; /* SHA-224 暂未实现 */ } } -/* bits2int:取 input 左起 qlen_bits 位作为整数。 - * - inlen*8 > qlen: 右移 (inlen*8 - qlen) 位(保留高位) - * - inlen*8 == qlen: 原值 - * - inlen*8 < qlen: 左移补零 */ +/* bits2int (RFC 6979 §2.3.2 / FIPS 186):取 input 左起 qlen_bits 位作为整数。 + * - blen > qlen: 保留左侧高位(右移 blen - qlen 位)。 + * - blen <= qlen: 值即 input(左侧补零 = 右对齐),无需移位。 + * (blen < qlen 时绝不能左移:P-384 配 SHA-256 会得到错误 z。) */ 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 以保证不溢出) */ +/* int2octets:x -> qlen_bits/8 字节大端 */ 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] + * 曲线抽象:p256 / p384 的差异点提取为这组小助手。 + * 点(paze_bn_t X,Y,Z)两种曲线 ABI 相同,用 paze_bn_t[3] 承载。 * ============================================================ */ -static paze_status_t rfc6979_k(uint8_t k_be[32], - const paze_bn_t *d, +typedef enum { ECDSA_CURVE_P256, ECDSA_CURVE_P384 } curve_t; + +static void curve_load_n(curve_t c, paze_bn_t *n) { + if (c == ECDSA_CURVE_P384) paze_p384_load_n(n); + else paze_p256_load_n(n); +} +static int curve_scalar_len(curve_t c) { return (c == ECDSA_CURVE_P384) ? 48 : 32; } +static int curve_pub_len(curve_t c) { return (c == ECDSA_CURVE_P384) ? 97 : 65; } + +/* R = k*G;若 P!=NULL 则 R = k*P。pt 为 3 个 paze_bn_t 的数组。 */ +static paze_status_t curve_point_mult(curve_t c, paze_bn_t pt[3], + const uint8_t *k, const paze_bn_t P[3]) { + if (c == ECDSA_CURVE_P384) { + paze_p384_point_t R, base; + if (P) { paze_bn_copy(&base.X, &P[0]); paze_bn_copy(&base.Y, &P[1]); paze_bn_copy(&base.Z, &P[2]); } + paze_status_t st = paze_p384_scalar_mult(&R, k, P ? &base : NULL); + if (st != PAZE_OK) return st; + paze_bn_copy(&pt[0], &R.X); paze_bn_copy(&pt[1], &R.Y); paze_bn_copy(&pt[2], &R.Z); + return PAZE_OK; + } + paze_p256_point_t R, base; + if (P) { paze_bn_copy(&base.X, &P[0]); paze_bn_copy(&base.Y, &P[1]); paze_bn_copy(&base.Z, &P[2]); } + paze_status_t st = paze_p256_scalar_mult(&R, k, P ? &base : NULL); + if (st != PAZE_OK) return st; + paze_bn_copy(&pt[0], &R.X); paze_bn_copy(&pt[1], &R.Y); paze_bn_copy(&pt[2], &R.Z); + return PAZE_OK; +} + +/* R = P1 + P2 (两个 3-bn 点) */ +static void curve_point_add(curve_t c, paze_bn_t R[3], + const paze_bn_t P1[3], const paze_bn_t P2[3]) { + if (c == ECDSA_CURVE_P384) { + paze_p384_point_t a, b, r; + a.X = P1[0]; a.Y = P1[1]; a.Z = P1[2]; + b.X = P2[0]; b.Y = P2[1]; b.Z = P2[2]; + paze_p384_add(&r, &a, &b); + R[0] = r.X; R[1] = r.Y; R[2] = r.Z; + } else { + paze_p256_point_t a, b, r; + a.X = P1[0]; a.Y = P1[1]; a.Z = P1[2]; + b.X = P2[0]; b.Y = P2[1]; b.Z = P2[2]; + paze_p256_add(&r, &a, &b); + R[0] = r.X; R[1] = r.Y; R[2] = r.Z; + } +} + +static int curve_point_is_inf(curve_t c, const paze_bn_t P[3]) { + (void)c; + return paze_bn_is_zero(&P[2]); +} + +static paze_status_t curve_point_x_mod_n(curve_t c, paze_bn_t *x, const paze_bn_t P[3]) { + if (c == ECDSA_CURVE_P384) { + paze_p384_point_t pt; + pt.X = P[0]; pt.Y = P[1]; pt.Z = P[2]; + return paze_p384_get_x_mod_n(x, &pt); + } + paze_p256_point_t pt; + pt.X = P[0]; pt.Y = P[1]; pt.Z = P[2]; + return paze_p256_get_x_mod_n(x, &pt); +} + +/* 从仿射点字节(0x04||X||Y)加载为 3-bn 点(校验在曲线上)。 */ +static paze_status_t curve_point_from_affine(curve_t c, paze_bn_t P[3], + const uint8_t *in, size_t len) { + (void)len; + if (c == ECDSA_CURVE_P384) { + paze_p384_point_t pt; + paze_status_t st = paze_p384_from_affine(&pt, in, 97); + if (st != PAZE_OK) return st; + P[0] = pt.X; P[1] = pt.Y; P[2] = pt.Z; + return PAZE_OK; + } + paze_p256_point_t pt; + paze_status_t st = paze_p256_from_affine(&pt, in, 65); + if (st != PAZE_OK) return st; + P[0] = pt.X; P[1] = pt.Y; P[2] = pt.Z; + return PAZE_OK; +} + +/* ============================================================ + * RFC 6979 确定性 k 生成 (曲线参数化) + * 输入:私钥 d(大端,curve_scalar_len 字节)、消息摘要 h1、哈希、曲线 + * 输出:k (1 <= k < n),写入 k_be[curve_scalar_len] + * ============================================================ */ + +static paze_status_t rfc6979_k(curve_t c, uint8_t *k_be, + const uint8_t *d_bytes, 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 */ + curve_load_n(c, &n); + int qlen_bits = paze_bn_bit_len(&n); + int slen = curve_scalar_len(c); - /* int2octets(d): d < n,32 字节 */ - uint8_t x_oct[32]; - int2octets(x_oct, 32, d); + /* int2octets(d): 直接拷贝已定长大端标量 */ + uint8_t x_oct[48]; + memcpy(x_oct, d_bytes, (size_t)slen); - /* bits2octets(h1): z1 = bits2int(h1); z2 = z1 mod n; int2octets(z2, 32) */ + /* bits2octets(h1): z1 = bits2int(h1); z2 = z1 mod n; int2octets(z2, slen) */ 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); + uint8_t h1_oct[48]; + int2octets(h1_oct, (size_t)slen, &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 buf[64 + 1 + 48 + 48]; 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) */ + memcpy(buf + hlen + 1, x_oct, (size_t)slen); + memcpy(buf + hlen + 1 + slen, h1_oct, (size_t)slen); + paze_hmac(alg, K, hlen, buf, hlen + 1 + (size_t)slen + (size_t)slen, K); + paze_hmac(alg, K, hlen, V, hlen, 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); + memcpy(buf + hlen + 1, x_oct, (size_t)slen); + memcpy(buf + hlen + 1 + slen, h1_oct, (size_t)slen); + paze_hmac(alg, K, hlen, buf, hlen + 1 + (size_t)slen + (size_t)slen, 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); + int2octets(k_be, (size_t)slen, &k); 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); @@ -122,7 +209,7 @@ static paze_status_t rfc6979_k(uint8_t k_be[32], } /* ============================================================ - * 公钥/私钥管理 + * 公钥/私钥管理 (P-256,既有 API) * ============================================================ */ void paze_ecdsa_priv_set_d(paze_ecdsa_priv_t *k, const uint8_t d_be[32]) { @@ -137,7 +224,6 @@ paze_status_t paze_ecdsa_pub_from_priv(paze_ecdsa_pub_t *pub, const uint8_t d_be 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)); @@ -200,51 +286,50 @@ paze_status_t paze_ecdsa_sig_from_der(paze_bn_t *r, paze_bn_t *s, } /* ============================================================ - * 签名 + * 签名 (core,曲线参数化) * ============================================================ */ -/* 核心签名逻辑(RFC 6979 确定性 k),输出 r/s 大数。 */ -static paze_status_t ecdsa_sign_internal(const paze_ecdsa_priv_t *k, +static paze_status_t ecdsa_sign_internal(curve_t c, + const uint8_t *d_be, paze_rsa_hash_t hash_alg, const uint8_t *mhash, size_t hlen, paze_bn_t *r_out, paze_bn_t *s_out) { - if (!k || !mhash || !r_out || !s_out) return PAZE_ERR_INVALID; + if (!d_be || !mhash || !r_out || !s_out) 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; + int slen = curve_scalar_len(c); paze_bn_t n, d, z; - paze_p256_load_n(&n); - paze_bn_from_bytes(&d, k->d, 32); - /* z = bits2int(mhash) */ + curve_load_n(c, &n); + paze_bn_from_bytes(&d, d_be, (size_t)slen); bits2int(&z, mhash, hlen, paze_bn_bit_len(&n)); paze_bn_t r, s; - uint8_t k_be[32]; + uint8_t k_be[48]; 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); + rc = rfc6979_k(c, k_be, d_be, 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); + paze_bn_t Rpt[3]; + paze_status_t st = curve_point_mult(c, Rpt, k_be, NULL); /* R = k*G */ + if (st != PAZE_OK) return st; + if (curve_point_is_inf(c, Rpt)) continue; + if (curve_point_x_mod_n(c, &r, Rpt) != PAZE_OK) continue; 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_from_bytes(&k_bn, k_be, (size_t)slen); 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 (减少签名可延展性) */ + /* low-s 归一化 */ paze_bn_t half_n; paze_bn_rshift(&half_n, &n, 1); if (paze_bn_cmp(&s, &half_n) > 0) { @@ -265,52 +350,55 @@ paze_status_t paze_ecdsa_sign(const paze_ecdsa_priv_t *k, uint8_t *sig, size_t *siglen) { if (!sig || !siglen) return PAZE_ERR_INVALID; paze_bn_t r, s; - paze_status_t rc = ecdsa_sign_internal(k, hash_alg, mhash, hlen, &r, &s); + paze_status_t rc = ecdsa_sign_internal(ECDSA_CURVE_P256, k->d, hash_alg, + mhash, hlen, &r, &s); if (rc != PAZE_OK) return rc; return paze_ecdsa_sig_to_der(&r, &s, sig, siglen); } /* ============================================================ - * 验签 + * 验签 (core,曲线参数化) * ============================================================ */ -/* 核心验签逻辑:r/s 须在 [1, n-1],R = u1*G + u2*Q,R.x == r。 */ -static paze_status_t ecdsa_verify_internal(const paze_ecdsa_pub_t *pub, +static paze_status_t ecdsa_verify_internal(curve_t c, + const uint8_t *pub_affine, paze_rsa_hash_t hash_alg, const uint8_t *mhash, size_t hlen, const paze_bn_t *r, const paze_bn_t *s) { - if (!pub || !mhash || !r || !s) return PAZE_ERR_INVALID; + if (!pub_affine || !mhash || !r || !s) 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; - paze_p256_load_n(&n); + curve_load_n(c, &n); 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); + int slen = curve_scalar_len(c); + uint8_t u1_be[48], u2_be[48]; + int2octets(u1_be, (size_t)slen, &u1); + int2octets(u2_be, (size_t)slen, &u2); - 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); + paze_bn_t Q[3]; + if (curve_point_from_affine(c, Q, pub_affine, (size_t)curve_pub_len(c)) != PAZE_OK) + return PAZE_ERR_VERIFY; - if (paze_p256_is_inf(&Rpt)) return PAZE_ERR_VERIFY; + paze_bn_t P1[3], P2[3], Rpt[3]; + if (curve_point_mult(c, P1, u1_be, NULL) != PAZE_OK) return PAZE_ERR_VERIFY; + if (curve_point_mult(c, P2, u2_be, Q) != PAZE_OK) return PAZE_ERR_VERIFY; + curve_point_add(c, Rpt, P1, P2); + + if (curve_point_is_inf(c, Rpt)) return PAZE_ERR_VERIFY; paze_bn_t v; - paze_p256_get_x_mod_n(&v, &Rpt); + curve_point_x_mod_n(c, &v, Rpt); return (paze_bn_cmp(&v, r) == 0) ? PAZE_OK : PAZE_ERR_VERIFY; } @@ -321,12 +409,45 @@ paze_status_t paze_ecdsa_verify(const paze_ecdsa_pub_t *pub, if (!sig) return PAZE_ERR_INVALID; paze_bn_t r, s; if (paze_ecdsa_sig_from_der(&r, &s, sig, siglen) != PAZE_OK) return PAZE_ERR_FORMAT; - return ecdsa_verify_internal(pub, hash_alg, mhash, hlen, &r, &s); + /* 编码公钥为仿射字节 */ + uint8_t qa[65]; + if (paze_p256_to_affine(&pub->Q, qa, sizeof(qa)) != PAZE_OK) return PAZE_ERR_VERIFY; + return ecdsa_verify_internal(ECDSA_CURVE_P256, qa, hash_alg, mhash, hlen, &r, &s); } -/* ---- PEM 包装 ---- */ +/* ============================================================ + * P-384 签名/验签 (新增,供 P-384 证书/TLS 用) + * 输入:私钥标量 d_bytes(48 字节大端)、公钥点 pub_affine(97 字节 0x04||X||Y)。 + * 哈希:ecdsa_secp384r1_sha384 用 SHA-384;调用方决定。 + * ============================================================ */ + +paze_status_t paze_ecdsa_p384_sign(const uint8_t d_bytes[48], + paze_rsa_hash_t hash_alg, + const uint8_t *mhash, size_t hlen, + uint8_t *sig, size_t *siglen) { + if (!sig || !siglen || !d_bytes) return PAZE_ERR_INVALID; + paze_bn_t r, s; + paze_status_t rc = ecdsa_sign_internal(ECDSA_CURVE_P384, d_bytes, hash_alg, + mhash, hlen, &r, &s); + if (rc != PAZE_OK) return rc; + return paze_ecdsa_sig_to_der(&r, &s, sig, siglen); +} + +paze_status_t paze_ecdsa_p384_verify(const uint8_t pub_affine[97], + paze_rsa_hash_t hash_alg, + const uint8_t *mhash, size_t hlen, + const uint8_t *sig, size_t siglen) { + if (!sig || !pub_affine) return PAZE_ERR_INVALID; + paze_bn_t r, s; + if (paze_ecdsa_sig_from_der(&r, &s, sig, siglen) != PAZE_OK) return PAZE_ERR_FORMAT; + return ecdsa_verify_internal(ECDSA_CURVE_P384, pub_affine, hash_alg, + mhash, hlen, &r, &s); +} + +/* ============================================================ + * PEM / DER 私钥与公钥解析 (P-256,既有) + * ============================================================ */ -/* 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; @@ -334,38 +455,31 @@ static paze_status_t ecdsa_priv_parse_der(paze_ecdsa_priv_t *k, 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; } @@ -385,28 +499,20 @@ paze_status_t paze_ecdsa_pub_from_pem(paze_ecdsa_pub_t *pub, const char *pem_tex 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 */ + if (st != PAZE_OK || tag != ASN1_SEQUENCE) { free(der); return PAZE_ERR_FORMAT; } - /* 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 (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; @@ -416,3 +522,56 @@ paze_status_t paze_ecdsa_pub_from_pem(paze_ecdsa_pub_t *pub, const char *pem_tex free(der); return st; } + +/* ============================================================ + * P-384 (RFC 5915) 私钥解析 + * ECPrivateKey ::= SEQUENCE { + * version INTEGER(1), + * privateKey OCTET STRING(48), + * parameters [0] OBJECT IDENTIFIER(secp384r1)?, + * publicKey [1] BIT STRING? } + * 校验 named curve 为 secp384r1;成功写出 48 字节标量到 d384。 + * ============================================================ */ +paze_status_t paze_ecdsa_p384_priv_from_der(uint8_t d384[48], + const uint8_t *der, size_t len) { + static const uint8_t OID_SECP384R1[] = {0x2B, 0x81, 0x04, 0x00, 0x22}; + if (!d384 || !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; + + 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; /* version */ + + if (paze_asn1_read_tl(&body, &tag, &b, &blen) != PAZE_OK) return PAZE_ERR_FORMAT; + if (tag != ASN1_OCTETSTRING || blen != 48) return PAZE_ERR_FORMAT; /* 非 P-384 标量 */ + memcpy(d384, b, 48); + + /* 校验参数 [0] 为 secp384r1 OID(可选但通常存在) */ + if (!paze_asn1_at_end(&body)) { + paze_asn1_read_tl(&body, &tag, &b, &blen); + if (tag == ASN1_CTX0) { + if (!paze_asn1_at_end(&body)) { + paze_asn1_read_tl(&body, &tag, &b, &blen); + } + /* b = OID body */ + if (tag == ASN1_OID) { + if (blen != sizeof(OID_SECP384R1) || + memcmp(b, OID_SECP384R1, sizeof(OID_SECP384R1)) != 0) + return PAZE_ERR_NOTSUP; /* 曲线不是 secp384r1 */ + } + } + } + return PAZE_OK; +} + +paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_text) { + if (!d384 || !pem_text) return PAZE_ERR_INVALID; + 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 = paze_ecdsa_p384_priv_from_der(d384, der, dlen); + free(der); + return st; +} diff --git a/src/crypto/p384.c b/src/crypto/p384.c new file mode 100644 index 0000000..d805bee --- /dev/null +++ b/src/crypto/p384.c @@ -0,0 +1,295 @@ +/* p384.c —— NIST P-384 椭圆曲线 (Jacobian 坐标, bignum 域算术) + * + * 曲线: y^2 = x^3 - 3x + b (mod p) + * p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + * n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF + * 581A0DB248B0A77AECEC196ACCC52973 + * b = 0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC + * 656398D8A2ED19D2A85C8EDD3EC2AEF + * + * 点运算用 Jacobian (X:Y:Z),加法 add-2007-bl,倍乘 dbl-2009-l (a=-3)。 + * 域算术复用 bignum 的 modmul/modadd/modsub (mod p)。 + * 与 p256.c 结构完全一致,仅位宽 384 位(字节宽 48)。 + */ +#include "paze/p384.h" +#include "paze/mem.h" +#include "paze/error.h" +#include + +/* ---- 曲线常量(大端 48 字节) ---- */ + +const uint8_t paze_p384_p_be[48] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF +}; +const uint8_t paze_p384_n_be[48] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC7,0x63,0x4D,0x81,0xF4,0x37,0x2D,0xDF, + 0x58,0x1A,0x0D,0xB2,0x48,0xB0,0xA7,0x7A,0xEC,0xEC,0x19,0x6A,0xCC,0xC5,0x29,0x73 +}; +const uint8_t paze_p384_gx_be[48] = { + 0xAA,0x87,0xCA,0x22,0xBE,0x8B,0x05,0x37,0x8E,0xB1,0xC7,0x1E,0xF3,0x20,0xAD,0x74, + 0x6E,0x1D,0x3B,0x62,0x8B,0xA7,0x9B,0x98,0x59,0xF7,0x41,0xE0,0x82,0x54,0x2A,0x38, + 0x55,0x02,0xF2,0x5D,0xBF,0x55,0x29,0x6C,0x3A,0x54,0x5E,0x38,0x72,0x76,0x0A,0xB7 +}; +const uint8_t paze_p384_gy_be[48] = { + 0x36,0x17,0xDE,0x4A,0x96,0x26,0x2C,0x6F,0x5D,0x9E,0x98,0xBF,0x92,0x92,0xDC,0x29, + 0xF8,0xF4,0x1D,0xBD,0x28,0x9A,0x14,0x7C,0xE9,0xDA,0x31,0x13,0xB5,0xF0,0xB8,0xC0, + 0x0A,0x60,0xB1,0xCE,0x1D,0x7E,0x81,0x9D,0x7A,0x43,0x1D,0x7C,0x90,0xEA,0x0E,0x5F +}; +static const uint8_t P384_B_BE[48] = { + 0xB3,0x31,0x2F,0xA7,0xE2,0x3E,0xE7,0xE4,0x98,0x8E,0x05,0x6B,0xE3,0xF8,0x2D,0x19, + 0x18,0x1D,0x9C,0x6E,0xFE,0x81,0x41,0x12,0x03,0x14,0x08,0x8F,0x50,0x13,0x87,0x5A, + 0xC6,0x56,0x39,0x8D,0x8A,0x2E,0xD1,0x9D,0x2A,0x85,0xC8,0xED,0xD3,0xEC,0x2A,0xEF +}; + +void paze_p384_load_p(paze_bn_t *p) { paze_bn_from_bytes(p, paze_p384_p_be, 48); } +void paze_p384_load_n(paze_bn_t *n) { paze_bn_from_bytes(n, paze_p384_n_be, 48); } + +void paze_p384_load_generator(paze_p384_point_t *G) { + paze_bn_from_bytes(&G->X, paze_p384_gx_be, 48); + paze_bn_from_bytes(&G->Y, paze_p384_gy_be, 48); + paze_bn_set_u32(&G->Z, 1); +} + +void paze_p384_set_inf(paze_p384_point_t *P) { + paze_bn_zero(&P->X); + paze_bn_zero(&P->Y); + paze_bn_zero(&P->Z); +} +int paze_p384_is_inf(const paze_p384_point_t *P) { return paze_bn_is_zero(&P->Z); } +void paze_p384_copy(paze_p384_point_t *dst, const paze_p384_point_t *src) { + paze_bn_copy(&dst->X, &src->X); + paze_bn_copy(&dst->Y, &src->Y); + paze_bn_copy(&dst->Z, &src->Z); +} + +/* ---- 域运算辅助 (mod p) ---- */ + +static void fe_mul(paze_bn_t *r, const paze_bn_t *a, const paze_bn_t *b, const paze_bn_t *p) { + paze_bn_modmul(r, a, b, p); +} +static void fe_sqr(paze_bn_t *r, const paze_bn_t *a, const paze_bn_t *p) { + paze_bn_modmul(r, a, a, p); +} +static void fe_add(paze_bn_t *r, const paze_bn_t *a, const paze_bn_t *b, const paze_bn_t *p) { + paze_bn_modadd(r, a, b, p); +} +static void fe_sub(paze_bn_t *r, const paze_bn_t *a, const paze_bn_t *b, const paze_bn_t *p) { + paze_bn_modsub(r, a, b, p); +} + +/* ============================================================ + * 点倍乘 dbl-2009-l (a = -3):公式与 p256 相同,曲线无关。 + * ============================================================ */ + +paze_status_t paze_p384_double(paze_p384_point_t *R, const paze_p384_point_t *P) { + if (paze_p384_is_inf(P)) { paze_p384_set_inf(R); return PAZE_OK; } + paze_bn_t p; + paze_p384_load_p(&p); + + paze_bn_t delta, gamma, beta, alpha, t, X3, Y3, Z3; + fe_sqr(&delta, &P->Z, &p); + fe_sqr(&gamma, &P->Y, &p); + fe_mul(&beta, &P->X, &gamma, &p); + + fe_sub(&t, &P->X, &delta, &p); + paze_bn_t t2; + fe_add(&t2, &P->X, &delta, &p); + fe_mul(&alpha, &t, &t2, &p); + paze_bn_t three; paze_bn_set_u32(&three, 3); + paze_bn_modmul(&alpha, &alpha, &three, &p); + + fe_sqr(&X3, &alpha, &p); + paze_bn_t beta8; + paze_bn_t eight; paze_bn_set_u32(&eight, 8); + paze_bn_modmul(&beta8, &beta, &eight, &p); + fe_sub(&X3, &X3, &beta8, &p); + + paze_bn_t yz; + fe_add(&yz, &P->Y, &P->Z, &p); + fe_sqr(&Z3, &yz, &p); + fe_sub(&Z3, &Z3, &gamma, &p); + fe_sub(&Z3, &Z3, &delta, &p); + + paze_bn_t four; paze_bn_set_u32(&four, 4); + paze_bn_t beta4; + paze_bn_modmul(&beta4, &beta, &four, &p); + paze_bn_t tmp; + fe_sub(&tmp, &beta4, &X3, &p); + fe_mul(&Y3, &alpha, &tmp, &p); + paze_bn_t gamma2; + fe_sqr(&gamma2, &gamma, &p); + paze_bn_t gamma2_8; + paze_bn_modmul(&gamma2_8, &gamma2, &eight, &p); + fe_sub(&Y3, &Y3, &gamma2_8, &p); + + paze_bn_copy(&R->X, &X3); + paze_bn_copy(&R->Y, &Y3); + paze_bn_copy(&R->Z, &Z3); + return PAZE_OK; +} + +/* ============================================================ + * 点加 add-2007-bl (Jacobian + Jacobian, a=-3):公式与 p256 相同。 + * ============================================================ */ + +paze_status_t paze_p384_add(paze_p384_point_t *R, + const paze_p384_point_t *P, + const paze_p384_point_t *Q) { + int infP = paze_p384_is_inf(P); + int infQ = paze_p384_is_inf(Q); + if (infP && infQ) { paze_p384_set_inf(R); return PAZE_OK; } + if (infP) { paze_p384_copy(R, Q); return PAZE_OK; } + if (infQ) { paze_p384_copy(R, P); return PAZE_OK; } + + paze_bn_t p; + paze_p384_load_p(&p); + + paze_bn_t Z1Z1, Z2Z2, U1, U2, S1, S2, H, rr; + fe_sqr(&Z1Z1, &P->Z, &p); + fe_sqr(&Z2Z2, &Q->Z, &p); + fe_mul(&U1, &P->X, &Z2Z2, &p); + fe_mul(&U2, &Q->X, &Z1Z1, &p); + + paze_bn_t t1; + fe_mul(&t1, &Q->Z, &Z2Z2, &p); /* Z2*Z2Z2 */ + fe_mul(&S1, &P->Y, &t1, &p); + fe_mul(&t1, &P->Z, &Z1Z1, &p); /* Z1*Z1Z1 */ + fe_mul(&S2, &Q->Y, &t1, &p); + + fe_sub(&H, &U2, &U1, &p); + fe_sub(&rr, &S2, &S1, &p); + + if (paze_bn_is_zero(&H)) { + if (paze_bn_is_zero(&rr)) { + return paze_p384_double(R, P); + } + paze_p384_set_inf(R); + return PAZE_OK; + } + + paze_bn_t H2, H3; + fe_sqr(&H2, &H, &p); + fe_mul(&H3, &H2, &H, &p); + + paze_bn_t X3; + fe_sqr(&X3, &rr, &p); + fe_sub(&X3, &X3, &H3, &p); + paze_bn_t U1H2; + fe_mul(&U1H2, &U1, &H2, &p); + paze_bn_t U1H2_2; + paze_bn_t two; paze_bn_set_u32(&two, 2); + paze_bn_modmul(&U1H2_2, &U1H2, &two, &p); + fe_sub(&X3, &X3, &U1H2_2, &p); + + paze_bn_t Y3, tmp; + fe_sub(&tmp, &U1H2, &X3, &p); + fe_mul(&Y3, &rr, &tmp, &p); + paze_bn_t S1H3; + fe_mul(&S1H3, &S1, &H3, &p); + fe_sub(&Y3, &Y3, &S1H3, &p); + + paze_bn_t Z3; + fe_mul(&Z3, &P->Z, &Q->Z, &p); + fe_mul(&Z3, &Z3, &H, &p); + + paze_bn_copy(&R->X, &X3); + paze_bn_copy(&R->Y, &Y3); + paze_bn_copy(&R->Z, &Z3); + return PAZE_OK; +} + +/* ============================================================ + * 标量乘 R = k * P (double-and-add-always,常量时间) + * ============================================================ */ + +paze_status_t paze_p384_scalar_mult(paze_p384_point_t *R, + const uint8_t k_be[48], + const paze_p384_point_t *P) { + paze_p384_point_t base, acc, addtmp; + if (P) paze_p384_copy(&base, P); + else paze_p384_load_generator(&base); + paze_p384_set_inf(&acc); + + for (int i = 0; i < 384; i++) { + int byte = i / 8; + int bit = 7 - (i % 8); + paze_p384_double(&acc, &acc); + paze_p384_add(&addtmp, &acc, &base); + uint8_t b = (k_be[byte] >> bit) & 1; + if (b) paze_p384_copy(&acc, &addtmp); + } + paze_p384_copy(R, &acc); + return PAZE_OK; +} + +/* ============================================================ + * 仿射编解码 + * ============================================================ */ + +static void fe_inv(paze_bn_t *r, const paze_bn_t *a, const paze_bn_t *p) { + paze_bn_t e; + paze_bn_set_u32(&e, 2); + paze_bn_sub(&e, p, &e); /* p - 2 */ + paze_bn_modexp(r, a, &e, p); +} + +paze_status_t paze_p384_to_affine(const paze_p384_point_t *P, uint8_t *out, size_t len) { + if (!P || !out) return PAZE_ERR_INVALID; + if (paze_p384_is_inf(P)) return PAZE_ERR_INVALID; + if (len < 97) return PAZE_ERR_SHORT; + paze_bn_t p; + paze_p384_load_p(&p); + + paze_bn_t zinv, zinv2, zinv3, x, y; + fe_inv(&zinv, &P->Z, &p); + fe_sqr(&zinv2, &zinv, &p); + fe_mul(&zinv3, &zinv2, &zinv, &p); + fe_mul(&x, &P->X, &zinv2, &p); + fe_mul(&y, &P->Y, &zinv3, &p); + + out[0] = 0x04; + paze_bn_to_bytes(&x, out + 1, 48); + paze_bn_to_bytes(&y, out + 49, 48); + return PAZE_OK; +} + +paze_status_t paze_p384_from_affine(paze_p384_point_t *P, const uint8_t *in, size_t len) { + if (!P || !in) return PAZE_ERR_INVALID; + if (len < 97) return PAZE_ERR_SHORT; + if (in[0] != 0x04) return PAZE_ERR_NOTSUP; /* 不支持压缩点 */ + paze_bn_t p; + paze_p384_load_p(&p); + + paze_bn_from_bytes(&P->X, in + 1, 48); + paze_bn_from_bytes(&P->Y, in + 49, 48); + paze_bn_set_u32(&P->Z, 1); + + /* 校验点在曲线上:y^2 == x^3 - 3x + b (mod p) */ + paze_bn_t lhs, rhs, x3, three, b, t; + paze_bn_from_bytes(&b, P384_B_BE, 48); + fe_sqr(&lhs, &P->Y, &p); /* y^2 */ + fe_sqr(&x3, &P->X, &p); /* x^2 */ + fe_mul(&rhs, &x3, &P->X, &p); /* x^3 */ + paze_bn_set_u32(&three, 3); + fe_mul(&t, &three, &P->X, &p); /* 3x */ + fe_sub(&rhs, &rhs, &t, &p); /* x^3 - 3x */ + fe_add(&rhs, &rhs, &b, &p); /* x^3 - 3x + b */ + if (paze_bn_cmp(&lhs, &rhs) != 0) return PAZE_ERR_VERIFY; + return PAZE_OK; +} + +paze_status_t paze_p384_get_x_mod_n(paze_bn_t *x, const paze_p384_point_t *P) { + if (paze_p384_is_inf(P)) return PAZE_ERR_INVALID; + paze_bn_t p, n; + paze_p384_load_p(&p); + paze_p384_load_n(&n); + paze_bn_t zinv, zinv2, xa; + fe_inv(&zinv, &P->Z, &p); + fe_sqr(&zinv2, &zinv, &p); + fe_mul(&xa, &P->X, &zinv2, &p); + paze_bn_mod(x, &xa, &n); + return PAZE_OK; +} diff --git a/src/crypto/x509.c b/src/crypto/x509.c index bc17e87..099a9cc 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -20,6 +20,7 @@ * RFC 5280 仅允许 Z 时区。转 Unix 秒用 Howard Hinnant days_from_civil。 */ #include "paze/x509.h" +#include "paze/p384.h" #include "paze/asn1.h" #include "paze/encoding.h" #include "paze/hash.h" @@ -40,7 +41,9 @@ static const uint8_t OID_SHA384_RSA[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0 static const uint8_t OID_SHA512_RSA[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0D}; static const uint8_t OID_EC_PUBKEY[] = {0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01}; static const uint8_t OID_ECDSA_SHA256[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02}; +static const uint8_t OID_ECDSA_SHA384[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03}; static const uint8_t OID_P256[] = {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07}; +static const uint8_t OID_P384[] = {0x2B,0x81,0x04,0x00,0x22}; static const uint8_t OID_SAN[] = {0x55,0x1D,0x11}; static int oid_eq(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen) { @@ -53,6 +56,7 @@ static paze_x509_sig_alg_t sig_alg_from_oid(const uint8_t *o, size_t n) { if (oid_eq(o,n,OID_SHA384_RSA,9)) return PAZE_X509_SIG_SHA384_RSA; if (oid_eq(o,n,OID_SHA512_RSA,9)) return PAZE_X509_SIG_SHA512_RSA; if (oid_eq(o,n,OID_ECDSA_SHA256,8))return PAZE_X509_SIG_ECDSA_SHA256; + if (oid_eq(o,n,OID_ECDSA_SHA384,8))return PAZE_X509_SIG_ECDSA_SHA384; return PAZE_X509_SIG_UNKNOWN; } @@ -174,16 +178,27 @@ static paze_status_t parse_spki(paze_asn1_reader_t *r, paze_x509_cert_t *cert) { return paze_rsa_pub_from_der(&cert->rsa_pub, pk, pklen); /* RSAPublicKey */ } if (oid_eq(oid, olen, OID_EC_PUBKEY, sizeof(OID_EC_PUBKEY))) { - /* 参数须为 prime256v1 OID */ + /* 参数须为 prime256v1 / secp384r1 OID */ if (plen == 0) return PAZE_ERR_FORMAT; paze_asn1_reader_t pr; paze_asn1_r_init(&pr, param, plen); uint8_t t2; const uint8_t *b2; size_t l2; if (paze_asn1_read_tl(&pr, &t2, &b2, &l2) != PAZE_OK) return PAZE_ERR_FORMAT; if (t2 != ASN1_OID) return PAZE_ERR_FORMAT; - if (!oid_eq(b2, l2, OID_P256, sizeof(OID_P256))) return PAZE_ERR_NOTSUP; /* 仅 P-256 */ - if (pklen != 65 || pk[0] != 0x04) return PAZE_ERR_FORMAT; - cert->pk_kind = PAZE_X509_PK_ECDSA_P256; - return paze_p256_from_affine(&cert->ecdsa_pub.Q, pk, 65); + if (oid_eq(b2, l2, OID_P256, sizeof(OID_P256))) { + if (pklen != 65 || pk[0] != 0x04) return PAZE_ERR_FORMAT; + cert->pk_kind = PAZE_X509_PK_ECDSA_P256; + return paze_p256_from_affine(&cert->ecdsa_pub.Q, pk, 65); + } + if (oid_eq(b2, l2, OID_P384, sizeof(OID_P384))) { + if (pklen != 97 || pk[0] != 0x04) return PAZE_ERR_FORMAT; + paze_p384_point_t Q; + paze_status_t st = paze_p384_from_affine(&Q, pk, 97); + if (st != PAZE_OK) return st; /* 校验在曲线上 */ + cert->pk_kind = PAZE_X509_PK_ECDSA_P384; + memcpy(cert->ecdsa_p384_pub, pk, 97); + return PAZE_OK; + } + return PAZE_ERR_NOTSUP; /* 未知 EC 曲线 */ } return PAZE_ERR_NOTSUP; } @@ -399,9 +414,22 @@ paze_status_t paze_x509_verify_signature(const paze_x509_cert_t *cert, break; case PAZE_X509_SIG_ECDSA_SHA256: if (paze_sha256(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR; - if (issuer->pk_kind != PAZE_X509_PK_ECDSA_P256) return PAZE_ERR_VERIFY; - return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA256, - hash, 32, cert->signature, cert->signature_len); + if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256) + return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA256, + hash, 32, cert->signature, cert->signature_len); + if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P384) + return paze_ecdsa_p384_verify(issuer->ecdsa_p384_pub, PAZE_RSA_HASH_SHA256, + hash, 32, cert->signature, cert->signature_len); + return PAZE_ERR_VERIFY; + case PAZE_X509_SIG_ECDSA_SHA384: + if (paze_sha384(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR; + if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P384) + return paze_ecdsa_p384_verify(issuer->ecdsa_p384_pub, PAZE_RSA_HASH_SHA384, + hash, 48, cert->signature, cert->signature_len); + if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256) + return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA384, + hash, 48, cert->signature, cert->signature_len); + return PAZE_ERR_VERIFY; default: return PAZE_ERR_NOTSUP; } @@ -474,6 +502,9 @@ static int pubkey_eq(const paze_x509_cert_t *a, const paze_x509_cert_t *b) { if (paze_p256_to_affine(&b->ecdsa_pub.Q, bb, 65) != PAZE_OK) return 0; return paze_ct_equal(ab, bb, 65) == 0; /* ct_equal:0=相等 */ } + if (a->pk_kind == PAZE_X509_PK_ECDSA_P384) { + return paze_ct_equal(a->ecdsa_p384_pub, b->ecdsa_p384_pub, 97) == 0; + } return 0; } @@ -675,6 +706,38 @@ done: return st; } +/* 构造 secp384r1 的 SubjectPublicKeyInfo DER */ +paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen, + const uint8_t pub_affine[97]) { + if (!out || !outlen || !pub_affine) return PAZE_ERR_INVALID; + paze_asn1_writer_t alg, bs, spki; + paze_asn1_w_init(&alg, NULL, 0); + paze_asn1_w_init(&bs, NULL, 0); + paze_asn1_w_init(&spki, NULL, 0); + paze_status_t st; + st = paze_asn1_w_oid(&alg, OID_EC_PUBKEY, sizeof(OID_EC_PUBKEY)); + if (st == PAZE_OK) st = paze_asn1_w_oid(&alg, OID_P384, sizeof(OID_P384)); + if (st == PAZE_OK) st = paze_asn1_w_byte(&bs, 0x00); + if (st == PAZE_OK) st = paze_asn1_w_data(&bs, pub_affine, 97); + { + paze_asn1_writer_t inner; + paze_asn1_w_init(&inner, NULL, 0); + if (st == PAZE_OK) st = w_seq(&inner, alg.buf, alg.len); + if (st == PAZE_OK) st = paze_asn1_w_tag_len(&inner, ASN1_BITSTRING, bs.len); + if (st == PAZE_OK) st = paze_asn1_w_data(&inner, bs.buf, bs.len); + if (st == PAZE_OK) st = w_seq(&spki, inner.buf, inner.len); + paze_asn1_w_free(&inner); + } + if (st == PAZE_OK) { + if (*outlen < spki.len) { *outlen = spki.len; st = PAZE_ERR_SHORT; } + else { memcpy(out, spki.buf, spki.len); *outlen = spki.len; } + } + paze_asn1_w_free(&alg); + paze_asn1_w_free(&bs); + paze_asn1_w_free(&spki); + return st; +} + paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen, const uint8_t *subject_spki, size_t spki_len, const uint8_t *subject_dn, size_t subj_len, @@ -691,6 +754,8 @@ paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen, sig_oid = OID_SHA256_RSA; sig_oid_len = sizeof(OID_SHA256_RSA); with_null = 1; } else if (issuer_priv->kind == PAZE_X509_PK_ECDSA_P256) { sig_oid = OID_ECDSA_SHA256; sig_oid_len = sizeof(OID_ECDSA_SHA256); with_null = 0; + } else if (issuer_priv->kind == PAZE_X509_PK_ECDSA_P384) { + sig_oid = OID_ECDSA_SHA384; sig_oid_len = sizeof(OID_ECDSA_SHA384); with_null = 0; } else return PAZE_ERR_INVALID; char nb[32], na[32]; @@ -736,21 +801,26 @@ paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen, paze_asn1_w_free(&tbs); if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; } - /* SHA-256(tbs) */ - uint8_t hsh[32]; - paze_sha256(tbsfull.buf, tbsfull.len, hsh); - - /* 签名 */ + /* 签名(曲线决定哈希:P-256→SHA-256, P-384→SHA-384) */ uint8_t sig[4096]; size_t sig_len = sizeof(sig); if (issuer_priv->kind == PAZE_X509_PK_RSA) { + uint8_t hsh[32]; + paze_sha256(tbsfull.buf, tbsfull.len, hsh); sig_len = paze_rsa_modulus_len(&issuer_priv->rsa.n); if (sig_len > sizeof(sig)) { paze_asn1_w_free(&tbsfull); return PAZE_ERR_OVERFLOW; } st = paze_rsa_pkcs1_sign(&issuer_priv->rsa, PAZE_RSA_HASH_SHA256, hsh, 32, sig, sig_len); - } else { + } else if (issuer_priv->kind == PAZE_X509_PK_ECDSA_P256) { + uint8_t hsh[32]; + paze_sha256(tbsfull.buf, tbsfull.len, hsh); paze_ecdsa_priv_t ek; paze_ecdsa_priv_set_d(&ek, issuer_priv->ecdsa_d); st = paze_ecdsa_sign(&ek, PAZE_RSA_HASH_SHA256, hsh, 32, sig, &sig_len); + } else { /* P-384 */ + uint8_t hsh[48]; + paze_sha384(tbsfull.buf, tbsfull.len, hsh); + st = paze_ecdsa_p384_sign(issuer_priv->ecdsa_d384, PAZE_RSA_HASH_SHA384, + hsh, 48, sig, &sig_len); } if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; } @@ -790,6 +860,15 @@ paze_status_t paze_x509_make_self_signed(uint8_t *out, size_t *outlen, paze_ecdsa_pub_t epub; paze_ecdsa_pub_from_priv(&epub, priv->ecdsa_d); st = paze_x509_build_spki(spki, &sl, PAZE_X509_PK_ECDSA_P256, NULL, &epub); + } else if (priv->kind == PAZE_X509_PK_ECDSA_P384) { + /* 公钥 = d384 * G */ + paze_p384_point_t Q; + st = paze_p384_scalar_mult(&Q, priv->ecdsa_d384, NULL); + if (st == PAZE_OK) { + uint8_t qa[97]; + st = paze_p384_to_affine(&Q, qa, sizeof(qa)); + if (st == PAZE_OK) st = paze_x509_build_spki384(spki, &sl, qa); + } } else return PAZE_ERR_INVALID; if (st != PAZE_OK) return st; diff --git a/src/ssl/tls_conn.c b/src/ssl/tls_conn.c index c1ad355..db94ee4 100644 --- a/src/ssl/tls_conn.c +++ b/src/ssl/tls_conn.c @@ -69,7 +69,8 @@ paze_status_t paze_tls_config_enable_early_data(paze_tls_config_t *cfg, int enab paze_status_t paze_tls_config_set_kex_group(paze_tls_config_t *cfg, uint16_t group) { if (!cfg) return PAZE_ERR_INVALID; - if (group != PAZE_TLS_GROUP_X25519 && group != PAZE_TLS_GROUP_SECP256R1) + if (group != PAZE_TLS_GROUP_X25519 && group != PAZE_TLS_GROUP_SECP256R1 && + group != PAZE_TLS_GROUP_SECP384R1) return PAZE_ERR_INVALID; cfg->kex_group = group; return PAZE_OK; @@ -136,6 +137,20 @@ static paze_status_t build_cert_chain_from_pem(const char *cert_pem, return PAZE_OK; } +/* 解析对端证书 DER 为 peer_chain 条目(拷贝 DER 使指针稳定)。 */ +paze_status_t paze_tls_store_peer_cert(paze_x509_cert_t *cert, + const uint8_t *der, size_t len) { + if (!cert || !der) return PAZE_ERR_INVALID; + paze_x509_free(cert); + uint8_t *copy = (uint8_t *)malloc(len ? len : 1); + if (!copy) return PAZE_ERR_NOMEM; + memcpy(copy, der, len); + paze_status_t st = paze_x509_parse_der(cert, copy, len); + if (st != PAZE_OK) { free(copy); return st; } + cert->owned_der = copy; /* 后续 paze_x509_free 释放 */ + return PAZE_OK; +} + paze_status_t paze_tls_config_set_cert_chain(paze_tls_config_t *cfg, const char *cert_pem, const char *privkey_pem) { @@ -146,18 +161,25 @@ paze_status_t paze_tls_config_set_cert_chain(paze_tls_config_t *cfg, free(cfg->cert_der); cfg->cert_der = der; cfg->cert_der_len = dlen; - /* 解析私钥:支持 RSA PKCS#1 和 ECDSA P-256 */ + /* 解析私钥:支持 RSA PKCS#1、ECDSA P-256 与 ECDSA P-384 */ if (strstr(privkey_pem, "RSA PRIVATE KEY")) { cfg->privkey.kind = PAZE_X509_PK_RSA; return paze_rsa_priv_from_pem(&cfg->privkey.rsa, privkey_pem); } if (strstr(privkey_pem, "EC PRIVATE KEY")) { - cfg->privkey.kind = PAZE_X509_PK_ECDSA_P256; + /* 先试 P-256(32 字节),失败再试 P-384(48 字节) */ paze_ecdsa_priv_t ek; paze_status_t ps = paze_ecdsa_priv_from_pem(&ek, privkey_pem); - if (ps != PAZE_OK) return ps; - memcpy(cfg->privkey.ecdsa_d, ek.d, 32); - return PAZE_OK; + if (ps == PAZE_OK) { + cfg->privkey.kind = PAZE_X509_PK_ECDSA_P256; + memcpy(cfg->privkey.ecdsa_d, ek.d, 32); + return PAZE_OK; + } + if (paze_ecdsa_p384_priv_from_pem(cfg->privkey.ecdsa_d384, privkey_pem) == PAZE_OK) { + cfg->privkey.kind = PAZE_X509_PK_ECDSA_P384; + return PAZE_OK; + } + return PAZE_ERR_NOTSUP; /* 不支持的 EC 曲线 / 格式 */ } if (strstr(privkey_pem, "PRIVATE KEY")) { return PAZE_ERR_NOTSUP; /* PKCS#8 暂不支持 */ diff --git a/src/ssl/tls_extensions.c b/src/ssl/tls_extensions.c index 481a41c..15ad5b2 100644 --- a/src/ssl/tls_extensions.c +++ b/src/ssl/tls_extensions.c @@ -72,27 +72,30 @@ int paze_tls_ext_parse_supported_versions(const uint8_t *data, size_t len, * ============================================================ */ size_t paze_tls_ext_write_supported_groups(uint8_t *buf) { uint8_t *p = buf + 4; - p[0] = 0; p[1] = 4; /* list length = 4 (2 groups × 2 bytes) */ + p[0] = 0; p[1] = 6; /* list length = 6 (3 groups × 2 bytes) */ paze_store16_be(p + 2, PAZE_TLS_GROUP_X25519); paze_store16_be(p + 4, PAZE_TLS_GROUP_SECP256R1); - size_t body = 6; + paze_store16_be(p + 6, PAZE_TLS_GROUP_SECP384R1); + size_t body = 8; return put_ext_header(buf, PAZE_TLS_EXT_SUPPORTED_GROUPS, body) + body; } /* 解析 supported_groups: - * group = 若 X25519 在列表中则优先 X25519,否则 P-256,否则 0 */ + * group = 若 X25519 在列表中则优先 X25519,否则 P-256,否则 P-384,否则 0 */ uint16_t paze_tls_ext_parse_supported_groups(const uint8_t *data, size_t len) { if (len < 2) return 0; size_t ll = paze_load16_be(data); if (len != 2 + ll || (ll & 1)) return 0; - int have_x25519 = 0, have_p256 = 0; + int have_x25519 = 0, have_p256 = 0, have_p384 = 0; for (size_t i = 0; i < ll; i += 2) { uint16_t g = paze_load16_be(data + 2 + i); if (g == PAZE_TLS_GROUP_X25519) have_x25519 = 1; if (g == PAZE_TLS_GROUP_SECP256R1) have_p256 = 1; + if (g == PAZE_TLS_GROUP_SECP384R1) have_p384 = 1; } if (have_x25519) return PAZE_TLS_GROUP_X25519; if (have_p256) return PAZE_TLS_GROUP_SECP256R1; + if (have_p384) return PAZE_TLS_GROUP_SECP384R1; return 0; } @@ -107,7 +110,8 @@ size_t paze_tls_ext_write_signature_algorithms(uint8_t *buf) { PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256, PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384, PAZE_TLS_SIG_RSA_PKCS1_SHA256, - PAZE_TLS_SIG_RSA_PKCS1_SHA384 + PAZE_TLS_SIG_RSA_PKCS1_SHA384, + PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 }; int n = sizeof(algs)/sizeof(algs[0]); uint16_t ll = (uint16_t)(n * 2); @@ -145,6 +149,13 @@ size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *k paze_store16_be(p, 65); p += 2; memcpy(p, kex->p256_pub, 65); p += 65; } + if (only_group == PAZE_TLS_GROUP_SECP384R1 || + (only_group == 0 && kex->kind == PAZE_KEX_P384)) { + /* P-384 share(仅 kind==P384 或 HRR 选定组时) */ + paze_store16_be(p, PAZE_TLS_GROUP_SECP384R1); p += 2; + paze_store16_be(p, 97); p += 2; + memcpy(p, kex->p384_pub, 97); p += 97; + } if (p == s + 2) return 0; /* 无 share 可写 */ bodylen = (size_t)(p - s); paze_store16_be(s, (uint16_t)(bodylen - 2)); /* client_shares 长度 */ diff --git a/src/ssl/tls_handshake12.c b/src/ssl/tls_handshake12.c index 2279745..0443edb 100644 --- a/src/ssl/tls_handshake12.c +++ b/src/ssl/tls_handshake12.c @@ -243,7 +243,7 @@ static paze_status_t tls12_client_parse_cert(paze_tls_t *tls, size_t cl = ((size_t)body[p] << 16) | ((size_t)body[p+1] << 8) | body[p+2]; p += 3; if (blen < p + cl) return PAZE_ERR_FORMAT; - paze_status_t st = paze_x509_parse_der(&tls->peer_chain[i], body + p, cl); + paze_status_t st = paze_tls_store_peer_cert(&tls->peer_chain[i], body + p, cl); if (st != PAZE_OK) return PAZE_ERR_FORMAT; tls->peer_chain_len++; i++; p += cl; } @@ -355,6 +355,7 @@ static paze_status_t tls12_client_build_cke(paze_tls_t *tls, const uint8_t *pub; size_t plen; if (tls->neg.group == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; } else if (tls->neg.group == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; } + else if (tls->neg.group == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; } else { paze_tls_set_err(tls, "1.2 group %04x not supported", tls->neg.group); return PAZE_ERR_NOTSUP; } if (1 + plen > 128) return PAZE_ERR_OVERFLOW; out[0] = (uint8_t)plen; /* RFC 5246 §7.4.7:ECDHE point 用 1 字节长度 */ @@ -606,6 +607,7 @@ static paze_status_t tls12_server_build_ske(paze_tls_t *tls, const uint8_t *pub; size_t plen; if (nc == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; } else if (nc == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; } + else if (nc == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; } else return PAZE_ERR_NOTSUP; out[0] = 0x03; @@ -752,7 +754,7 @@ paze_status_t paze_tls12_server_handshake(paze_tls_t *tls) { } tls->neg.group = ex.group ? ex.group : PAZE_TLS_GROUP_SECP256R1; if (tls12_is_ecdhe(cipher)) { - st = paze_tls_kex_generate(&tls->kex, tls->neg.group == PAZE_TLS_GROUP_SECP256R1); + st = paze_tls_kex_generate(&tls->kex, tls->neg.group); if (st != PAZE_OK) return st; } diff --git a/src/ssl/tls_handshake13.c b/src/ssl/tls_handshake13.c index 2976803..d48da46 100644 --- a/src/ssl/tls_handshake13.c +++ b/src/ssl/tls_handshake13.c @@ -9,6 +9,7 @@ * 所有 C++ lambda 已转为静态 C 回调函数。 */ #include "tls_internal.h" +#include "paze/p384.h" #include #include @@ -25,12 +26,16 @@ uint8_t *paze_tls_hs_put_header(uint8_t *msg, uint8_t type, size_t body_len) { } static paze_status_t paze_tls_kex_gen_p256(paze_tls_kex_t *kex); +static paze_status_t paze_tls_kex_gen_p384(paze_tls_kex_t *kex); paze_status_t paze_tls_kex_generate(paze_tls_kex_t *kex, uint16_t group_hint) { paze_memzero(kex, sizeof(*kex)); int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1); + int prefer_p384 = (group_hint == PAZE_TLS_GROUP_SECP384R1); int only_x = (group_hint == PAZE_TLS_GROUP_X25519); - kex->kind = prefer_p256 ? PAZE_KEX_P256 : PAZE_KEX_X25519; + if (prefer_p384) kex->kind = PAZE_KEX_P384; + else if (prefer_p256) kex->kind = PAZE_KEX_P256; + else kex->kind = PAZE_KEX_X25519; if (only_x) { /* 仅生成 X25519 密钥对(其余清零) */ @@ -38,6 +43,9 @@ paze_status_t paze_tls_kex_generate(paze_tls_kex_t *kex, uint16_t group_hint) { if (paze_x25519_public(kex->x25519_pub, kex->x25519_priv) != 0) return PAZE_ERR; return PAZE_OK; } + if (prefer_p384) { + return paze_tls_kex_gen_p384(kex); + } if (prefer_p256) { /* 仅生成 P-256 密钥对 */ return paze_tls_kex_gen_p256(kex); @@ -65,6 +73,22 @@ static paze_status_t paze_tls_kex_gen_p256(paze_tls_kex_t *kex) { return PAZE_OK; } +/* 生成 P-384 密钥对(priv 归一化到 [1, n-1],pub = 0x04||X||Y) */ +static paze_status_t paze_tls_kex_gen_p384(paze_tls_kex_t *kex) { + if (paze_random(kex->p384_priv, 48) != PAZE_OK) return PAZE_ERR_PLATFORM; + paze_bn_t d, n, tmp; + paze_p384_load_n(&n); + paze_bn_from_bytes(&d, kex->p384_priv, 48); + paze_bn_mod(&d, &d, &n); + paze_bn_set_u32(&tmp, 1); + paze_bn_add(&d, &d, &tmp); + paze_bn_to_bytes(&d, kex->p384_priv, 48); + paze_p384_point_t Q; + paze_p384_scalar_mult(&Q, kex->p384_priv, NULL); + if (paze_p384_to_affine(&Q, kex->p384_pub, 97) != PAZE_OK) return PAZE_ERR; + return PAZE_OK; +} + paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group, const uint8_t *peer_pub, size_t peer_pub_len, uint8_t *shared_out, size_t *shared_len) { @@ -85,6 +109,29 @@ paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group, *shared_len = 32; return PAZE_OK; } + if (server_group == PAZE_TLS_GROUP_SECP384R1) { + if (peer_pub_len != 97 || peer_pub[0] != 0x04) return PAZE_ERR_FORMAT; + paze_p384_point_t Q, R; + if (paze_p384_from_affine(&Q, peer_pub, 97) != PAZE_OK) return PAZE_ERR_FORMAT; + if (paze_p384_scalar_mult(&R, mine->p384_priv, &Q) != PAZE_OK) return PAZE_ERR; + /* TLS 1.3 ECDHE 共享密钥 = 共享点的 x 坐标(固定 48 字节大端,SEC1)。 + * 与 OpenSSL 一致;不用 x mod n(P-256 现有实现虽用 mod n,但保留之)。 */ + paze_bn_t zinv, zinv2, x; + /* 计算仿射 x = X / Z^2 (mod p) */ + { + paze_bn_t p; + paze_p384_load_p(&p); + paze_bn_t e; + paze_bn_set_u32(&e, 2); + paze_bn_sub(&e, &p, &e); /* p - 2 */ + paze_bn_modexp(&zinv, &R.Z, &e, &p); + paze_bn_modmul(&zinv2, &zinv, &zinv, &p); + paze_bn_modmul(&x, &R.X, &zinv2, &p); + } + paze_bn_to_bytes(&x, shared_out, 48); + *shared_len = 48; + return PAZE_OK; + } return PAZE_ERR_NOTSUP; } @@ -332,6 +379,15 @@ static paze_status_t sign_cv(paze_tls_t *tls, uint16_t *sig_alg, *sig_alg = PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256; return PAZE_OK; } + if (cfg->privkey.kind == PAZE_X509_PK_ECDSA_P384) { + uint8_t h[48]; paze_sha384(tbs, tbs_len, h); + /* TLS 1.3 的 ECDSA 签名为 DER 编码 (RFC 8446 §4.2.3) */ + paze_status_t st = paze_ecdsa_p384_sign(cfg->privkey.ecdsa_d384, + PAZE_RSA_HASH_SHA384, h, 48, sig, sig_len); + if (st != PAZE_OK) return st; + *sig_alg = PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384; + return PAZE_OK; + } return PAZE_ERR_NOTSUP; } @@ -344,11 +400,12 @@ static paze_status_t verify_cv(paze_tls_t *tls, int is_server_peer, paze_rsa_hash_t rh = PAZE_RSA_HASH_SHA256; switch (sig_alg) { - case PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256: rh = PAZE_RSA_HASH_SHA256; break; - case PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384: rh = PAZE_RSA_HASH_SHA384; break; - case PAZE_TLS_SIG_RSA_PKCS1_SHA256: rh = PAZE_RSA_HASH_SHA256; break; - case PAZE_TLS_SIG_RSA_PKCS1_SHA384: rh = PAZE_RSA_HASH_SHA384; break; - case PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256: rh = PAZE_RSA_HASH_SHA256; break; + case PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256: rh = PAZE_RSA_HASH_SHA256; break; + case PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384: rh = PAZE_RSA_HASH_SHA384; break; + case PAZE_TLS_SIG_RSA_PKCS1_SHA256: rh = PAZE_RSA_HASH_SHA256; break; + case PAZE_TLS_SIG_RSA_PKCS1_SHA384: rh = PAZE_RSA_HASH_SHA384; break; + case PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256: rh = PAZE_RSA_HASH_SHA256; break; + case PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384: rh = PAZE_RSA_HASH_SHA384; break; default: return PAZE_ERR_NOTSUP; } uint8_t h[64]; size_t hl = 0; @@ -369,6 +426,12 @@ static paze_status_t verify_cv(paze_tls_t *tls, int is_server_peer, /* TLS 1.3 的 ECDSA 签名为 DER 编码 (RFC 8446 §4.2.3) */ return paze_ecdsa_verify(&leaf->ecdsa_pub, PAZE_RSA_HASH_SHA256, h, hl, sig, sig_len); } + if (leaf->pk_kind == PAZE_X509_PK_ECDSA_P384) { + if (sig_alg != PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384) + return PAZE_ERR_VERIFY; + return paze_ecdsa_p384_verify(leaf->ecdsa_p384_pub, PAZE_RSA_HASH_SHA384, + h, hl, sig, sig_len); + } return PAZE_ERR_VERIFY; } @@ -653,7 +716,8 @@ static paze_status_t client_handle_hrr(paze_tls_t *tls, paze_tls_set_err(tls, "HRR missing required ext"); return PAZE_ERR_PROTOCOL; } - if (hx.g != PAZE_TLS_GROUP_X25519 && hx.g != PAZE_TLS_GROUP_SECP256R1) { + if (hx.g != PAZE_TLS_GROUP_X25519 && hx.g != PAZE_TLS_GROUP_SECP256R1 && + hx.g != PAZE_TLS_GROUP_SECP384R1) { paze_tls_set_err(tls, "HRR selected unsupported group %d", hx.g); return PAZE_ERR_NOTSUP; } @@ -863,7 +927,7 @@ paze_status_t paze_tls13_client_handshake(paze_tls_t *tls) { size_t cl = ((size_t)body[p] << 16) | ((size_t)body[p+1] << 8) | body[p+2]; p += 3; if (blen < p + cl) return PAZE_ERR_FORMAT; - st = paze_x509_parse_der(&tls->peer_chain[i], body + p, cl); + st = paze_tls_store_peer_cert(&tls->peer_chain[i], body + p, cl); if (st != PAZE_OK) return PAZE_ERR_FORMAT; tls->peer_chain_len++; i++; p += cl; if (tls->neg.version == PAZE_TLS_VERSION_1_3) { @@ -1346,8 +1410,10 @@ paze_status_t paze_tls13_server_handshake(paze_tls_t *tls) { if (have_share) { if (select_group == PAZE_TLS_GROUP_X25519) n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_X25519, tls->kex.x25519_pub, 32); - else + else if (select_group == PAZE_TLS_GROUP_SECP256R1) n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP256R1, tls->kex.p256_pub, 65); + else + n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP384R1, tls->kex.p384_pub, 97); sp += n; } if (tls->psk_mode) { diff --git a/src/ssl/tls_internal.h b/src/ssl/tls_internal.h index 84aabb0..80978fd 100644 --- a/src/ssl/tls_internal.h +++ b/src/ssl/tls_internal.h @@ -75,7 +75,8 @@ typedef struct { typedef enum { PAZE_KEX_NONE = 0, PAZE_KEX_X25519, - PAZE_KEX_P256 + PAZE_KEX_P256, + PAZE_KEX_P384 } paze_tls_kex_kind_t; typedef struct { @@ -86,6 +87,9 @@ typedef struct { /* P-256 */ uint8_t p256_priv[32]; uint8_t p256_pub[65]; /* 0x04||X||Y */ + /* P-384 */ + uint8_t p384_priv[48]; + uint8_t p384_pub[97]; /* 0x04||X||Y */ } paze_tls_kex_t; /* ============================================================ @@ -139,7 +143,8 @@ struct paze_tls_config { /* 0-RTT: 客户端启用(服务端默认接受,1=接受) */ int enable_early; /* 客户端 key_share 限制:0=默认(X25519 优先); - * PAZE_TLS_GROUP_X25519 / PAZE_TLS_GROUP_SECP256R1 = 仅发该组 share(用于测试/限组) */ + * PAZE_TLS_GROUP_X25519 / PAZE_TLS_GROUP_SECP256R1 / PAZE_TLS_GROUP_SECP384R1 + * = 仅发该组 share(用于测试/限组) */ uint16_t kex_group; }; @@ -471,6 +476,12 @@ paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group, const uint8_t *peer_pub, size_t peer_pub_len, uint8_t *shared_out, size_t *shared_len); +/* 解析对端证书 DER 为 peer_chain 条目:拷贝一份 DER 到自有缓冲,使 + * issuer_dn/subject_dn/tbs_der/signature 指针在后续记录处理中保持有效 + * (记录层 app_buf 会被后续记录复用)。cert->owned_der 由 paze_x509_free 释放。 */ +paze_status_t paze_tls_store_peer_cert(paze_x509_cert_t *cert, + const uint8_t *der, size_t len); + /* 1.3 握手 (由 tls_client/tls_server 调用) */ paze_status_t paze_tls13_client_handshake(paze_tls_t *tls); paze_status_t paze_tls13_server_handshake(paze_tls_t *tls);