实现 TLS secp521r1 (P-521) 完整链路: 新增 include/paze/p521.h 与 src/crypto/p521.c(域 p=2^521-1, 标量/点 66/133 字节, 常量时间标量乘); ECDSA 支持 P-521(RFC 6979+SHA-512)与 RFC 5915 私钥解析(paze_ecdsa_p521_*); X.509 支持 secp521r1 证书解析/验签/签发(build_spki521, ecdsa-with-SHA512); TLS 1.3 支持 secp521r1 组(0x0019, key_share/supported_groups/ECDH SEC1 x 坐标/HRR/服务端组选择)与签名算法 ECDSA_SECP521R1_SHA512(0x0603), TLS 1.2 ECDHE 亦支持; pazessl s_client -key_share P-521; 曲线/ECDSA/证书均经 OpenSSL 双向验证, TLS 端点 P-521 密钥交换+证书链/主机名验证通过, 既有自测无回归; STATUS/AGENT/CHANGELOG 更新

这个提交包含在:
JGZYES
2026-08-14 12:34:53 +08:00
父节点 ef86a4c201
当前提交 2504d32d3b
修改 16 个文件,包含 613 行新增39 行删除
+11
查看文件
@@ -67,3 +67,14 @@ STATUS.md 完成度总表 AGENT.md 本文件
- 补全(2026-08-14):`pssh ssh -W host:port`stdio/netcat 转发,目标 TCP 隧道桥接本地 stdio)、`-N`(仅端口转发不执行远程命令,配 `-L/-R/-D`)。 - 补全(2026-08-14):`pssh ssh -W host:port`stdio/netcat 转发,目标 TCP 隧道桥接本地 stdio)、`-N`(仅端口转发不执行远程命令,配 `-L/-R/-D`)。
已知限制:`-J` 接受逗号分隔的多跳语法,但多级级联跳板在同步 I/O 架构下的应用数据阶段交互不稳定,实测多跳握手可完成但握手后易卡;故当前对多跳打印警告并**退化为仅第一跳的稳定单跳**。单跳与 `-W`/`-N` 均已实测验证。 已知限制:`-J` 接受逗号分隔的多跳语法,但多级级联跳板在同步 I/O 架构下的应用数据阶段交互不稳定,实测多跳握手可完成但握手后易卡;故当前对多跳打印警告并**退化为仅第一跳的稳定单跳**。单跳与 `-W`/`-N` 均已实测验证。
### 4. secp521r1TLS P-521)(✅ 已完成 2026-08-14
复用 P-384 全链路套路新增 P-521
- 曲线 `src/crypto/p521.c` + `include/paze/p521.h`(域 p=2^521-1,标量/仿射点 66/133 字节,常量时间标量乘;注意 P-521 非整字节对齐,标量乘须按大端位 `byte=65-t/8, bit=t&7` 遍历)。
- ECDSA:`ecdsa.c/h``paze_ecdsa_p521_sign/verify`(RFC 6979,配 SHA-512)与 RFC 5915 私钥解析。
- X.509:`x509.c/h` 支持 secp521r1 证书解析/验签/签发(`ecdsa_p521_pub[133]``build_spki521`、signer `ecdsa_d521[66]`、ecdsa-with-SHA512)。
- TLS:`PAZE_TLS_GROUP_SECP521R1(0x0019)` / `PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512(0x0603)`,kex 增 `P521`,ECDH 按 SEC1 x 坐标 66 字节,supported_groups/key_share/CertificateVerify/HRR/TLS 1.2 ECDHE 均支持。
- CLI:`s_client -key_share P-521`
- 验证:曲线(n·G=∞、3G=2G+G)、ECDSA 双向、X.509 证书 OpenSSL verify=OK、TLS 端点(密钥交换 hrr=YES+证书链/主机名验证)全部通过;既有自测无回归。
+14
查看文件
@@ -2,6 +2,20 @@
本项目 (PazeSSL / PazeSSH) 的变更记录。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/);版本号按里程碑独立标注(仓库未打 tag,以日期与功能阶段为准)。 本项目 (PazeSSL / PazeSSH) 的变更记录。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/);版本号按里程碑独立标注(仓库未打 tag,以日期与功能阶段为准)。
## [开发主线] — 2026-08-14
### 新增 —— TLS secp521r1 (P-521) 完整链路
- 新增 P-521 椭圆曲线:`src/crypto/p521.c` + `include/paze/p521.h`(域 p = 2^521-1,标量/仿射点 66/133 字节,常量时间标量乘;非整字节对齐,标量乘按大端位遍历)。
- ECDSA 支持 P-521 签名/验签(RFC 6979 确定性 k,配合 SHA-512)与 RFC 5915 私钥解析(`paze_ecdsa_p521_sign/verify``paze_ecdsa_p521_priv_from_pem/der`)。
- X.509 支持 secp521r1 证书解析、验签与签发(`pk_kind==ECDSA_P521``ecdsa_p521_pub[133]``paze_x509_build_spki521`、签发者 `ecdsa_d521[66]`、ecdsa-with-SHA512)。
- TLS 1.3 支持 secp521r1 命名组与签名算法:
-`0x0019``PAZE_TLS_GROUP_SECP521R1`)纳入 key_share / supported_groups / ECDH(按 SEC1 x 坐标,66 字节) / HelloRetryRequest / 服务端组选择。
- 签名算法 `PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512 (0x0603)` 纳入 CertificateVerify 签发与验签。
- TLS 1.2 ECDHE 亦支持 P-521 组。
- CLI`pazessl s_client -key_share P-521`
- 验证:曲线(n·G=∞、3G=2G+G)、ECDSA 双向(OpenSSL 验我的签名 + 我验 OpenSSL 签名)、X.509 P-521 自签名证书 OpenSSL `verify=OK`、TLS 端点 P-521 密钥交换(hrr=YES)+ 证书链/主机名验证全部通过;既有自测无回归。
## [开发主线] — 2026-08-13 ## [开发主线] — 2026-08-13
### 新增 —— TLS secp384r1 (P-384) 完整链路 ### 新增 —— TLS secp384r1 (P-384) 完整链路
+2 -1
查看文件
@@ -16,7 +16,7 @@
- 哈希:SHA-1 / SHA-256 / SHA-512 / MD5 / HMAC / HKDF / PBKDF2 - 哈希:SHA-1 / SHA-256 / SHA-512 / MD5 / HMAC / HKDF / PBKDF2
- 对称:AES-128/192/256、AES-CBC/GCM、ChaCha20、Poly1305、ChaCha20-Poly1305 AEAD - 对称:AES-128/192/256、AES-CBC/GCM、ChaCha20、Poly1305、ChaCha20-Poly1305 AEAD
- 曲线:X25519、Ed25519、**P-256、P-384secp384r1**、ECDSA(大数运算自研:模幂、模逆、Montgomery) - 曲线:X25519、Ed25519、**P-256、P-384secp384r1、P-521secp521r1**、ECDSA(大数运算自研:模幂、模逆、Montgomery)
- 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码 - 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码
- 其他:ASN.1 DER、base64、hex、常量时间准则 - 其他:ASN.1 DER、base64、hex、常量时间准则
@@ -32,6 +32,7 @@
-**0-RTT 数据路径**RFC 8446 §4.2.10/§4.5/§8):early_data 扩展、client_early_traffic_secret 密钥派生、握手前早数据收发、EndOfEarlyDataearly key 加密且计入 transcript);`pazessl s_client/s_server -early` 端到端验证(早数据接收 + early accepted -**0-RTT 数据路径**RFC 8446 §4.2.10/§4.5/§8):early_data 扩展、client_early_traffic_secret 密钥派生、握手前早数据收发、EndOfEarlyDataearly key 加密且计入 transcript);`pazessl s_client/s_server -early` 端到端验证(早数据接收 + early accepted
-**HRRHelloRetryRequest**RFC 8446 §4.1.3/§4.1.4):服务端 key_share 不匹配时发 HRR(随机数=固定魔数)、transcript 合成 MessageHash 重放、客户端 CH2(仅选定组 share)响应、HRR 后放弃 0-RTT;`-key_share` 选项触发,`hrr=YES` 互操作验证通过 -**HRRHelloRetryRequest**RFC 8446 §4.1.3/§4.1.4):服务端 key_share 不匹配时发 HRR(随机数=固定魔数)、transcript 合成 MessageHash 重放、客户端 CH2(仅选定组 share)响应、HRR 后放弃 0-RTT;`-key_share` 选项触发,`hrr=YES` 互操作验证通过
-**secp384r1TLS 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 双向交叉验证 -**secp384r1TLS 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 双向交叉验证
-**secp521r1TLS P-521**:新增 P-521 曲线点运算(`p521.c`,域 p=2^521-1,标量/点 66/133 字节,常量时间标量乘);ECDSA 支持 P-521 签名/验签(RFC 6979,配 SHA-512,`paze_ecdsa_p521_*`);X.509 支持 secp521r1 证书解析/验签/签发(含 ecdsa-with-SHA512,`paze_x509_build_spki521`);TLS 1.3 支持 secp521r1 组与签名算法 ECDSA_SECP521R1_SHA5120x0603),TLS 1.2 ECDHE 亦支持。`s_client -key_share P-521` 端到端验证(HRR + P-521 证书链/主机名验证,应用数据收发);曲线(n·G=∞)、ECDSA 双向、X.509 证书均经 OpenSSL 交叉验证
-**修复**ECDSA `bits2int` 输入短于群阶时错误左移(影响 P-384+SHA-256 验签);TLS 1.3/1.2 对端证书 `issuer_dn/subject_dn` 等指针指向被记录层复用缓冲导致的链验证失败(`paze_tls_store_peer_cert` 拷贝 DER -**修复**ECDSA `bits2int` 输入短于群阶时错误左移(影响 P-384+SHA-256 验签);TLS 1.3/1.2 对端证书 `issuer_dn/subject_dn` 等指针指向被记录层复用缓冲导致的链验证失败(`paze_tls_store_peer_cert` 拷贝 DER
## PazeSSH — SSH-2(✅ 完成) ## PazeSSH — SSH-2(✅ 完成)
+3 -2
查看文件
@@ -72,7 +72,7 @@ static int usage(void) {
"PazeSSL v0.1 (libc-only TLS 1.3 + 1.2)\n" "PazeSSL v0.1 (libc-only TLS 1.3 + 1.2)\n"
"Usage:\n" "Usage:\n"
" pazessl s_client -connect host:port [-CAfile roots.pem] [-servername SNI] [-tls1_2]\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|P-384]\n" " [-sess_in file] [-sess_out file] [-msg text] [-early] [-key_share X25519|P-256|P-384|P-521]\n"
" pazessl s_server -accept port -cert cert.pem -key key.pem [-tls1_2] [-reuse N] [-early]\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 verify -CAfile roots.pem cert.pem\n"
" pazessl genrsa -out key.pem [2048]\n" " pazessl genrsa -out key.pem [2048]\n"
@@ -164,7 +164,8 @@ int main(int argc, char **argv) {
if (strcmp(key_share, "X25519") == 0) g = PAZE_TLS_GROUP_X25519; 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 if (strcmp(key_share, "P-256") == 0) g = PAZE_TLS_GROUP_SECP256R1;
else if (strcmp(key_share, "P-384") == 0) g = PAZE_TLS_GROUP_SECP384R1; 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; } else if (strcmp(key_share, "P-521") == 0) g = PAZE_TLS_GROUP_SECP521R1;
else { fprintf(stderr, "bad -key_share (X25519|P-256|P-384|P-521)\n"); return 1; }
if (paze_tls_config_set_kex_group(cfg, g) != PAZE_OK) return 1; if (paze_tls_config_set_kex_group(cfg, g) != PAZE_OK) return 1;
} }
if (sni) paze_tls_config_set_sni(cfg, sni); if (sni) paze_tls_config_set_sni(cfg, sni);
+15
查看文件
@@ -83,6 +83,21 @@ paze_status_t paze_ecdsa_p384_priv_from_der(uint8_t d384[48],
const uint8_t *der, size_t len); const uint8_t *der, size_t len);
paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_text); paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_text);
/* P-521 (secp521r1) 签名/验签(确定 k, RFC 6979;配 ecdsa_secp521r1_SHA512 用
* PAZE_RSA_HASH_SHA512)。d_bytes 66 字节大端, pub_affine 133 字节 0x04||X||Y。 */
paze_status_t paze_ecdsa_p521_sign(const uint8_t d_bytes[66],
paze_rsa_hash_t hash_alg,
const uint8_t *mhash, size_t hlen,
uint8_t *sig, size_t *siglen);
paze_status_t paze_ecdsa_p521_verify(const uint8_t pub_affine[133],
paze_rsa_hash_t hash_alg,
const uint8_t *mhash, size_t hlen,
const uint8_t *sig, size_t siglen);
/* P-521 (RFC 5915) EC PRIVATE KEY 解析:校验 secp521r1,写 66 字节标量。 */
paze_status_t paze_ecdsa_p521_priv_from_der(uint8_t d521[66],
const uint8_t *der, size_t len);
paze_status_t paze_ecdsa_p521_priv_from_pem(uint8_t d521[66], const char *pem_text);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+54
查看文件
@@ -0,0 +1,54 @@
/* p521.h —— NIST P-521 (secp521r1) 椭圆曲线
*
* 域算术复用 bignum (mod p),点运算用 Jacobian 坐标,公式与 p256/p384 相同。
* 曲线: y^2 = x^3 - 3x + b (mod p), p = 2^521 - 1
* 域元素/标量 66 字节,未压缩仿射点 133 字节 (0x04 || X || Y)。
* 与 p256.h/p384.h 接口保持一致。
*/
#ifndef PAZE_P521_H
#define PAZE_P521_H
#include "paze/paze_types.h"
#include "paze/bignum.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Jacobian 坐标点:(X:Y:Z),Z=0 表示无穷远。 */
typedef struct {
paze_bn_t X, Y, Z;
} paze_p521_point_t;
/* 域/群阶常量(大端 66 字节) */
extern const uint8_t paze_p521_p_be[66];
extern const uint8_t paze_p521_n_be[66];
extern const uint8_t paze_p521_gx_be[66];
extern const uint8_t paze_p521_gy_be[66];
void paze_p521_load_p(paze_bn_t *p);
void paze_p521_load_n(paze_bn_t *n);
void paze_p521_load_generator(paze_p521_point_t *G);
void paze_p521_set_inf(paze_p521_point_t *P);
int paze_p521_is_inf(const paze_p521_point_t *P);
void paze_p521_copy(paze_p521_point_t *dst, const paze_p521_point_t *src);
paze_status_t paze_p521_from_affine(paze_p521_point_t *P, const uint8_t *in, size_t len);
paze_status_t paze_p521_to_affine(const paze_p521_point_t *P, uint8_t *out, size_t len);
paze_status_t paze_p521_add(paze_p521_point_t *R,
const paze_p521_point_t *P,
const paze_p521_point_t *Q);
paze_status_t paze_p521_double(paze_p521_point_t *R, const paze_p521_point_t *P);
paze_status_t paze_p521_scalar_mult(paze_p521_point_t *R,
const uint8_t k_be[66],
const paze_p521_point_t *P);
paze_status_t paze_p521_get_x_mod_n(paze_bn_t *x, const paze_p521_point_t *P);
#ifdef __cplusplus
}
#endif
#endif /* PAZE_P521_H */
+2
查看文件
@@ -50,11 +50,13 @@ extern "C" {
/* 命名组 (NamedGroup, key exchange) */ /* 命名组 (NamedGroup, key exchange) */
#define PAZE_TLS_GROUP_SECP256R1 0x0017 #define PAZE_TLS_GROUP_SECP256R1 0x0017
#define PAZE_TLS_GROUP_SECP384R1 0x0018 #define PAZE_TLS_GROUP_SECP384R1 0x0018
#define PAZE_TLS_GROUP_SECP521R1 0x0019
#define PAZE_TLS_GROUP_X25519 0x001D #define PAZE_TLS_GROUP_X25519 0x001D
/* 签名算法 (SignatureScheme) */ /* 签名算法 (SignatureScheme) */
#define PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256 0x0403 #define PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256 0x0403
#define PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 0x0503 #define PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 0x0503
#define PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512 0x0603
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256 0x0804 #define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256 0x0804
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384 0x0805 #define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384 0x0805
#define PAZE_TLS_SIG_RSA_PKCS1_SHA256 0x0401 #define PAZE_TLS_SIG_RSA_PKCS1_SHA256 0x0401
+11 -2
查看文件
@@ -34,7 +34,8 @@ typedef enum {
PAZE_X509_PK_UNKNOWN = 0, PAZE_X509_PK_UNKNOWN = 0,
PAZE_X509_PK_RSA = 1, 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_ECDSA_P384 = 3,
PAZE_X509_PK_ECDSA_P521 = 4
} paze_x509_pk_kind_t; } paze_x509_pk_kind_t;
/* 证书签名算法 */ /* 证书签名算法 */
@@ -45,7 +46,8 @@ typedef enum {
PAZE_X509_SIG_SHA384_RSA = 3, PAZE_X509_SIG_SHA384_RSA = 3,
PAZE_X509_SIG_SHA512_RSA = 4, 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_ECDSA_SHA384 = 6, /* P-384 */
PAZE_X509_SIG_ECDSA_SHA512 = 7 /* P-521 */
} paze_x509_sig_alg_t; } paze_x509_sig_alg_t;
#define PAZE_X509_SAN_MAX 8 #define PAZE_X509_SAN_MAX 8
@@ -69,6 +71,8 @@ typedef struct {
paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */ paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */
/* pk_kind==ECDSA_P384 时,主体公钥为未压缩点 0x04||X||Y (97 字节) */ /* pk_kind==ECDSA_P384 时,主体公钥为未压缩点 0x04||X||Y (97 字节) */
uint8_t ecdsa_p384_pub[97]; uint8_t ecdsa_p384_pub[97];
/* pk_kind==ECDSA_P521 时,主体公钥为未压缩点 0x04||X||Y (133 字节) */
uint8_t ecdsa_p521_pub[133];
/* 签名值(BIT STRING 内容,已去掉 unused-bits 前导 0x00) */ /* 签名值(BIT STRING 内容,已去掉 unused-bits 前导 0x00) */
const uint8_t *signature; size_t signature_len; const uint8_t *signature; size_t signature_len;
@@ -138,6 +142,7 @@ typedef struct {
paze_rsa_priv_t rsa; /* kind==RSA 时有效 */ paze_rsa_priv_t rsa; /* kind==RSA 时有效 */
uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */ uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */
uint8_t ecdsa_d384[48]; /* kind==ECDSA_P384 时,私钥标量大端 */ uint8_t ecdsa_d384[48]; /* kind==ECDSA_P384 时,私钥标量大端 */
uint8_t ecdsa_d521[66]; /* kind==ECDSA_P521 时,私钥标量大端 */
} paze_x509_signer_t; } paze_x509_signer_t;
/* 构造 SubjectPublicKeyInfo DER。 /* 构造 SubjectPublicKeyInfo DER。
@@ -150,6 +155,10 @@ paze_status_t paze_x509_build_spki(uint8_t *out, size_t *outlen,
* ecPublicKey + secp384r1 + pub_affine(97 字节 0x04||X||Y) */ * ecPublicKey + secp384r1 + pub_affine(97 字节 0x04||X||Y) */
paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen, paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen,
const uint8_t pub_affine[97]); const uint8_t pub_affine[97]);
/* 构造 secp521r1 的 SubjectPublicKeyInfo DER:
* ecPublicKey + secp521r1 + pub_affine(133 字节 0x04||X||Y) */
paze_status_t paze_x509_build_spki521(uint8_t *out, size_t *outlen,
const uint8_t pub_affine[133]);
/* 构造仅含 commonName 的 Name DER (UTF8String)。 */ /* 构造仅含 commonName 的 Name DER (UTF8String)。 */
paze_status_t paze_x509_build_dn_cn(uint8_t *out, size_t *outlen, const char *cn); paze_status_t paze_x509_build_dn_cn(uint8_t *out, size_t *outlen, const char *cn);
+115 -13
查看文件
@@ -12,6 +12,7 @@
*/ */
#include "paze/ecdsa.h" #include "paze/ecdsa.h"
#include "paze/p384.h" #include "paze/p384.h"
#include "paze/p521.h"
#include "paze/hmac.h" #include "paze/hmac.h"
#include "paze/hash.h" #include "paze/hash.h"
#include "paze/asn1.h" #include "paze/asn1.h"
@@ -52,22 +53,35 @@ static void int2octets(uint8_t *out, size_t outlen, const paze_bn_t *x) {
} }
/* ============================================================ /* ============================================================
* 曲线抽象:p256 / p384 的差异点提取为这组小助手。 * 曲线抽象:p256 / p384 / p521 的差异点提取为这组小助手。
* 点(paze_bn_t X,Y,Z)种曲线 ABI 相同,用 paze_bn_t[3] 承载。 * 点(paze_bn_t X,Y,Z)种曲线 ABI 相同,用 paze_bn_t[3] 承载。
* ============================================================ */ * ============================================================ */
typedef enum { ECDSA_CURVE_P256, ECDSA_CURVE_P384 } curve_t; typedef enum { ECDSA_CURVE_P256, ECDSA_CURVE_P384, ECDSA_CURVE_P521 } curve_t;
static void curve_load_n(curve_t c, paze_bn_t *n) { static void curve_load_n(curve_t c, paze_bn_t *n) {
if (c == ECDSA_CURVE_P384) paze_p384_load_n(n); if (c == ECDSA_CURVE_P521) paze_p521_load_n(n);
else if (c == ECDSA_CURVE_P384) paze_p384_load_n(n);
else paze_p256_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_scalar_len(curve_t c) {
static int curve_pub_len(curve_t c) { return (c == ECDSA_CURVE_P384) ? 97 : 65; } return (c == ECDSA_CURVE_P521) ? 66 : ((c == ECDSA_CURVE_P384) ? 48 : 32);
}
static int curve_pub_len(curve_t c) {
return (c == ECDSA_CURVE_P521) ? 133 : ((c == ECDSA_CURVE_P384) ? 97 : 65);
}
/* R = k*G;若 P!=NULL 则 R = k*P。pt 为 3 个 paze_bn_t 的数组。 */ /* 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], 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]) { const uint8_t *k, const paze_bn_t P[3]) {
if (c == ECDSA_CURVE_P521) {
paze_p521_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_p521_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;
}
if (c == ECDSA_CURVE_P384) { if (c == ECDSA_CURVE_P384) {
paze_p384_point_t R, base; 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]); } if (P) { paze_bn_copy(&base.X, &P[0]); paze_bn_copy(&base.Y, &P[1]); paze_bn_copy(&base.Z, &P[2]); }
@@ -87,7 +101,13 @@ static paze_status_t curve_point_mult(curve_t c, paze_bn_t pt[3],
/* R = P1 + P2 (两个 3-bn 点) */ /* R = P1 + P2 (两个 3-bn 点) */
static void curve_point_add(curve_t c, paze_bn_t R[3], 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]) { const paze_bn_t P1[3], const paze_bn_t P2[3]) {
if (c == ECDSA_CURVE_P384) { if (c == ECDSA_CURVE_P521) {
paze_p521_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_p521_add(&r, &a, &b);
R[0] = r.X; R[1] = r.Y; R[2] = r.Z;
} else if (c == ECDSA_CURVE_P384) {
paze_p384_point_t a, b, r; paze_p384_point_t a, b, r;
a.X = P1[0]; a.Y = P1[1]; a.Z = P1[2]; a.X = P1[0]; a.Y = P1[1]; a.Z = P1[2];
b.X = P2[0]; b.Y = P2[1]; b.Z = P2[2]; b.X = P2[0]; b.Y = P2[1]; b.Z = P2[2];
@@ -108,6 +128,11 @@ static int curve_point_is_inf(curve_t c, const paze_bn_t P[3]) {
} }
static paze_status_t curve_point_x_mod_n(curve_t c, paze_bn_t *x, const paze_bn_t P[3]) { 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_P521) {
paze_p521_point_t pt;
pt.X = P[0]; pt.Y = P[1]; pt.Z = P[2];
return paze_p521_get_x_mod_n(x, &pt);
}
if (c == ECDSA_CURVE_P384) { if (c == ECDSA_CURVE_P384) {
paze_p384_point_t pt; paze_p384_point_t pt;
pt.X = P[0]; pt.Y = P[1]; pt.Z = P[2]; pt.X = P[0]; pt.Y = P[1]; pt.Z = P[2];
@@ -122,6 +147,13 @@ static paze_status_t curve_point_x_mod_n(curve_t c, paze_bn_t *x, const paze_bn_
static paze_status_t curve_point_from_affine(curve_t c, paze_bn_t P[3], static paze_status_t curve_point_from_affine(curve_t c, paze_bn_t P[3],
const uint8_t *in, size_t len) { const uint8_t *in, size_t len) {
(void)len; (void)len;
if (c == ECDSA_CURVE_P521) {
paze_p521_point_t pt;
paze_status_t st = paze_p521_from_affine(&pt, in, 133);
if (st != PAZE_OK) return st;
P[0] = pt.X; P[1] = pt.Y; P[2] = pt.Z;
return PAZE_OK;
}
if (c == ECDSA_CURVE_P384) { if (c == ECDSA_CURVE_P384) {
paze_p384_point_t pt; paze_p384_point_t pt;
paze_status_t st = paze_p384_from_affine(&pt, in, 97); paze_status_t st = paze_p384_from_affine(&pt, in, 97);
@@ -155,14 +187,14 @@ static paze_status_t rfc6979_k(curve_t c, uint8_t *k_be,
int slen = curve_scalar_len(c); int slen = curve_scalar_len(c);
/* int2octets(d): 直接拷贝已定长大端标量 */ /* int2octets(d): 直接拷贝已定长大端标量 */
uint8_t x_oct[48]; uint8_t x_oct[66];
memcpy(x_oct, d_bytes, (size_t)slen); memcpy(x_oct, d_bytes, (size_t)slen);
/* bits2octets(h1): z1 = bits2int(h1); z2 = z1 mod n; int2octets(z2, slen) */ /* bits2octets(h1): z1 = bits2int(h1); z2 = z1 mod n; int2octets(z2, slen) */
paze_bn_t z1, z2; paze_bn_t z1, z2;
bits2int(&z1, h1, h1len, qlen_bits); bits2int(&z1, h1, h1len, qlen_bits);
paze_bn_mod(&z2, &z1, &n); paze_bn_mod(&z2, &z1, &n);
uint8_t h1_oct[48]; uint8_t h1_oct[66];
int2octets(h1_oct, (size_t)slen, &z2); int2octets(h1_oct, (size_t)slen, &z2);
/* V = 0x01 * hlen, K = 0x00 * hlen */ /* V = 0x01 * hlen, K = 0x00 * hlen */
@@ -170,8 +202,10 @@ static paze_status_t rfc6979_k(curve_t c, uint8_t *k_be,
memset(V, 0x01, hlen); memset(V, 0x01, hlen);
memset(K, 0x00, hlen); memset(K, 0x00, hlen);
uint8_t buf[64 + 1 + 48 + 48]; /* buf 需容纳 hlen+1+slen+slen(最大 SHA-512=64 + 1 + 66 + 66 = 197);
uint8_t T[64]; * T 需容纳 |qlen/8| 的连续 HMAC 块(P-521 用 SHA-512 时 2 轮 = 128 字节)。 */
uint8_t buf[197];
uint8_t T[132];
/* K = HMAC_K(V || 0x00 || x || h1_oct) */ /* K = HMAC_K(V || 0x00 || x || h1_oct) */
memcpy(buf, V, hlen); buf[hlen] = 0x00; memcpy(buf, V, hlen); buf[hlen] = 0x00;
@@ -305,7 +339,7 @@ static paze_status_t ecdsa_sign_internal(curve_t c,
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n)); bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
paze_bn_t r, s; paze_bn_t r, s;
uint8_t k_be[48]; uint8_t k_be[66];
paze_status_t rc; paze_status_t rc;
int got = 0; int got = 0;
@@ -383,7 +417,7 @@ static paze_status_t ecdsa_verify_internal(curve_t c,
paze_bn_modmul(&u2, r, &w, &n); paze_bn_modmul(&u2, r, &w, &n);
int slen = curve_scalar_len(c); int slen = curve_scalar_len(c);
uint8_t u1_be[48], u2_be[48]; uint8_t u1_be[66], u2_be[66];
int2octets(u1_be, (size_t)slen, &u1); int2octets(u1_be, (size_t)slen, &u1);
int2octets(u2_be, (size_t)slen, &u2); int2octets(u2_be, (size_t)slen, &u2);
@@ -444,6 +478,29 @@ paze_status_t paze_ecdsa_p384_verify(const uint8_t pub_affine[97],
mhash, hlen, &r, &s); mhash, hlen, &r, &s);
} }
paze_status_t paze_ecdsa_p521_sign(const uint8_t d_bytes[66],
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_P521, 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_p521_verify(const uint8_t pub_affine[133],
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_P521, pub_affine, hash_alg,
mhash, hlen, &r, &s);
}
/* ============================================================ /* ============================================================
* PEM / DER 私钥与公钥解析 (P-256,既有) * PEM / DER 私钥与公钥解析 (P-256,既有)
* ============================================================ */ * ============================================================ */
@@ -575,3 +632,48 @@ paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_te
free(der); free(der);
return st; return st;
} }
/* ============================================================
* P-521 (RFC 5915) 私钥解析:校验 secp521r1,写 66 字节标量。
* ============================================================ */
paze_status_t paze_ecdsa_p521_priv_from_der(uint8_t d521[66],
const uint8_t *der, size_t len) {
static const uint8_t OID_SECP521R1[] = {0x2B, 0x81, 0x04, 0x00, 0x23};
if (!d521 || !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 != 66) return PAZE_ERR_FORMAT; /* 非 P-521 标量 */
memcpy(d521, b, 66);
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);
}
if (tag == ASN1_OID) {
if (blen != sizeof(OID_SECP521R1) ||
memcmp(b, OID_SECP521R1, sizeof(OID_SECP521R1)) != 0)
return PAZE_ERR_NOTSUP;
}
}
}
return PAZE_OK;
}
paze_status_t paze_ecdsa_p521_priv_from_pem(uint8_t d521[66], const char *pem_text) {
if (!d521 || !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_p521_priv_from_der(d521, der, dlen);
free(der);
return st;
}
+211
查看文件
@@ -0,0 +1,211 @@
/* p521.c —— NIST P-521 椭圆曲线 (Jacobian 坐标, bignum 域算术)
*
* 线: y^2 = x^3 - 3x + b (mod p), p = 2^521 - 1
* / 66 ( 1 ),仿 133
* (dbl-2009-l / add-2007-bl, a=-3) p256.c/p384.c
* : OpenSSL ecparam -name secp521r1 -param_enc explicit
*/
#include "paze/p521.h"
#include "paze/mem.h"
#include "paze/error.h"
#include <string.h>
/* ---- 曲线常量(大端 66 字节; P 最高字节 0x01,低位部分) ---- */
const uint8_t paze_p521_p_be[66] = {
0x01,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,
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,0xFF,
0xFF,0xFF
};
const uint8_t paze_p521_n_be[66] = {
0x01,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,
0xff,0xfa,0x51,0x86,0x87,0x83,0xbf,0x2f,0x96,0x6b,0x7f,0xcc,0x01,0x48,0xf7,0x09,
0xa5,0xd0,0x3b,0xb5,0xc9,0xb8,0x89,0x9c,0x47,0xae,0xbb,0x6f,0xb7,0x1e,0x91,0x38,
0x64,0x09
};
const uint8_t paze_p521_gx_be[66] = {
0x00,0xC6,0x85,0x8E,0x06,0xB7,0x04,0x04,0xE9,0xCD,0x9E,0x3E,0xCB,0x66,0x23,0x95,
0xB4,0x42,0x9C,0x64,0x81,0x39,0x05,0x3F,0xB5,0x21,0xF8,0x28,0xAF,0x60,0x6B,0x4D,
0x3D,0xBA,0xA1,0x4B,0x5E,0x77,0xEF,0xE7,0x59,0x28,0xFE,0x1D,0xC1,0x27,0xA2,0xFF,
0xA8,0xDE,0x33,0x48,0xB3,0xC1,0x85,0x6A,0x42,0x9B,0xF9,0x7E,0x7E,0x31,0xC2,0xE5,
0xBD,0x66
};
const uint8_t paze_p521_gy_be[66] = {
0x01,0x18,0x39,0x29,0x6A,0x78,0x9A,0x3B,0xC0,0x04,0x5C,0x8A,0x5F,0xB4,0x2C,0x7D,
0x1B,0xD9,0x98,0xF5,0x44,0x49,0x57,0x9B,0x44,0x68,0x17,0xAF,0xBD,0x17,0x27,0x3E,
0x66,0x2C,0x97,0xEE,0x72,0x99,0x5E,0xF4,0x26,0x40,0xC5,0x50,0xB9,0x01,0x3F,0xAD,
0x07,0x61,0x35,0x3C,0x70,0x86,0xA2,0x72,0xC2,0x40,0x88,0xBE,0x94,0x76,0x9F,0xD1,
0x66,0x50
};
/* b(补前导 0x00 成 66 字节) */
static const uint8_t P521_B_BE[66] = {
0x00,0x51,0x95,0x3E,0xB9,0x61,0x8E,0x1C,0x9A,0x1F,0x92,0x9A,0x21,0xA0,0xB6,0x85,
0x40,0xEE,0xA2,0xDA,0x72,0x5B,0x99,0xB3,0x15,0xF3,0xB8,0xB4,0x89,0x91,0x8E,0xF1,
0x09,0xE1,0x56,0x19,0x39,0x51,0xEC,0x7E,0x93,0x7B,0x16,0x52,0xC0,0xBD,0x3B,0xB1,
0xBF,0x07,0x35,0x73,0xDF,0x88,0x3D,0x2C,0x34,0xF1,0xEF,0x45,0x1F,0xD4,0x6B,0x50,
0x3F,0x00
};
void paze_p521_load_p(paze_bn_t *p) { paze_bn_from_bytes(p, paze_p521_p_be, 66); }
void paze_p521_load_n(paze_bn_t *n) { paze_bn_from_bytes(n, paze_p521_n_be, 66); }
void paze_p521_load_generator(paze_p521_point_t *G) {
paze_bn_from_bytes(&G->X, paze_p521_gx_be, 66);
paze_bn_from_bytes(&G->Y, paze_p521_gy_be, 66);
paze_bn_set_u32(&G->Z, 1);
}
void paze_p521_set_inf(paze_p521_point_t *P) {
paze_bn_zero(&P->X);
paze_bn_zero(&P->Y);
paze_bn_zero(&P->Z);
}
int paze_p521_is_inf(const paze_p521_point_t *P) { return paze_bn_is_zero(&P->Z); }
void paze_p521_copy(paze_p521_point_t *dst, const paze_p521_point_t *src) {
paze_bn_copy(&dst->X, &src->X);
paze_bn_copy(&dst->Y, &src->Y);
paze_bn_copy(&dst->Z, &src->Z);
}
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); }
paze_status_t paze_p521_double(paze_p521_point_t *R, const paze_p521_point_t *P) {
if (paze_p521_is_inf(P)) { paze_p521_set_inf(R); return PAZE_OK; }
paze_bn_t p; paze_p521_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;
}
paze_status_t paze_p521_add(paze_p521_point_t *R,
const paze_p521_point_t *P,
const paze_p521_point_t *Q) {
if (paze_p521_is_inf(P) && paze_p521_is_inf(Q)) { paze_p521_set_inf(R); return PAZE_OK; }
if (paze_p521_is_inf(P)) { paze_p521_copy(R, Q); return PAZE_OK; }
if (paze_p521_is_inf(Q)) { paze_p521_copy(R, P); return PAZE_OK; }
paze_bn_t p; paze_p521_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); fe_mul(&S1, &P->Y, &t1, &p);
fe_mul(&t1, &P->Z, &Z1Z1, &p); 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_p521_double(R, P);
paze_p521_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, tmp2; fe_sub(&tmp2, &U1H2, &X3, &p);
fe_mul(&Y3, &rr, &tmp2, &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。P-521 阶 n 为 521 位;k_be 为大端 66 字节。
* t(0=) = 65 - (t/8), = t&7
* (t=520)(t=0) double-and-add */
paze_status_t paze_p521_scalar_mult(paze_p521_point_t *R,
const uint8_t k_be[66],
const paze_p521_point_t *P) {
paze_p521_point_t base, acc, addtmp;
if (P) paze_p521_copy(&base, P);
else paze_p521_load_generator(&base);
paze_p521_set_inf(&acc);
for (int t = 520; t >= 0; t--) {
int byte = 65 - (t / 8);
int bit = t & 7;
paze_p521_double(&acc, &acc);
paze_p521_add(&addtmp, &acc, &base);
uint8_t b = (k_be[byte] >> bit) & 1;
if (b) paze_p521_copy(&acc, &addtmp);
}
paze_p521_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_p521_to_affine(const paze_p521_point_t *P, uint8_t *out, size_t len) {
if (!P || !out) return PAZE_ERR_INVALID;
if (paze_p521_is_inf(P)) return PAZE_ERR_INVALID;
if (len < 133) return PAZE_ERR_SHORT;
paze_bn_t p; paze_p521_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, 66);
paze_bn_to_bytes(&y, out + 67, 66);
return PAZE_OK;
}
paze_status_t paze_p521_from_affine(paze_p521_point_t *P, const uint8_t *in, size_t len) {
if (!P || !in) return PAZE_ERR_INVALID;
if (len < 133) return PAZE_ERR_SHORT;
if (in[0] != 0x04) return PAZE_ERR_NOTSUP;
paze_bn_t p; paze_p521_load_p(&p);
paze_bn_from_bytes(&P->X, in + 1, 66);
paze_bn_from_bytes(&P->Y, in + 67, 66);
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, P521_B_BE, 66);
fe_sqr(&lhs, &P->Y, &p); /* y^2 */
fe_sqr(&x3, &P->X, &p); fe_mul(&rhs, &x3, &P->X, &p); /* x^3 */
paze_bn_set_u32(&three, 3);
fe_mul(&t, &three, &P->X, &p); fe_sub(&rhs, &rhs, &t, &p); /* x^3-3x */
fe_add(&rhs, &rhs, &b, &p);
if (paze_bn_cmp(&lhs, &rhs) != 0) return PAZE_ERR_VERIFY;
return PAZE_OK;
}
paze_status_t paze_p521_get_x_mod_n(paze_bn_t *x, const paze_p521_point_t *P) {
if (paze_p521_is_inf(P)) return PAZE_ERR_INVALID;
paze_bn_t p, n; paze_p521_load_p(&p); paze_p521_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;
}
+83 -1
查看文件
@@ -21,6 +21,7 @@
*/ */
#include "paze/x509.h" #include "paze/x509.h"
#include "paze/p384.h" #include "paze/p384.h"
#include "paze/p521.h"
#include "paze/asn1.h" #include "paze/asn1.h"
#include "paze/encoding.h" #include "paze/encoding.h"
#include "paze/hash.h" #include "paze/hash.h"
@@ -42,8 +43,10 @@ static const uint8_t OID_SHA512_RSA[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0
static const uint8_t OID_EC_PUBKEY[] = {0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01}; 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_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_ECDSA_SHA384[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03};
static const uint8_t OID_ECDSA_SHA512[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x04};
static const uint8_t OID_P256[] = {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07}; 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_P384[] = {0x2B,0x81,0x04,0x00,0x22};
static const uint8_t OID_P521[] = {0x2B,0x81,0x04,0x00,0x23};
static const uint8_t OID_SAN[] = {0x55,0x1D,0x11}; 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) { static int oid_eq(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen) {
@@ -57,6 +60,7 @@ static paze_x509_sig_alg_t sig_alg_from_oid(const uint8_t *o, size_t n) {
if (oid_eq(o,n,OID_SHA512_RSA,9)) return PAZE_X509_SIG_SHA512_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_SHA256,8))return PAZE_X509_SIG_ECDSA_SHA256;
if (oid_eq(o,n,OID_ECDSA_SHA384,8))return PAZE_X509_SIG_ECDSA_SHA384; if (oid_eq(o,n,OID_ECDSA_SHA384,8))return PAZE_X509_SIG_ECDSA_SHA384;
if (oid_eq(o,n,OID_ECDSA_SHA512,8))return PAZE_X509_SIG_ECDSA_SHA512;
return PAZE_X509_SIG_UNKNOWN; return PAZE_X509_SIG_UNKNOWN;
} }
@@ -198,6 +202,15 @@ static paze_status_t parse_spki(paze_asn1_reader_t *r, paze_x509_cert_t *cert) {
memcpy(cert->ecdsa_p384_pub, pk, 97); memcpy(cert->ecdsa_p384_pub, pk, 97);
return PAZE_OK; return PAZE_OK;
} }
if (oid_eq(b2, l2, OID_P521, sizeof(OID_P521))) {
if (pklen != 133 || pk[0] != 0x04) return PAZE_ERR_FORMAT;
paze_p521_point_t Q;
paze_status_t st = paze_p521_from_affine(&Q, pk, 133);
if (st != PAZE_OK) return st;
cert->pk_kind = PAZE_X509_PK_ECDSA_P521;
memcpy(cert->ecdsa_p521_pub, pk, 133);
return PAZE_OK;
}
return PAZE_ERR_NOTSUP; /* 未知 EC 曲线 */ return PAZE_ERR_NOTSUP; /* 未知 EC 曲线 */
} }
return PAZE_ERR_NOTSUP; return PAZE_ERR_NOTSUP;
@@ -420,6 +433,9 @@ paze_status_t paze_x509_verify_signature(const paze_x509_cert_t *cert,
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P384) if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P384)
return paze_ecdsa_p384_verify(issuer->ecdsa_p384_pub, PAZE_RSA_HASH_SHA256, return paze_ecdsa_p384_verify(issuer->ecdsa_p384_pub, PAZE_RSA_HASH_SHA256,
hash, 32, cert->signature, cert->signature_len); hash, 32, cert->signature, cert->signature_len);
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P521)
return paze_ecdsa_p521_verify(issuer->ecdsa_p521_pub, PAZE_RSA_HASH_SHA256,
hash, 32, cert->signature, cert->signature_len);
return PAZE_ERR_VERIFY; return PAZE_ERR_VERIFY;
case PAZE_X509_SIG_ECDSA_SHA384: case PAZE_X509_SIG_ECDSA_SHA384:
if (paze_sha384(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR; if (paze_sha384(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR;
@@ -429,6 +445,21 @@ paze_status_t paze_x509_verify_signature(const paze_x509_cert_t *cert,
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256) if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256)
return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA384, return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA384,
hash, 48, cert->signature, cert->signature_len); hash, 48, cert->signature, cert->signature_len);
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P521)
return paze_ecdsa_p521_verify(issuer->ecdsa_p521_pub, PAZE_RSA_HASH_SHA384,
hash, 48, cert->signature, cert->signature_len);
return PAZE_ERR_VERIFY;
case PAZE_X509_SIG_ECDSA_SHA512:
if (paze_sha512(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR;
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P521)
return paze_ecdsa_p521_verify(issuer->ecdsa_p521_pub, PAZE_RSA_HASH_SHA512,
hash, 64, 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_SHA512,
hash, 64, cert->signature, cert->signature_len);
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256)
return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA512,
hash, 64, cert->signature, cert->signature_len);
return PAZE_ERR_VERIFY; return PAZE_ERR_VERIFY;
default: default:
return PAZE_ERR_NOTSUP; return PAZE_ERR_NOTSUP;
@@ -505,6 +536,9 @@ static int pubkey_eq(const paze_x509_cert_t *a, const paze_x509_cert_t *b) {
if (a->pk_kind == PAZE_X509_PK_ECDSA_P384) { if (a->pk_kind == PAZE_X509_PK_ECDSA_P384) {
return paze_ct_equal(a->ecdsa_p384_pub, b->ecdsa_p384_pub, 97) == 0; return paze_ct_equal(a->ecdsa_p384_pub, b->ecdsa_p384_pub, 97) == 0;
} }
if (a->pk_kind == PAZE_X509_PK_ECDSA_P521) {
return paze_ct_equal(a->ecdsa_p521_pub, b->ecdsa_p521_pub, 133) == 0;
}
return 0; return 0;
} }
@@ -738,6 +772,38 @@ paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen,
return st; return st;
} }
/* 构造 secp521r1 的 SubjectPublicKeyInfo DER */
paze_status_t paze_x509_build_spki521(uint8_t *out, size_t *outlen,
const uint8_t pub_affine[133]) {
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_P521, sizeof(OID_P521));
if (st == PAZE_OK) st = paze_asn1_w_byte(&bs, 0x00);
if (st == PAZE_OK) st = paze_asn1_w_data(&bs, pub_affine, 133);
{
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, 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_spki, size_t spki_len,
const uint8_t *subject_dn, size_t subj_len, const uint8_t *subject_dn, size_t subj_len,
@@ -756,6 +822,8 @@ paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen,
sig_oid = OID_ECDSA_SHA256; sig_oid_len = sizeof(OID_ECDSA_SHA256); with_null = 0; 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) { } 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; sig_oid = OID_ECDSA_SHA384; sig_oid_len = sizeof(OID_ECDSA_SHA384); with_null = 0;
} else if (issuer_priv->kind == PAZE_X509_PK_ECDSA_P521) {
sig_oid = OID_ECDSA_SHA512; sig_oid_len = sizeof(OID_ECDSA_SHA512); with_null = 0;
} else return PAZE_ERR_INVALID; } else return PAZE_ERR_INVALID;
char nb[32], na[32]; char nb[32], na[32];
@@ -816,11 +884,16 @@ paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen,
paze_ecdsa_priv_t ek; paze_ecdsa_priv_t ek;
paze_ecdsa_priv_set_d(&ek, issuer_priv->ecdsa_d); paze_ecdsa_priv_set_d(&ek, issuer_priv->ecdsa_d);
st = paze_ecdsa_sign(&ek, PAZE_RSA_HASH_SHA256, hsh, 32, sig, &sig_len); st = paze_ecdsa_sign(&ek, PAZE_RSA_HASH_SHA256, hsh, 32, sig, &sig_len);
} else { /* P-384 */ } else if (issuer_priv->kind == PAZE_X509_PK_ECDSA_P384) {
uint8_t hsh[48]; uint8_t hsh[48];
paze_sha384(tbsfull.buf, tbsfull.len, hsh); paze_sha384(tbsfull.buf, tbsfull.len, hsh);
st = paze_ecdsa_p384_sign(issuer_priv->ecdsa_d384, PAZE_RSA_HASH_SHA384, st = paze_ecdsa_p384_sign(issuer_priv->ecdsa_d384, PAZE_RSA_HASH_SHA384,
hsh, 48, sig, &sig_len); hsh, 48, sig, &sig_len);
} else { /* P-521 */
uint8_t hsh[64];
paze_sha512(tbsfull.buf, tbsfull.len, hsh);
st = paze_ecdsa_p521_sign(issuer_priv->ecdsa_d521, PAZE_RSA_HASH_SHA512,
hsh, 64, sig, &sig_len);
} }
if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; } if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; }
@@ -869,6 +942,15 @@ paze_status_t paze_x509_make_self_signed(uint8_t *out, size_t *outlen,
st = paze_p384_to_affine(&Q, qa, sizeof(qa)); st = paze_p384_to_affine(&Q, qa, sizeof(qa));
if (st == PAZE_OK) st = paze_x509_build_spki384(spki, &sl, qa); if (st == PAZE_OK) st = paze_x509_build_spki384(spki, &sl, qa);
} }
} else if (priv->kind == PAZE_X509_PK_ECDSA_P521) {
/* 公钥 = d521 * G */
paze_p521_point_t Q;
st = paze_p521_scalar_mult(&Q, priv->ecdsa_d521, NULL);
if (st == PAZE_OK) {
uint8_t qa[133];
st = paze_p521_to_affine(&Q, qa, sizeof(qa));
if (st == PAZE_OK) st = paze_x509_build_spki521(spki, &sl, qa);
}
} else return PAZE_ERR_INVALID; } else return PAZE_ERR_INVALID;
if (st != PAZE_OK) return st; if (st != PAZE_OK) return st;
+5 -1
查看文件
@@ -70,7 +70,7 @@ 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) { paze_status_t paze_tls_config_set_kex_group(paze_tls_config_t *cfg, uint16_t group) {
if (!cfg) return PAZE_ERR_INVALID; 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) group != PAZE_TLS_GROUP_SECP384R1 && group != PAZE_TLS_GROUP_SECP521R1)
return PAZE_ERR_INVALID; return PAZE_ERR_INVALID;
cfg->kex_group = group; cfg->kex_group = group;
return PAZE_OK; return PAZE_OK;
@@ -179,6 +179,10 @@ paze_status_t paze_tls_config_set_cert_chain(paze_tls_config_t *cfg,
cfg->privkey.kind = PAZE_X509_PK_ECDSA_P384; cfg->privkey.kind = PAZE_X509_PK_ECDSA_P384;
return PAZE_OK; return PAZE_OK;
} }
if (paze_ecdsa_p521_priv_from_pem(cfg->privkey.ecdsa_d521, privkey_pem) == PAZE_OK) {
cfg->privkey.kind = PAZE_X509_PK_ECDSA_P521;
return PAZE_OK;
}
return PAZE_ERR_NOTSUP; /* 不支持的 EC 曲线 / 格式 */ return PAZE_ERR_NOTSUP; /* 不支持的 EC 曲线 / 格式 */
} }
if (strstr(privkey_pem, "PRIVATE KEY")) { if (strstr(privkey_pem, "PRIVATE KEY")) {
+16 -5
查看文件
@@ -72,30 +72,33 @@ 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) { size_t paze_tls_ext_write_supported_groups(uint8_t *buf) {
uint8_t *p = buf + 4; uint8_t *p = buf + 4;
p[0] = 0; p[1] = 6; /* list length = 6 (3 groups × 2 bytes) */ p[0] = 0; p[1] = 8; /* list length = 8 (4 groups × 2 bytes) */
paze_store16_be(p + 2, PAZE_TLS_GROUP_X25519); paze_store16_be(p + 2, PAZE_TLS_GROUP_X25519);
paze_store16_be(p + 4, PAZE_TLS_GROUP_SECP256R1); paze_store16_be(p + 4, PAZE_TLS_GROUP_SECP256R1);
paze_store16_be(p + 6, PAZE_TLS_GROUP_SECP384R1); paze_store16_be(p + 6, PAZE_TLS_GROUP_SECP384R1);
size_t body = 8; paze_store16_be(p + 8, PAZE_TLS_GROUP_SECP521R1);
size_t body = 10;
return put_ext_header(buf, PAZE_TLS_EXT_SUPPORTED_GROUPS, body) + body; return put_ext_header(buf, PAZE_TLS_EXT_SUPPORTED_GROUPS, body) + body;
} }
/* 解析 supported_groups: /* 解析 supported_groups:
* group = X25519 X25519, P-256, P-384, 0 */ * group = X25519 > P-256 > P-384 > P-521, 0 */
uint16_t paze_tls_ext_parse_supported_groups(const uint8_t *data, size_t len) { uint16_t paze_tls_ext_parse_supported_groups(const uint8_t *data, size_t len) {
if (len < 2) return 0; if (len < 2) return 0;
size_t ll = paze_load16_be(data); size_t ll = paze_load16_be(data);
if (len != 2 + ll || (ll & 1)) return 0; if (len != 2 + ll || (ll & 1)) return 0;
int have_x25519 = 0, have_p256 = 0, have_p384 = 0; int have_x25519 = 0, have_p256 = 0, have_p384 = 0, have_p521 = 0;
for (size_t i = 0; i < ll; i += 2) { for (size_t i = 0; i < ll; i += 2) {
uint16_t g = paze_load16_be(data + 2 + i); uint16_t g = paze_load16_be(data + 2 + i);
if (g == PAZE_TLS_GROUP_X25519) have_x25519 = 1; if (g == PAZE_TLS_GROUP_X25519) have_x25519 = 1;
if (g == PAZE_TLS_GROUP_SECP256R1) have_p256 = 1; if (g == PAZE_TLS_GROUP_SECP256R1) have_p256 = 1;
if (g == PAZE_TLS_GROUP_SECP384R1) have_p384 = 1; if (g == PAZE_TLS_GROUP_SECP384R1) have_p384 = 1;
if (g == PAZE_TLS_GROUP_SECP521R1) have_p521 = 1;
} }
if (have_x25519) return PAZE_TLS_GROUP_X25519; if (have_x25519) return PAZE_TLS_GROUP_X25519;
if (have_p256) return PAZE_TLS_GROUP_SECP256R1; if (have_p256) return PAZE_TLS_GROUP_SECP256R1;
if (have_p384) return PAZE_TLS_GROUP_SECP384R1; if (have_p384) return PAZE_TLS_GROUP_SECP384R1;
if (have_p521) return PAZE_TLS_GROUP_SECP521R1;
return 0; return 0;
} }
@@ -111,7 +114,8 @@ size_t paze_tls_ext_write_signature_algorithms(uint8_t *buf) {
PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384, PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384,
PAZE_TLS_SIG_RSA_PKCS1_SHA256, PAZE_TLS_SIG_RSA_PKCS1_SHA256,
PAZE_TLS_SIG_RSA_PKCS1_SHA384, PAZE_TLS_SIG_RSA_PKCS1_SHA384,
PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384,
PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512
}; };
int n = sizeof(algs)/sizeof(algs[0]); int n = sizeof(algs)/sizeof(algs[0]);
uint16_t ll = (uint16_t)(n * 2); uint16_t ll = (uint16_t)(n * 2);
@@ -156,6 +160,13 @@ size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *k
paze_store16_be(p, 97); p += 2; paze_store16_be(p, 97); p += 2;
memcpy(p, kex->p384_pub, 97); p += 97; memcpy(p, kex->p384_pub, 97); p += 97;
} }
if (only_group == PAZE_TLS_GROUP_SECP521R1 ||
(only_group == 0 && kex->kind == PAZE_KEX_P521)) {
/* P-521 share(仅 kind==P521 或 HRR 选定组时) */
paze_store16_be(p, PAZE_TLS_GROUP_SECP521R1); p += 2;
paze_store16_be(p, 133); p += 2;
memcpy(p, kex->p521_pub, 133); p += 133;
}
if (p == s + 2) return 0; /* 无 share 可写 */ if (p == s + 2) return 0; /* 无 share 可写 */
bodylen = (size_t)(p - s); bodylen = (size_t)(p - s);
paze_store16_be(s, (uint16_t)(bodylen - 2)); /* client_shares 长度 */ paze_store16_be(s, (uint16_t)(bodylen - 2)); /* client_shares 长度 */
+2
查看文件
@@ -356,6 +356,7 @@ static paze_status_t tls12_client_build_cke(paze_tls_t *tls,
if (tls->neg.group == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; } 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_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 if (tls->neg.group == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; }
else if (tls->neg.group == PAZE_TLS_GROUP_SECP521R1) { pub = tls->kex.p521_pub; plen = 133; }
else { paze_tls_set_err(tls, "1.2 group %04x not supported", tls->neg.group); return PAZE_ERR_NOTSUP; } 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; if (1 + plen > 128) return PAZE_ERR_OVERFLOW;
out[0] = (uint8_t)plen; /* RFC 5246 §7.4.7:ECDHE point 用 1 字节长度 */ out[0] = (uint8_t)plen; /* RFC 5246 §7.4.7:ECDHE point 用 1 字节长度 */
@@ -608,6 +609,7 @@ static paze_status_t tls12_server_build_ske(paze_tls_t *tls,
if (nc == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; } 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_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; }
else if (nc == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; } else if (nc == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; }
else if (nc == PAZE_TLS_GROUP_SECP521R1) { pub = tls->kex.p521_pub; plen = 133; }
else return PAZE_ERR_NOTSUP; else return PAZE_ERR_NOTSUP;
out[0] = 0x03; out[0] = 0x03;
+64 -13
查看文件
@@ -10,6 +10,7 @@
*/ */
#include "tls_internal.h" #include "tls_internal.h"
#include "paze/p384.h" #include "paze/p384.h"
#include "paze/p521.h"
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
@@ -27,29 +28,27 @@ 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_p256(paze_tls_kex_t *kex);
static paze_status_t paze_tls_kex_gen_p384(paze_tls_kex_t *kex); static paze_status_t paze_tls_kex_gen_p384(paze_tls_kex_t *kex);
static paze_status_t paze_tls_kex_gen_p521(paze_tls_kex_t *kex);
paze_status_t paze_tls_kex_generate(paze_tls_kex_t *kex, uint16_t group_hint) { paze_status_t paze_tls_kex_generate(paze_tls_kex_t *kex, uint16_t group_hint) {
paze_memzero(kex, sizeof(*kex)); paze_memzero(kex, sizeof(*kex));
int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1); int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1);
int prefer_p384 = (group_hint == PAZE_TLS_GROUP_SECP384R1); int prefer_p384 = (group_hint == PAZE_TLS_GROUP_SECP384R1);
int prefer_p521 = (group_hint == PAZE_TLS_GROUP_SECP521R1);
int only_x = (group_hint == PAZE_TLS_GROUP_X25519); int only_x = (group_hint == PAZE_TLS_GROUP_X25519);
if (prefer_p384) kex->kind = PAZE_KEX_P384; if (prefer_p521) kex->kind = PAZE_KEX_P521;
else if (prefer_p384) kex->kind = PAZE_KEX_P384;
else if (prefer_p256) kex->kind = PAZE_KEX_P256; else if (prefer_p256) kex->kind = PAZE_KEX_P256;
else kex->kind = PAZE_KEX_X25519; else kex->kind = PAZE_KEX_X25519;
if (only_x) { if (only_x) {
/* 仅生成 X25519 密钥对(其余清零) */
if (paze_random(kex->x25519_priv, 32) != PAZE_OK) return PAZE_ERR_PLATFORM; if (paze_random(kex->x25519_priv, 32) != PAZE_OK) return PAZE_ERR_PLATFORM;
if (paze_x25519_public(kex->x25519_pub, kex->x25519_priv) != 0) return PAZE_ERR; if (paze_x25519_public(kex->x25519_pub, kex->x25519_priv) != 0) return PAZE_ERR;
return PAZE_OK; return PAZE_OK;
} }
if (prefer_p384) { if (prefer_p521) return paze_tls_kex_gen_p521(kex);
return paze_tls_kex_gen_p384(kex); if (prefer_p384) return paze_tls_kex_gen_p384(kex);
} if (prefer_p256) return paze_tls_kex_gen_p256(kex);
if (prefer_p256) {
/* 仅生成 P-256 密钥对 */
return paze_tls_kex_gen_p256(kex);
}
/* 默认:X25519 优先(仅发 X25519 share;P-256 密钥对也生成备用) */ /* 默认:X25519 优先(仅发 X25519 share;P-256 密钥对也生成备用) */
if (paze_random(kex->x25519_priv, 32) != PAZE_OK) return PAZE_ERR_PLATFORM; if (paze_random(kex->x25519_priv, 32) != PAZE_OK) return PAZE_ERR_PLATFORM;
@@ -89,6 +88,22 @@ static paze_status_t paze_tls_kex_gen_p384(paze_tls_kex_t *kex) {
return PAZE_OK; return PAZE_OK;
} }
/* 生成 P-521 密钥对(priv 归一化到 [1, n-1],pub = 0x04||X||Y) */
static paze_status_t paze_tls_kex_gen_p521(paze_tls_kex_t *kex) {
if (paze_random(kex->p521_priv, 66) != PAZE_OK) return PAZE_ERR_PLATFORM;
paze_bn_t d, n, tmp;
paze_p521_load_n(&n);
paze_bn_from_bytes(&d, kex->p521_priv, 66);
paze_bn_mod(&d, &d, &n);
paze_bn_set_u32(&tmp, 1);
paze_bn_add(&d, &d, &tmp);
paze_bn_to_bytes(&d, kex->p521_priv, 66);
paze_p521_point_t Q;
paze_p521_scalar_mult(&Q, kex->p521_priv, NULL);
if (paze_p521_to_affine(&Q, kex->p521_pub, 133) != PAZE_OK) return PAZE_ERR;
return PAZE_OK;
}
paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group, 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, const uint8_t *peer_pub, size_t peer_pub_len,
uint8_t *shared_out, size_t *shared_len) { uint8_t *shared_out, size_t *shared_len) {
@@ -132,6 +147,24 @@ paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group,
*shared_len = 48; *shared_len = 48;
return PAZE_OK; return PAZE_OK;
} }
if (server_group == PAZE_TLS_GROUP_SECP521R1) {
if (peer_pub_len != 133 || peer_pub[0] != 0x04) return PAZE_ERR_FORMAT;
paze_p521_point_t Q, R;
if (paze_p521_from_affine(&Q, peer_pub, 133) != PAZE_OK) return PAZE_ERR_FORMAT;
if (paze_p521_scalar_mult(&R, mine->p521_priv, &Q) != PAZE_OK) return PAZE_ERR;
/* TLS 1.3 ECDHE 共享密钥 = 共享点 x 坐标(SEC1,固定 66 字节) */
paze_bn_t zinv, zinv2, x;
{
paze_bn_t p; paze_p521_load_p(&p);
paze_bn_t e; paze_bn_set_u32(&e, 2); paze_bn_sub(&e, &p, &e);
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, 66);
*shared_len = 66;
return PAZE_OK;
}
return PAZE_ERR_NOTSUP; return PAZE_ERR_NOTSUP;
} }
@@ -388,6 +421,14 @@ static paze_status_t sign_cv(paze_tls_t *tls, uint16_t *sig_alg,
*sig_alg = PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384; *sig_alg = PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384;
return PAZE_OK; return PAZE_OK;
} }
if (cfg->privkey.kind == PAZE_X509_PK_ECDSA_P521) {
uint8_t h[64]; paze_sha512(tbs, tbs_len, h);
paze_status_t st = paze_ecdsa_p521_sign(cfg->privkey.ecdsa_d521,
PAZE_RSA_HASH_SHA512, h, 64, sig, sig_len);
if (st != PAZE_OK) return st;
*sig_alg = PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512;
return PAZE_OK;
}
return PAZE_ERR_NOTSUP; return PAZE_ERR_NOTSUP;
} }
@@ -406,11 +447,13 @@ static paze_status_t verify_cv(paze_tls_t *tls, int is_server_peer,
case PAZE_TLS_SIG_RSA_PKCS1_SHA384: rh = PAZE_RSA_HASH_SHA384; 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_SECP256R1_SHA256: rh = PAZE_RSA_HASH_SHA256; break;
case PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384: rh = PAZE_RSA_HASH_SHA384; break; case PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384: rh = PAZE_RSA_HASH_SHA384; break;
case PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512: rh = PAZE_RSA_HASH_SHA512; break;
default: return PAZE_ERR_NOTSUP; default: return PAZE_ERR_NOTSUP;
} }
uint8_t h[64]; size_t hl = 0; uint8_t h[64]; size_t hl = 0;
if (rh == PAZE_RSA_HASH_SHA256) { paze_sha256(tbs, tbs_len, h); hl = 32; } if (rh == PAZE_RSA_HASH_SHA256) { paze_sha256(tbs, tbs_len, h); hl = 32; }
else if (rh == PAZE_RSA_HASH_SHA384) { paze_sha384(tbs, tbs_len, h); hl = 48; } else if (rh == PAZE_RSA_HASH_SHA384) { paze_sha384(tbs, tbs_len, h); hl = 48; }
else if (rh == PAZE_RSA_HASH_SHA512) { paze_sha512(tbs, tbs_len, h); hl = 64; }
else return PAZE_ERR_NOTSUP; else return PAZE_ERR_NOTSUP;
if (leaf->pk_kind == PAZE_X509_PK_RSA) { if (leaf->pk_kind == PAZE_X509_PK_RSA) {
@@ -432,6 +475,12 @@ static paze_status_t verify_cv(paze_tls_t *tls, int is_server_peer,
return paze_ecdsa_p384_verify(leaf->ecdsa_p384_pub, PAZE_RSA_HASH_SHA384, return paze_ecdsa_p384_verify(leaf->ecdsa_p384_pub, PAZE_RSA_HASH_SHA384,
h, hl, sig, sig_len); h, hl, sig, sig_len);
} }
if (leaf->pk_kind == PAZE_X509_PK_ECDSA_P521) {
if (sig_alg != PAZE_TLS_SIG_ECDSA_SECP521R1_SHA512)
return PAZE_ERR_VERIFY;
return paze_ecdsa_p521_verify(leaf->ecdsa_p521_pub, PAZE_RSA_HASH_SHA512,
h, hl, sig, sig_len);
}
return PAZE_ERR_VERIFY; return PAZE_ERR_VERIFY;
} }
@@ -717,7 +766,7 @@ static paze_status_t client_handle_hrr(paze_tls_t *tls,
return PAZE_ERR_PROTOCOL; 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) { hx.g != PAZE_TLS_GROUP_SECP384R1 && hx.g != PAZE_TLS_GROUP_SECP521R1) {
paze_tls_set_err(tls, "HRR selected unsupported group %d", hx.g); paze_tls_set_err(tls, "HRR selected unsupported group %d", hx.g);
return PAZE_ERR_NOTSUP; return PAZE_ERR_NOTSUP;
} }
@@ -850,7 +899,7 @@ paze_status_t paze_tls13_client_handshake(paze_tls_t *tls) {
} }
tls->neg.group = group; tls->neg.group = group;
uint8_t shared[64]; size_t shared_len = 0; uint8_t shared[68]; size_t shared_len = 0;
if (found_ks) { if (found_ks) {
st = paze_tls_kex_ecdh(&tls->kex, group, ks_pub, ks_publen, shared, &shared_len); st = paze_tls_kex_ecdh(&tls->kex, group, ks_pub, ks_publen, shared, &shared_len);
if (st != PAZE_OK) return st; if (st != PAZE_OK) return st;
@@ -1291,7 +1340,7 @@ paze_status_t paze_tls13_server_handshake(paze_tls_t *tls) {
ks_lookup_ctx_t ksl = { select_group, &ks_pub, &ks_publen, &have_share }; ks_lookup_ctx_t ksl = { select_group, &ks_pub, &ks_publen, &have_share };
paze_tls_extensions_foreach(exts, 2 + ext_total, ks_lookup_cb, &ksl); paze_tls_extensions_foreach(exts, 2 + ext_total, ks_lookup_cb, &ksl);
uint8_t shared[64]; size_t shared_len = 0; uint8_t shared[68]; size_t shared_len = 0;
/* 0-RTT 密钥派生:CH 带 early_data 且 PSK 被接受 → 派生 early_read /* 0-RTT 密钥派生:CH 带 early_data 且 PSK 被接受 → 派生 early_read
* (AEAD = CH AEAD,RFC 8446 §4.2.10) * (AEAD = CH AEAD,RFC 8446 §4.2.10)
@@ -1412,8 +1461,10 @@ paze_status_t paze_tls13_server_handshake(paze_tls_t *tls) {
n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_X25519, tls->kex.x25519_pub, 32); n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_X25519, tls->kex.x25519_pub, 32);
else if (select_group == PAZE_TLS_GROUP_SECP256R1) 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); n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP256R1, tls->kex.p256_pub, 65);
else else if (select_group == PAZE_TLS_GROUP_SECP384R1)
n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP384R1, tls->kex.p384_pub, 97); n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP384R1, tls->kex.p384_pub, 97);
else
n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP521R1, tls->kex.p521_pub, 133);
sp += n; sp += n;
} }
if (tls->psk_mode) { if (tls->psk_mode) {
+5 -1
查看文件
@@ -76,7 +76,8 @@ typedef enum {
PAZE_KEX_NONE = 0, PAZE_KEX_NONE = 0,
PAZE_KEX_X25519, PAZE_KEX_X25519,
PAZE_KEX_P256, PAZE_KEX_P256,
PAZE_KEX_P384 PAZE_KEX_P384,
PAZE_KEX_P521
} paze_tls_kex_kind_t; } paze_tls_kex_kind_t;
typedef struct { typedef struct {
@@ -90,6 +91,9 @@ typedef struct {
/* P-384 */ /* P-384 */
uint8_t p384_priv[48]; uint8_t p384_priv[48];
uint8_t p384_pub[97]; /* 0x04||X||Y */ uint8_t p384_pub[97]; /* 0x04||X||Y */
/* P-521 */
uint8_t p521_priv[66];
uint8_t p521_pub[133]; /* 0x04||X||Y */
} paze_tls_kex_t; } paze_tls_kex_t;
/* ============================================================ /* ============================================================