实现 TLS secp384r1 (P-384) 完整链路: 新增 include/paze/p384.h 与 src/crypto/p384.c (Jacobian 点运算+常量时间标量乘); ECDSA 支持 P-384 签名/验签(RFC 6979)与 RFC 5915 私钥解析(paze_ecdsa_p384_*); X.509 支持 secp384r1 证书解析/验签/签发(build_spki384); TLS 1.3 支持 secp384r1 组(key_share/supported_groups/ECDH SEC1 x 坐标/HRR/服务端组选择)与签名算法 ECDSA_SECP384R1_SHA384, TLS 1.2 ECDHE 亦支持; pazessl s_client -key_share P-384; 附带修复: ECDSA bits2int 短于群阶右对齐, 新增 paze_tls_store_peer_cert 避免对端证书指针被记录层缓冲复用导致链验证失败; 曲线/ECDSA/证书经 OpenSSL 双向验证, TLS 端点验证通过, 既有自测无回归; STATUS/AGENT 更新

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