diff --git a/AGENT.MD b/AGENT.MD index a5ea6d0..b645726 100644 --- a/AGENT.MD +++ b/AGENT.MD @@ -67,3 +67,14 @@ STATUS.md 完成度总表 AGENT.md 本文件 - 补全(2026-08-14):`pssh ssh -W host:port`(stdio/netcat 转发,目标 TCP 隧道桥接本地 stdio)、`-N`(仅端口转发不执行远程命令,配 `-L/-R/-D`)。 已知限制:`-J` 接受逗号分隔的多跳语法,但多级级联跳板在同步 I/O 架构下的应用数据阶段交互不稳定,实测多跳握手可完成但握手后易卡;故当前对多跳打印警告并**退化为仅第一跳的稳定单跳**。单跳与 `-W`/`-N` 均已实测验证。 + +### 4. secp521r1(TLS 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+证书链/主机名验证)全部通过;既有自测无回归。 + diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a1238..7ff8188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ 本项目 (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 ### 新增 —— TLS secp384r1 (P-384) 完整链路 diff --git a/STATUS.md b/STATUS.md index 2a0bcec..4da2c88 100644 --- a/STATUS.md +++ b/STATUS.md @@ -16,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、P-384(secp384r1)**、ECDSA(大数运算自研:模幂、模逆、Montgomery) +- 曲线:X25519、Ed25519、**P-256、P-384(secp384r1)、P-521(secp521r1)**、ECDSA(大数运算自研:模幂、模逆、Montgomery) - 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码 - 其他: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 密钥派生、握手前早数据收发、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 双向交叉验证 +- ✅ **secp521r1(TLS 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_SHA512(0x0603),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) ## PazeSSH — SSH-2(✅ 完成) diff --git a/apps/pazessl/main.c b/apps/pazessl/main.c index a8fcf1e..18683be 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|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 verify -CAfile roots.pem cert.pem\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; 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 { 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 (sni) paze_tls_config_set_sni(cfg, sni); diff --git a/include/paze/ecdsa.h b/include/paze/ecdsa.h index 2aff97d..3e92a27 100644 --- a/include/paze/ecdsa.h +++ b/include/paze/ecdsa.h @@ -83,6 +83,21 @@ 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); +/* 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 } #endif diff --git a/include/paze/p521.h b/include/paze/p521.h new file mode 100644 index 0000000..d06e40c --- /dev/null +++ b/include/paze/p521.h @@ -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 */ diff --git a/include/paze/tls.h b/include/paze/tls.h index e7eaa08..22d0f8c 100644 --- a/include/paze/tls.h +++ b/include/paze/tls.h @@ -50,11 +50,13 @@ extern "C" { /* 命名组 (NamedGroup, key exchange) */ #define PAZE_TLS_GROUP_SECP256R1 0x0017 #define PAZE_TLS_GROUP_SECP384R1 0x0018 +#define PAZE_TLS_GROUP_SECP521R1 0x0019 #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_ECDSA_SECP521R1_SHA512 0x0603 #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 f1b3c44..9d08a5c 100644 --- a/include/paze/x509.h +++ b/include/paze/x509.h @@ -34,7 +34,8 @@ typedef enum { PAZE_X509_PK_UNKNOWN = 0, PAZE_X509_PK_RSA = 1, 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; /* 证书签名算法 */ @@ -45,7 +46,8 @@ typedef enum { PAZE_X509_SIG_SHA384_RSA = 3, PAZE_X509_SIG_SHA512_RSA = 4, 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; #define PAZE_X509_SAN_MAX 8 @@ -69,6 +71,8 @@ typedef struct { paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */ /* pk_kind==ECDSA_P384 时,主体公钥为未压缩点 0x04||X||Y (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) */ const uint8_t *signature; size_t signature_len; @@ -138,6 +142,7 @@ typedef struct { paze_rsa_priv_t rsa; /* kind==RSA 时有效 */ uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */ uint8_t ecdsa_d384[48]; /* kind==ECDSA_P384 时,私钥标量大端 */ + uint8_t ecdsa_d521[66]; /* kind==ECDSA_P521 时,私钥标量大端 */ } paze_x509_signer_t; /* 构造 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) */ paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen, 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)。 */ 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 c3d2a44..4dd42da 100644 --- a/src/crypto/ecdsa.c +++ b/src/crypto/ecdsa.c @@ -12,6 +12,7 @@ */ #include "paze/ecdsa.h" #include "paze/p384.h" +#include "paze/p521.h" #include "paze/hmac.h" #include "paze/hash.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 的差异点提取为这组小助手。 - * 点(paze_bn_t X,Y,Z)两种曲线 ABI 相同,用 paze_bn_t[3] 承载。 + * 曲线抽象:p256 / p384 / p521 的差异点提取为这组小助手。 + * 点(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) { - 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); } -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; } +static int curve_scalar_len(curve_t c) { + 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 的数组。 */ 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_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) { 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]); } @@ -87,7 +101,13 @@ static paze_status_t curve_point_mult(curve_t c, paze_bn_t pt[3], /* 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) { + 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; a.X = P1[0]; a.Y = P1[1]; a.Z = P1[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]) { + 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) { paze_p384_point_t pt; 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], const uint8_t *in, size_t 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) { paze_p384_point_t pt; 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); /* int2octets(d): 直接拷贝已定长大端标量 */ - uint8_t x_oct[48]; + uint8_t x_oct[66]; memcpy(x_oct, d_bytes, (size_t)slen); /* 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[48]; + uint8_t h1_oct[66]; int2octets(h1_oct, (size_t)slen, &z2); /* 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(K, 0x00, hlen); - uint8_t buf[64 + 1 + 48 + 48]; - uint8_t T[64]; + /* buf 需容纳 hlen+1+slen+slen(最大 SHA-512=64 + 1 + 66 + 66 = 197); + * 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) */ 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)); paze_bn_t r, s; - uint8_t k_be[48]; + uint8_t k_be[66]; paze_status_t rc; int got = 0; @@ -383,7 +417,7 @@ static paze_status_t ecdsa_verify_internal(curve_t c, paze_bn_modmul(&u2, r, &w, &n); 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(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); } +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,既有) * ============================================================ */ @@ -575,3 +632,48 @@ paze_status_t paze_ecdsa_p384_priv_from_pem(uint8_t d384[48], const char *pem_te free(der); 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; +} diff --git a/src/crypto/p521.c b/src/crypto/p521.c new file mode 100644 index 0000000..839416f --- /dev/null +++ b/src/crypto/p521.c @@ -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 + +/* ---- 曲线常量(大端 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; +} diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 099a9cc..670d747 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -21,6 +21,7 @@ */ #include "paze/x509.h" #include "paze/p384.h" +#include "paze/p521.h" #include "paze/asn1.h" #include "paze/encoding.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_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_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_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 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_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_SHA512,8))return PAZE_X509_SIG_ECDSA_SHA512; 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); 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; @@ -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) return paze_ecdsa_p384_verify(issuer->ecdsa_p384_pub, PAZE_RSA_HASH_SHA256, 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; case PAZE_X509_SIG_ECDSA_SHA384: 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) return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA384, 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; default: 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) { 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; } @@ -738,6 +772,38 @@ paze_status_t paze_x509_build_spki384(uint8_t *out, size_t *outlen, 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, const uint8_t *subject_spki, size_t spki_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; } 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 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; 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_set_d(&ek, issuer_priv->ecdsa_d); 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]; 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); + } 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; } @@ -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)); 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; if (st != PAZE_OK) return st; diff --git a/src/ssl/tls_conn.c b/src/ssl/tls_conn.c index db94ee4..3e3c07c 100644 --- a/src/ssl/tls_conn.c +++ b/src/ssl/tls_conn.c @@ -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) { if (!cfg) return PAZE_ERR_INVALID; 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; cfg->kex_group = group; 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; 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 曲线 / 格式 */ } if (strstr(privkey_pem, "PRIVATE KEY")) { diff --git a/src/ssl/tls_extensions.c b/src/ssl/tls_extensions.c index 15ad5b2..5ec640c 100644 --- a/src/ssl/tls_extensions.c +++ b/src/ssl/tls_extensions.c @@ -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) { 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 + 4, PAZE_TLS_GROUP_SECP256R1); 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; } /* 解析 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) { 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, 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) { 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 (g == PAZE_TLS_GROUP_SECP521R1) have_p521 = 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; + if (have_p521) return PAZE_TLS_GROUP_SECP521R1; 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_PKCS1_SHA256, 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]); 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; 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 可写 */ 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 0443edb..50e6b89 100644 --- a/src/ssl/tls_handshake12.c +++ b/src/ssl/tls_handshake12.c @@ -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; } 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_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; } if (1 + plen > 128) return PAZE_ERR_OVERFLOW; 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; } 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_SECP521R1) { pub = tls->kex.p521_pub; plen = 133; } else return PAZE_ERR_NOTSUP; out[0] = 0x03; diff --git a/src/ssl/tls_handshake13.c b/src/ssl/tls_handshake13.c index d48da46..b99cdef 100644 --- a/src/ssl/tls_handshake13.c +++ b/src/ssl/tls_handshake13.c @@ -10,6 +10,7 @@ */ #include "tls_internal.h" #include "paze/p384.h" +#include "paze/p521.h" #include #include @@ -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_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_memzero(kex, sizeof(*kex)); int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1); 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); - 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 kex->kind = PAZE_KEX_X25519; if (only_x) { - /* 仅生成 X25519 密钥对(其余清零) */ 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; 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); - } + if (prefer_p521) return paze_tls_kex_gen_p521(kex); + if (prefer_p384) return paze_tls_kex_gen_p384(kex); + if (prefer_p256) return paze_tls_kex_gen_p256(kex); /* 默认:X25519 优先(仅发 X25519 share;P-256 密钥对也生成备用) */ 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; } +/* 生成 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, const uint8_t *peer_pub, size_t peer_pub_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; 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; } @@ -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; 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; } @@ -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_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_SECP521R1_SHA512: rh = PAZE_RSA_HASH_SHA512; break; default: return PAZE_ERR_NOTSUP; } uint8_t h[64]; size_t hl = 0; 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_SHA512) { paze_sha512(tbs, tbs_len, h); hl = 64; } else return PAZE_ERR_NOTSUP; 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, 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; } @@ -717,7 +766,7 @@ static paze_status_t client_handle_hrr(paze_tls_t *tls, return PAZE_ERR_PROTOCOL; } 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); return PAZE_ERR_NOTSUP; } @@ -850,7 +899,7 @@ paze_status_t paze_tls13_client_handshake(paze_tls_t *tls) { } 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) { st = paze_tls_kex_ecdh(&tls->kex, group, ks_pub, ks_publen, shared, &shared_len); 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 }; 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 * (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); 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 + 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); + else + n = paze_tls_ext_write_key_share_server(sp, PAZE_TLS_GROUP_SECP521R1, tls->kex.p521_pub, 133); sp += n; } if (tls->psk_mode) { diff --git a/src/ssl/tls_internal.h b/src/ssl/tls_internal.h index 80978fd..9480b99 100644 --- a/src/ssl/tls_internal.h +++ b/src/ssl/tls_internal.h @@ -76,7 +76,8 @@ typedef enum { PAZE_KEX_NONE = 0, PAZE_KEX_X25519, PAZE_KEX_P256, - PAZE_KEX_P384 + PAZE_KEX_P384, + PAZE_KEX_P521 } paze_tls_kex_kind_t; typedef struct { @@ -90,6 +91,9 @@ typedef struct { /* P-384 */ uint8_t p384_priv[48]; 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; /* ============================================================