实现 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 更新
这个提交包含在:
@@ -27,16 +27,37 @@ STATUS.md 完成度总表 AGENT.md 本文件
|
|||||||
8. **Git**:中文提交信息;不主动推送,用户要求才推(parlz=gitea、origin=GitHub);无 push 权限/网络问题时如实报告。
|
8. **Git**:中文提交信息;不主动推送,用户要求才推(parlz=gitea、origin=GitHub);无 push 权限/网络问题时如实报告。
|
||||||
9. **文档**:改功能同步更新 STATUS.md;不建多余 .md。
|
9. **文档**:改功能同步更新 STATUS.md;不建多余 .md。
|
||||||
|
|
||||||
|
## 已实现功能要点
|
||||||
|
|
||||||
|
### 0-RTT / HRR(TLS 1.3,RFC 8446)
|
||||||
|
- 状态机(`src/ssl/tls_handshake13.c`):
|
||||||
|
- 客户端:`paze_tls13_client_send_ch`(抽出的 CH 发送,幂等)、`client_handle_hrr`(识别 HRR 魔数 → `paze_tls_tr_reset_to_synthetic` 合成 MessageHash → CH2 仅选定组 share)、`client_rebuild_transcript`、EndOfEarlyData 在 client Finished **之前**用 early_write 发送
|
||||||
|
- 服务端:`server_try_psk`(ticket MAC+binder 验证)、`ch_ext_cb`/`ks_lookup_cb`(supported_groups 首组 vs key_share 查找决定 HRR)、`sent_hrr` 分支发送 HRR(random=魔数 `CF21AD74E58690691115AEDE1F40DFC9C4504D46C174A12E8B4A6F1346F84A4F`)、early_read 解密早数据入 `early_buf`、跳过 EndOfEarlyData 后切 handshake_read
|
||||||
|
- key schedule(`src/ssl/tls_keys.c`):`paze_tls13_derive_early_key`(PSK 关联 hash 直哈希最终 CH,client_early_traffic_secret → early_write/early_read)、`paze_tls13_psk_early_secret`
|
||||||
|
- 扩展(`src/ssl/tls_extensions.c`):`paze_tls_ext_write/parse_early_data`(type 42)、`key_share_client(…only_group)`
|
||||||
|
- 内部字段(`src/ssl/tls_internal.h`):`hrr_raw/ch2/had_hrr/hrr_group/sent_hrr`、`early_offer/early_sent/early_accepted/early_accept`、`early_read/early_write`
|
||||||
|
- 公共 API(`include/paze/tls.h` + `tls_conn.c`):`paze_tls_config_enable_early_data`、`paze_tls_early_write`(握手前发早数据)、`paze_tls_early_data_accepted`、`paze_tls_early_data_len`(服务端早数据缓冲)、`paze_tls_hrr_occurred`
|
||||||
|
- CLI(`apps/pazessl/main.c`):`s_client -early -sess_in/-sess_out -key_share X25519|P-256`;`s_server -early -reuse`
|
||||||
|
- 已知约束:0-RTT 仅在同进程会话复用(ticket_key 内存态)时可用;跨进程重启服务端会拒绝 PSK → early 记录解密失败(预期行为)
|
||||||
|
- 验证:`s_server -reuse 2 -early` + 两次 `s_client`(首次 `-sess_out`、二次 `-sess_in -early`)→ `early data received` + `early accepted`;`-key_share P-256` → `hrr=YES`
|
||||||
|
|
||||||
## 待办(按优先级)
|
## 待办(按优先级)
|
||||||
|
|
||||||
### 1. 0-RTT / HRR — TLS 1.3 数据路径(✅ 已完成 2026-08-13)
|
### 1. 0-RTT / HRR — TLS 1.3 数据路径(✅ 已完成 2026-08-13,详见上文要点)
|
||||||
- 服务端:CH 无 key_share → 发 HRR(random=魔数 `CF21AD74...F84A4F`)→ 等 CH2;`sent_hrr` 标记
|
|
||||||
- 客户端:识别 HRR 魔数 → `paze_tls_tr_reset_to_synthetic` → 生成 CH2(仅选定组 share)→ 放弃 0-RTT
|
|
||||||
- 0-RTT:客户端 CH 带 early_data 扩展 + 发 early 数据(early_write);服务端解密(early_read);EndOfEarlyData 用 client_early_traffic_secret
|
|
||||||
- 验证:`pazessl s_client -early -sess_in ...` / `s_server -early` 端到端通过(同进程会话复用);`-key_share P-256` 触发 HRR 通过
|
|
||||||
|
|
||||||
### 2. TLS secp384r1
|
### 2. TLS secp384r1(✅ 已完成 2026-08-13)
|
||||||
实现 P-384 点运算(bignum 已有),加曲线 + 套件,中等偏繁。
|
|
||||||
|
已实现 P-384 完整链路:
|
||||||
|
- 曲线:`src/crypto/p384.c` + `include/paze/p384.h`(Jacobian 点运算、常量时间标量乘、仿射编解码,结构对齐 p256)
|
||||||
|
- ECDSA:`ecdsa.c/h` 新增 `paze_ecdsa_p384_sign/verify`(RFC 6979 确定性 k)、`paze_ecdsa_p384_priv_from_pem/der`(RFC 5915,secp384r1)
|
||||||
|
- X.509:`x509.c/h` 支持 secp384r1 证书解析(`pk_kind==ECDSA_P384`)、验签(ecdsa-with-SHA384,及 SHA256 配 P-384)、`paze_x509_build_spki384`、签发(`signer.ecdsa_d384`)
|
||||||
|
- TLS:`tls.h` 增 `PAZE_TLS_GROUP_SECP384R1(0x0018)` / `PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384(0x0503)`;`tls_internal.h` `kex` 增 `P384` 与 `p384_priv[48]/p384_pub[97]`;`tls_handshake13.c` `kex_generate/ecdh`、sign_cv/verify_cv、HRR、服务端 key_share 支持 P-384(ECDH 按 SEC1 x 坐标 48 字节);`tls_extensions.c` supported_groups/signature_algorithms/key_share;TLS 1.2 ECDHE 亦支持
|
||||||
|
- CLI:`s_client -key_share P-384`
|
||||||
|
- 验证:P-384 曲线(n·G=∞、3G=2G+G)、ECDSA 双向(OpenSSL 验我的签名 + 我验 OpenSSL 签名)、X.509 P-384 自签名证书 OpenSSL `verify=OK`、TLS 端点 P-384 密钥交换(hrr=YES)+证书链/主机名验证全部通过;既有自测无回归
|
||||||
|
|
||||||
|
附带修复:
|
||||||
|
- `ecdsa.c` `bits2int`:输入短于群阶 qlen 时应右对齐而非左移(否则 P-384+SHA-256 验签错误)
|
||||||
|
- `tls_conn.c` 新增 `paze_tls_store_peer_cert`:对端证书 DER 拷贝到自有缓冲,避免 issuer/subject 指针指向被记录层复用的 `app_buf` 导致链验证失败(TLS 1.3 与 1.2 均在 Certificate 解析处使用)
|
||||||
|
|
||||||
### 3. SSH ProxyJump
|
### 3. SSH ProxyJump
|
||||||
客户端连接管理(经跳板机转发),中等。
|
客户端连接管理(经跳板机转发),中等。
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
> PazeSSL / PazeSSH:从零实现、仅依赖 libc 的 OpenSSL / OpenSSH 平替(纯 C, ISO C17)。
|
> PazeSSL / PazeSSH:从零实现、仅依赖 libc 的 OpenSSL / OpenSSH 平替(纯 C, ISO C17)。
|
||||||
> 按层推进,本文件汇总当前各层完成度(2026-08-13 更新)。
|
> 按层推进,本文件汇总当前各层完成度(2026-08-13 更新)。
|
||||||
|
|
||||||
## 总体
|
## 总体
|
||||||
|
|
||||||
| 层 | 模块 | 状态 |
|
| 层 | 模块 | 状态 |
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
|
|
||||||
- 哈希:SHA-1 / SHA-256 / SHA-512 / MD5 / HMAC / HKDF / PBKDF2
|
- 哈希:SHA-1 / SHA-256 / SHA-512 / MD5 / HMAC / HKDF / PBKDF2
|
||||||
- 对称:AES-128/192/256、AES-CBC/GCM、ChaCha20、Poly1305、ChaCha20-Poly1305 AEAD
|
- 对称:AES-128/192/256、AES-CBC/GCM、ChaCha20、Poly1305、ChaCha20-Poly1305 AEAD
|
||||||
- 曲线:X25519、Ed25519、P-256、ECDSA(大数运算自研:模幂、模逆、Montgomery)
|
- 曲线:X25519、Ed25519、**P-256、P-384(secp384r1)**、ECDSA(大数运算自研:模幂、模逆、Montgomery)
|
||||||
- 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码
|
- 非对称:RSA(密钥生成/加解密/签名)、X.509 证书解析与构建、PEM/DER 编解码
|
||||||
- 其他:ASN.1 DER、base64、hex、常量时间准则
|
- 其他:ASN.1 DER、base64、hex、常量时间准则
|
||||||
|
|
||||||
@@ -32,6 +31,8 @@
|
|||||||
- ✅ TLS 1.3 SHA-384 密码套件(TLS_AES_256_GCM_SHA384)服务端/客户端握手(含 PSK 恢复的 resumption_master_secret)
|
- ✅ TLS 1.3 SHA-384 密码套件(TLS_AES_256_GCM_SHA384)服务端/客户端握手(含 PSK 恢复的 resumption_master_secret)
|
||||||
- ✅ **0-RTT 数据路径**(RFC 8446 §4.2.10/§4.5/§8):early_data 扩展、client_early_traffic_secret 密钥派生、握手前早数据收发、EndOfEarlyData(early key 加密且计入 transcript);`pazessl s_client/s_server -early` 端到端验证(早数据接收 + early accepted)
|
- ✅ **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` 互操作验证通过
|
- ✅ **HRR(HelloRetryRequest)**(RFC 8446 §4.1.3/§4.1.4):服务端 key_share 不匹配时发 HRR(随机数=固定魔数)、transcript 合成 MessageHash 重放、客户端 CH2(仅选定组 share)响应、HRR 后放弃 0-RTT;`-key_share` 选项触发,`hrr=YES` 互操作验证通过
|
||||||
|
- ✅ **secp384r1(TLS P-384)**:新增 P-384 曲线点运算(`p384.c`,Jacobian,常量时间标量乘);ECDSA 支持 P-384 签名/验签(RFC 6979 确定性 k,`paze_ecdsa_p384_*`);X.509 支持 secp384r1 证书解析/验签/签发(含 ecdsa-with-SHA384 与 P-384 公钥,`paze_x509_build_spki384`);TLS 1.3 支持 secp384r1 组(key_share/supported_groups/ECDH 按 SEC1 x 坐标)、签名算法 ECDSA_SECP384R1_SHA384;TLS 1.2 ECDHE 亦支持 P-384。`s_client -key_share P-384` 端到端验证(含 HRR 触发与 P-384 证书链/主机名验证);曲线与 ECDSA 经 OpenSSL 双向交叉验证
|
||||||
|
- ✅ **修复**:ECDSA `bits2int` 输入短于群阶时错误左移(影响 P-384+SHA-256 验签);TLS 1.3/1.2 对端证书 `issuer_dn/subject_dn` 等指针指向被记录层复用缓冲导致的链验证失败(`paze_tls_store_peer_cert` 拷贝 DER)
|
||||||
|
|
||||||
## PazeSSH — SSH-2(✅ 完成)
|
## PazeSSH — SSH-2(✅ 完成)
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -72,7 +72,7 @@ static int usage(void) {
|
|||||||
"PazeSSL v0.1 (libc-only TLS 1.3 + 1.2)\n"
|
"PazeSSL v0.1 (libc-only TLS 1.3 + 1.2)\n"
|
||||||
"Usage:\n"
|
"Usage:\n"
|
||||||
" pazessl s_client -connect host:port [-CAfile roots.pem] [-servername SNI] [-tls1_2]\n"
|
" pazessl s_client -connect host:port [-CAfile roots.pem] [-servername SNI] [-tls1_2]\n"
|
||||||
" [-sess_in file] [-sess_out file] [-msg text] [-early] [-key_share X25519|P-256]\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 s_server -accept port -cert cert.pem -key key.pem [-tls1_2] [-reuse N] [-early]\n"
|
||||||
" pazessl verify -CAfile roots.pem cert.pem\n"
|
" pazessl verify -CAfile roots.pem cert.pem\n"
|
||||||
" pazessl genrsa -out key.pem [2048]\n"
|
" pazessl genrsa -out key.pem [2048]\n"
|
||||||
@@ -163,7 +163,8 @@ int main(int argc, char **argv) {
|
|||||||
uint16_t g = 0;
|
uint16_t g = 0;
|
||||||
if (strcmp(key_share, "X25519") == 0) g = PAZE_TLS_GROUP_X25519;
|
if (strcmp(key_share, "X25519") == 0) g = PAZE_TLS_GROUP_X25519;
|
||||||
else if (strcmp(key_share, "P-256") == 0) g = PAZE_TLS_GROUP_SECP256R1;
|
else if (strcmp(key_share, "P-256") == 0) g = PAZE_TLS_GROUP_SECP256R1;
|
||||||
else { 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 (paze_tls_config_set_kex_group(cfg, g) != PAZE_OK) return 1;
|
||||||
}
|
}
|
||||||
if (sni) paze_tls_config_set_sni(cfg, sni);
|
if (sni) paze_tls_config_set_sni(cfg, sni);
|
||||||
|
|||||||
@@ -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) */
|
/* 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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -49,10 +49,12 @@ extern "C" {
|
|||||||
|
|
||||||
/* 命名组 (NamedGroup, key exchange) */
|
/* 命名组 (NamedGroup, key exchange) */
|
||||||
#define PAZE_TLS_GROUP_SECP256R1 0x0017
|
#define PAZE_TLS_GROUP_SECP256R1 0x0017
|
||||||
|
#define PAZE_TLS_GROUP_SECP384R1 0x0018
|
||||||
#define PAZE_TLS_GROUP_X25519 0x001D
|
#define PAZE_TLS_GROUP_X25519 0x001D
|
||||||
|
|
||||||
/* 签名算法 (SignatureScheme) */
|
/* 签名算法 (SignatureScheme) */
|
||||||
#define PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256 0x0403
|
#define PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256 0x0403
|
||||||
|
#define PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384 0x0503
|
||||||
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256 0x0804
|
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA256 0x0804
|
||||||
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384 0x0805
|
#define PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384 0x0805
|
||||||
#define PAZE_TLS_SIG_RSA_PKCS1_SHA256 0x0401
|
#define PAZE_TLS_SIG_RSA_PKCS1_SHA256 0x0401
|
||||||
|
|||||||
+11
-2
@@ -33,7 +33,8 @@ extern "C" {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
PAZE_X509_PK_UNKNOWN = 0,
|
PAZE_X509_PK_UNKNOWN = 0,
|
||||||
PAZE_X509_PK_RSA = 1,
|
PAZE_X509_PK_RSA = 1,
|
||||||
PAZE_X509_PK_ECDSA_P256 = 2
|
PAZE_X509_PK_ECDSA_P256 = 2,
|
||||||
|
PAZE_X509_PK_ECDSA_P384 = 3
|
||||||
} paze_x509_pk_kind_t;
|
} paze_x509_pk_kind_t;
|
||||||
|
|
||||||
/* 证书签名算法 */
|
/* 证书签名算法 */
|
||||||
@@ -43,7 +44,8 @@ typedef enum {
|
|||||||
PAZE_X509_SIG_SHA256_RSA = 2,
|
PAZE_X509_SIG_SHA256_RSA = 2,
|
||||||
PAZE_X509_SIG_SHA384_RSA = 3,
|
PAZE_X509_SIG_SHA384_RSA = 3,
|
||||||
PAZE_X509_SIG_SHA512_RSA = 4,
|
PAZE_X509_SIG_SHA512_RSA = 4,
|
||||||
PAZE_X509_SIG_ECDSA_SHA256 = 5 /* P-256 */
|
PAZE_X509_SIG_ECDSA_SHA256 = 5, /* P-256 */
|
||||||
|
PAZE_X509_SIG_ECDSA_SHA384 = 6 /* P-384 */
|
||||||
} paze_x509_sig_alg_t;
|
} paze_x509_sig_alg_t;
|
||||||
|
|
||||||
#define PAZE_X509_SAN_MAX 8
|
#define PAZE_X509_SAN_MAX 8
|
||||||
@@ -65,6 +67,8 @@ typedef struct {
|
|||||||
paze_x509_pk_kind_t pk_kind; /* 主体公钥类型 */
|
paze_x509_pk_kind_t pk_kind; /* 主体公钥类型 */
|
||||||
paze_rsa_pub_t rsa_pub; /* pk_kind==RSA 时有效 */
|
paze_rsa_pub_t rsa_pub; /* pk_kind==RSA 时有效 */
|
||||||
paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */
|
paze_ecdsa_pub_t ecdsa_pub; /* pk_kind==ECDSA_P256 时有效 */
|
||||||
|
/* pk_kind==ECDSA_P384 时,主体公钥为未压缩点 0x04||X||Y (97 字节) */
|
||||||
|
uint8_t ecdsa_p384_pub[97];
|
||||||
|
|
||||||
/* 签名值(BIT STRING 内容,已去掉 unused-bits 前导 0x00) */
|
/* 签名值(BIT STRING 内容,已去掉 unused-bits 前导 0x00) */
|
||||||
const uint8_t *signature; size_t signature_len;
|
const uint8_t *signature; size_t signature_len;
|
||||||
@@ -133,6 +137,7 @@ typedef struct {
|
|||||||
paze_x509_pk_kind_t kind;
|
paze_x509_pk_kind_t kind;
|
||||||
paze_rsa_priv_t rsa; /* kind==RSA 时有效 */
|
paze_rsa_priv_t rsa; /* kind==RSA 时有效 */
|
||||||
uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */
|
uint8_t ecdsa_d[32]; /* kind==ECDSA_P256 时,私钥标量大端 */
|
||||||
|
uint8_t ecdsa_d384[48]; /* kind==ECDSA_P384 时,私钥标量大端 */
|
||||||
} paze_x509_signer_t;
|
} paze_x509_signer_t;
|
||||||
|
|
||||||
/* 构造 SubjectPublicKeyInfo DER。
|
/* 构造 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,
|
paze_x509_pk_kind_t kind,
|
||||||
const paze_rsa_pub_t *rsa_pub,
|
const paze_rsa_pub_t *rsa_pub,
|
||||||
const paze_ecdsa_pub_t *ec_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)。 */
|
/* 构造仅含 commonName 的 Name DER (UTF8String)。 */
|
||||||
paze_status_t paze_x509_build_dn_cn(uint8_t *out, size_t *outlen, const char *cn);
|
paze_status_t paze_x509_build_dn_cn(uint8_t *out, size_t *outlen, const char *cn);
|
||||||
|
|||||||
+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 重用漏洞。
|
* 签名:k 由 RFC 6979 从私钥与消息摘要确定性派生,避免 RNG 重用漏洞。
|
||||||
* 验签:标准 ECDSA,公式 v = (u1*G + u2*Q).x mod n == r。
|
* 验签:标准 ECDSA,公式 v = (u1*G + u2*Q).x mod n == r。
|
||||||
* 签名编码:DER SEQUENCE { r INTEGER, s INTEGER }。
|
* 签名编码: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/ecdsa.h"
|
||||||
|
#include "paze/p384.h"
|
||||||
#include "paze/hmac.h"
|
#include "paze/hmac.h"
|
||||||
#include "paze/hash.h"
|
#include "paze/hash.h"
|
||||||
#include "paze/asn1.h"
|
#include "paze/asn1.h"
|
||||||
@@ -23,97 +28,179 @@ static const paze_hash_alg_t *hash_alg_of(paze_rsa_hash_t h) {
|
|||||||
switch (h) {
|
switch (h) {
|
||||||
case PAZE_RSA_HASH_SHA1: return paze_hash_sha1();
|
case PAZE_RSA_HASH_SHA1: return paze_hash_sha1();
|
||||||
case PAZE_RSA_HASH_SHA256: return paze_hash_sha256();
|
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();
|
case PAZE_RSA_HASH_SHA512: return paze_hash_sha512();
|
||||||
default: return NULL; /* SHA-224/384 暂未实现 */
|
default: return NULL; /* SHA-224 暂未实现 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bits2int:取 input 左起 qlen_bits 位作为整数。
|
/* bits2int (RFC 6979 §2.3.2 / FIPS 186):取 input 左起 qlen_bits 位作为整数。
|
||||||
* - inlen*8 > qlen: 右移 (inlen*8 - qlen) 位(保留高位)
|
* - blen > qlen: 保留左侧高位(右移 blen - qlen 位)。
|
||||||
* - inlen*8 == qlen: 原值
|
* - blen <= qlen: 值即 input(左侧补零 = 右对齐),无需移位。
|
||||||
* - inlen*8 < qlen: 左移补零 */
|
* (blen < qlen 时绝不能左移:P-384 配 SHA-256 会得到错误 z。) */
|
||||||
static void bits2int(paze_bn_t *z, const uint8_t *in, size_t inlen, int qlen_bits) {
|
static void bits2int(paze_bn_t *z, const uint8_t *in, size_t inlen, int qlen_bits) {
|
||||||
paze_bn_from_bytes(z, in, inlen);
|
paze_bn_from_bytes(z, in, inlen);
|
||||||
int blen = (int)inlen * 8;
|
int blen = (int)inlen * 8;
|
||||||
if (blen > qlen_bits) {
|
if (blen > qlen_bits) {
|
||||||
paze_bn_rshift(z, z, 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) {
|
static void int2octets(uint8_t *out, size_t outlen, const paze_bn_t *x) {
|
||||||
paze_bn_to_bytes(x, out, outlen);
|
paze_bn_to_bytes(x, out, outlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* RFC 6979 确定性 k 生成
|
* 曲线抽象:p256 / p384 的差异点提取为这组小助手。
|
||||||
* 输入:私钥 d(标量), 消息摘要 h1(原始字节), 哈希算法
|
* 点(paze_bn_t X,Y,Z)两种曲线 ABI 相同,用 paze_bn_t[3] 承载。
|
||||||
* 输出:k (1 <= k < n),写入 k_be[32]
|
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|
||||||
static paze_status_t rfc6979_k(uint8_t k_be[32],
|
typedef enum { ECDSA_CURVE_P256, ECDSA_CURVE_P384 } curve_t;
|
||||||
const paze_bn_t *d,
|
|
||||||
|
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,
|
const uint8_t *h1, size_t h1len,
|
||||||
paze_rsa_hash_t hash_alg) {
|
paze_rsa_hash_t hash_alg) {
|
||||||
const paze_hash_alg_t *alg = hash_alg_of(hash_alg);
|
const paze_hash_alg_t *alg = hash_alg_of(hash_alg);
|
||||||
if (!alg) return PAZE_ERR_NOTSUP;
|
if (!alg) return PAZE_ERR_NOTSUP;
|
||||||
size_t hlen = alg->digest_len;
|
size_t hlen = alg->digest_len;
|
||||||
paze_bn_t n;
|
paze_bn_t n;
|
||||||
paze_p256_load_n(&n);
|
curve_load_n(c, &n);
|
||||||
int qlen_bits = paze_bn_bit_len(&n); /* 256 */
|
int qlen_bits = paze_bn_bit_len(&n);
|
||||||
|
int slen = curve_scalar_len(c);
|
||||||
|
|
||||||
/* int2octets(d): d < n,32 字节 */
|
/* int2octets(d): 直接拷贝已定长大端标量 */
|
||||||
uint8_t x_oct[32];
|
uint8_t x_oct[48];
|
||||||
int2octets(x_oct, 32, d);
|
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;
|
paze_bn_t z1, z2;
|
||||||
bits2int(&z1, h1, h1len, qlen_bits);
|
bits2int(&z1, h1, h1len, qlen_bits);
|
||||||
paze_bn_mod(&z2, &z1, &n);
|
paze_bn_mod(&z2, &z1, &n);
|
||||||
uint8_t h1_oct[32];
|
uint8_t h1_oct[48];
|
||||||
int2octets(h1_oct, 32, &z2);
|
int2octets(h1_oct, (size_t)slen, &z2);
|
||||||
|
|
||||||
/* V = 0x01 * hlen, K = 0x00 * hlen */
|
/* V = 0x01 * hlen, K = 0x00 * hlen */
|
||||||
uint8_t V[64], K[64];
|
uint8_t V[64], K[64];
|
||||||
memset(V, 0x01, hlen);
|
memset(V, 0x01, hlen);
|
||||||
memset(K, 0x00, hlen);
|
memset(K, 0x00, hlen);
|
||||||
|
|
||||||
uint8_t buf[64 + 1 + 32 + 32];
|
uint8_t buf[64 + 1 + 48 + 48];
|
||||||
uint8_t T[64];
|
uint8_t T[64];
|
||||||
|
|
||||||
/* K = HMAC_K(V || 0x00 || x || h1_oct) */
|
/* K = HMAC_K(V || 0x00 || x || h1_oct) */
|
||||||
memcpy(buf, V, hlen); buf[hlen] = 0x00;
|
memcpy(buf, V, hlen); buf[hlen] = 0x00;
|
||||||
memcpy(buf + hlen + 1, x_oct, 32);
|
memcpy(buf + hlen + 1, x_oct, (size_t)slen);
|
||||||
memcpy(buf + hlen + 1 + 32, h1_oct, 32);
|
memcpy(buf + hlen + 1 + slen, h1_oct, (size_t)slen);
|
||||||
paze_hmac(alg, K, hlen, buf, hlen + 1 + 32 + 32, K);
|
paze_hmac(alg, K, hlen, buf, hlen + 1 + (size_t)slen + (size_t)slen, K);
|
||||||
paze_hmac(alg, K, hlen, V, hlen, V); /* V = HMAC_K(V) */
|
paze_hmac(alg, K, hlen, V, hlen, V);
|
||||||
|
|
||||||
/* K = HMAC_K(V || 0x01 || x || h1_oct); V = HMAC_K(V) */
|
/* K = HMAC_K(V || 0x01 || x || h1_oct); V = HMAC_K(V) */
|
||||||
memcpy(buf, V, hlen); buf[hlen] = 0x01;
|
memcpy(buf, V, hlen); buf[hlen] = 0x01;
|
||||||
memcpy(buf + hlen + 1, x_oct, 32);
|
memcpy(buf + hlen + 1, x_oct, (size_t)slen);
|
||||||
memcpy(buf + hlen + 1 + 32, h1_oct, 32);
|
memcpy(buf + hlen + 1 + slen, h1_oct, (size_t)slen);
|
||||||
paze_hmac(alg, K, hlen, buf, hlen + 1 + 32 + 32, K);
|
paze_hmac(alg, K, hlen, buf, hlen + 1 + (size_t)slen + (size_t)slen, K);
|
||||||
paze_hmac(alg, K, hlen, V, hlen, V);
|
paze_hmac(alg, K, hlen, V, hlen, V);
|
||||||
|
|
||||||
/* 循环生成 k */
|
/* 循环生成 k */
|
||||||
for (int retry = 0; retry < 256; retry++) {
|
for (int retry = 0; retry < 256; retry++) {
|
||||||
/* T = empty; while len(T) < qlen: V = HMAC_K(V); T = T||V */
|
|
||||||
size_t tlen = 0;
|
size_t tlen = 0;
|
||||||
while (tlen < (size_t)(qlen_bits + 7) / 8) {
|
while (tlen < (size_t)(qlen_bits + 7) / 8) {
|
||||||
paze_hmac(alg, K, hlen, V, hlen, V);
|
paze_hmac(alg, K, hlen, V, hlen, V);
|
||||||
memcpy(T + tlen, V, hlen);
|
memcpy(T + tlen, V, hlen);
|
||||||
tlen += hlen;
|
tlen += hlen;
|
||||||
}
|
}
|
||||||
/* k = bits2int(T) */
|
|
||||||
paze_bn_t k;
|
paze_bn_t k;
|
||||||
bits2int(&k, T, tlen, qlen_bits);
|
bits2int(&k, T, tlen, qlen_bits);
|
||||||
if (!paze_bn_is_zero(&k) && paze_bn_cmp(&k, &n) < 0) {
|
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;
|
return PAZE_OK;
|
||||||
}
|
}
|
||||||
/* 否则 K = HMAC_K(V || 0x00); V = HMAC_K(V) */
|
|
||||||
memcpy(buf, V, hlen); buf[hlen] = 0x00;
|
memcpy(buf, V, hlen); buf[hlen] = 0x00;
|
||||||
paze_hmac(alg, K, hlen, buf, hlen + 1, K);
|
paze_hmac(alg, K, hlen, buf, hlen + 1, K);
|
||||||
paze_hmac(alg, K, hlen, V, hlen, V);
|
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]) {
|
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_status_t paze_ecdsa_gen(paze_ecdsa_priv_t *k) {
|
||||||
paze_bn_t n, d;
|
paze_bn_t n, d;
|
||||||
paze_p256_load_n(&n);
|
paze_p256_load_n(&n);
|
||||||
/* 生成 [1, n-1] 随机 d */
|
|
||||||
do {
|
do {
|
||||||
paze_bn_random_range(&d, &n);
|
paze_bn_random_range(&d, &n);
|
||||||
} while (paze_bn_is_zero(&d));
|
} 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(curve_t c,
|
||||||
static paze_status_t ecdsa_sign_internal(const paze_ecdsa_priv_t *k,
|
const uint8_t *d_be,
|
||||||
paze_rsa_hash_t hash_alg,
|
paze_rsa_hash_t hash_alg,
|
||||||
const uint8_t *mhash, size_t hlen,
|
const uint8_t *mhash, size_t hlen,
|
||||||
paze_bn_t *r_out, paze_bn_t *s_out) {
|
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 (!hash_alg_of(hash_alg)) return PAZE_ERR_NOTSUP;
|
||||||
if (hlen != paze_rsa_hash_len(hash_alg)) return PAZE_ERR_INVALID;
|
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_bn_t n, d, z;
|
||||||
paze_p256_load_n(&n);
|
curve_load_n(c, &n);
|
||||||
paze_bn_from_bytes(&d, k->d, 32);
|
paze_bn_from_bytes(&d, d_be, (size_t)slen);
|
||||||
/* z = bits2int(mhash) */
|
|
||||||
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
|
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
|
||||||
|
|
||||||
paze_bn_t r, s;
|
paze_bn_t r, s;
|
||||||
uint8_t k_be[32];
|
uint8_t k_be[48];
|
||||||
paze_status_t rc;
|
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;
|
int got = 0;
|
||||||
for (int round = 0; round < 8 && !got; round++) {
|
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;
|
if (rc != PAZE_OK) return rc;
|
||||||
|
|
||||||
paze_p256_point_t Rpt;
|
paze_bn_t Rpt[3];
|
||||||
paze_p256_scalar_mult(&Rpt, k_be, NULL); /* R = k*G */
|
paze_status_t st = curve_point_mult(c, Rpt, k_be, NULL); /* R = k*G */
|
||||||
if (paze_p256_is_inf(&Rpt)) continue;
|
if (st != PAZE_OK) return st;
|
||||||
paze_p256_get_x_mod_n(&r, &Rpt);
|
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;
|
if (paze_bn_is_zero(&r)) continue;
|
||||||
|
|
||||||
/* s = k^-1 (z + r*d) mod n */
|
/* s = k^-1 (z + r*d) mod n */
|
||||||
paze_bn_t k_bn, rd, sum, kinv;
|
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_modmul(&rd, &r, &d, &n);
|
||||||
paze_bn_modadd(&sum, &z, &rd, &n);
|
paze_bn_modadd(&sum, &z, &rd, &n);
|
||||||
paze_bn_modinv(&kinv, &k_bn, &n);
|
paze_bn_modinv(&kinv, &k_bn, &n);
|
||||||
paze_bn_modmul(&s, &kinv, &sum, &n);
|
paze_bn_modmul(&s, &kinv, &sum, &n);
|
||||||
if (paze_bn_is_zero(&s)) continue;
|
if (paze_bn_is_zero(&s)) continue;
|
||||||
|
|
||||||
/* low-s 归一化:s > n/2 则 s = n - s (减少签名可延展性) */
|
/* low-s 归一化 */
|
||||||
paze_bn_t half_n;
|
paze_bn_t half_n;
|
||||||
paze_bn_rshift(&half_n, &n, 1);
|
paze_bn_rshift(&half_n, &n, 1);
|
||||||
if (paze_bn_cmp(&s, &half_n) > 0) {
|
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) {
|
uint8_t *sig, size_t *siglen) {
|
||||||
if (!sig || !siglen) return PAZE_ERR_INVALID;
|
if (!sig || !siglen) return PAZE_ERR_INVALID;
|
||||||
paze_bn_t r, s;
|
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;
|
if (rc != PAZE_OK) return rc;
|
||||||
return paze_ecdsa_sig_to_der(&r, &s, sig, siglen);
|
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(curve_t c,
|
||||||
static paze_status_t ecdsa_verify_internal(const paze_ecdsa_pub_t *pub,
|
const uint8_t *pub_affine,
|
||||||
paze_rsa_hash_t hash_alg,
|
paze_rsa_hash_t hash_alg,
|
||||||
const uint8_t *mhash, size_t hlen,
|
const uint8_t *mhash, size_t hlen,
|
||||||
const paze_bn_t *r, const paze_bn_t *s) {
|
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 (!hash_alg_of(hash_alg)) return PAZE_ERR_NOTSUP;
|
||||||
if (hlen != paze_rsa_hash_len(hash_alg)) return PAZE_ERR_INVALID;
|
if (hlen != paze_rsa_hash_len(hash_alg)) return PAZE_ERR_INVALID;
|
||||||
|
|
||||||
paze_bn_t n;
|
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_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;
|
if (paze_bn_cmp(r, &n) >= 0 || paze_bn_cmp(s, &n) >= 0) return PAZE_ERR_VERIFY;
|
||||||
|
|
||||||
/* z = bits2int(mhash) */
|
|
||||||
paze_bn_t z;
|
paze_bn_t z;
|
||||||
bits2int(&z, mhash, hlen, paze_bn_bit_len(&n));
|
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_t w, u1, u2;
|
||||||
paze_bn_modinv(&w, s, &n);
|
paze_bn_modinv(&w, s, &n);
|
||||||
paze_bn_modmul(&u1, &z, &w, &n);
|
paze_bn_modmul(&u1, &z, &w, &n);
|
||||||
paze_bn_modmul(&u2, r, &w, &n);
|
paze_bn_modmul(&u2, r, &w, &n);
|
||||||
|
|
||||||
/* 点1 = u1*G; 点2 = u2*Q; R = 点1 + 点2 */
|
int slen = curve_scalar_len(c);
|
||||||
uint8_t u1_be[32], u2_be[32];
|
uint8_t u1_be[48], u2_be[48];
|
||||||
paze_bn_to_bytes(&u1, u1_be, 32);
|
int2octets(u1_be, (size_t)slen, &u1);
|
||||||
paze_bn_to_bytes(&u2, u2_be, 32);
|
int2octets(u2_be, (size_t)slen, &u2);
|
||||||
|
|
||||||
paze_p256_point_t P1, P2, Rpt;
|
paze_bn_t Q[3];
|
||||||
paze_p256_scalar_mult(&P1, u1_be, NULL); /* u1 * G */
|
if (curve_point_from_affine(c, Q, pub_affine, (size_t)curve_pub_len(c)) != PAZE_OK)
|
||||||
paze_p256_scalar_mult(&P2, u2_be, &pub->Q); /* u2 * Q */
|
return PAZE_ERR_VERIFY;
|
||||||
paze_p256_add(&Rpt, &P1, &P2);
|
|
||||||
|
|
||||||
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_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;
|
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;
|
if (!sig) return PAZE_ERR_INVALID;
|
||||||
paze_bn_t r, s;
|
paze_bn_t r, s;
|
||||||
if (paze_ecdsa_sig_from_der(&r, &s, sig, siglen) != PAZE_OK) return PAZE_ERR_FORMAT;
|
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,
|
static paze_status_t ecdsa_priv_parse_der(paze_ecdsa_priv_t *k,
|
||||||
const uint8_t *der, size_t len) {
|
const uint8_t *der, size_t len) {
|
||||||
if (!k || !der) return PAZE_ERR_INVALID;
|
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);
|
paze_asn1_r_init(&r, der, len);
|
||||||
if (paze_asn1_enter_seq(&r, &body) != PAZE_OK) return PAZE_ERR_FORMAT;
|
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;
|
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 (paze_asn1_read_tl(&body, &tag, &b, &blen) != PAZE_OK) return PAZE_ERR_FORMAT;
|
||||||
if (tag != ASN1_INTEGER) 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 (paze_asn1_read_tl(&body, &tag, &b, &blen) != PAZE_OK) return PAZE_ERR_FORMAT;
|
||||||
if (tag != ASN1_OCTETSTRING || blen != 32) return PAZE_ERR_FORMAT;
|
if (tag != ASN1_OCTETSTRING || blen != 32) return PAZE_ERR_FORMAT;
|
||||||
memcpy(k->d, b, 32);
|
memcpy(k->d, b, 32);
|
||||||
|
|
||||||
/* 尝试读可选参数 */
|
|
||||||
if (!paze_asn1_at_end(&body)) {
|
if (!paze_asn1_at_end(&body)) {
|
||||||
paze_asn1_read_tl(&body, &tag, &b, &blen);
|
paze_asn1_read_tl(&body, &tag, &b, &blen);
|
||||||
if (tag == ASN1_CTX0) {
|
if (tag == ASN1_CTX0) {
|
||||||
/* parameters [0]: 跳过(假设就是 P-256 OID) */
|
|
||||||
if (!paze_asn1_at_end(&body)) {
|
if (!paze_asn1_at_end(&body)) {
|
||||||
paze_asn1_read_tl(&body, &tag, &b, &blen);
|
paze_asn1_read_tl(&body, &tag, &b, &blen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 尝试读可选 publicKey [1] BIT STRING */
|
|
||||||
if (tag == ASN1_CTX1 && blen >= 1 && b[0] == 0x00) {
|
if (tag == ASN1_CTX1 && blen >= 1 && b[0] == 0x00) {
|
||||||
const uint8_t *pk = b + 1;
|
const uint8_t *pk = b + 1;
|
||||||
size_t pklen = blen - 1;
|
size_t pklen = blen - 1;
|
||||||
if (pklen == 65 && pk[0] == 0x04) {
|
if (pklen == 65 && pk[0] == 0x04) {
|
||||||
/* 使用嵌入的公钥点 */
|
|
||||||
paze_p256_from_affine(&k->Q, pk, 65);
|
paze_p256_from_affine(&k->Q, pk, 65);
|
||||||
return PAZE_OK;
|
return PAZE_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 无公钥:从私钥推导 Q = d*G */
|
|
||||||
paze_p256_scalar_mult(&k->Q, k->d, NULL);
|
paze_p256_scalar_mult(&k->Q, k->d, NULL);
|
||||||
return PAZE_OK;
|
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;
|
if (!pub || !pem_text) return PAZE_ERR_INVALID;
|
||||||
memset(pub, 0, sizeof(*pub));
|
memset(pub, 0, sizeof(*pub));
|
||||||
size_t dlen = 0;
|
size_t dlen = 0;
|
||||||
/* PUBLIC KEY = X.509 SPKI 格式 */
|
|
||||||
uint8_t *der = paze_pem_decode(pem_text, "PUBLIC KEY", &dlen);
|
uint8_t *der = paze_pem_decode(pem_text, "PUBLIC KEY", &dlen);
|
||||||
if (!der) return PAZE_ERR_FORMAT;
|
if (!der) return PAZE_ERR_FORMAT;
|
||||||
|
|
||||||
/* 解析 X.509 SPKI: SEQUENCE { AlgorithmIdentifier, BIT STRING } */
|
|
||||||
paze_asn1_reader_t r, spki;
|
paze_asn1_reader_t r, spki;
|
||||||
paze_asn1_r_init(&r, der, dlen);
|
paze_asn1_r_init(&r, der, dlen);
|
||||||
paze_status_t st = paze_asn1_enter_seq(&r, &spki);
|
paze_status_t st = paze_asn1_enter_seq(&r, &spki);
|
||||||
if (st != PAZE_OK) { free(der); return PAZE_ERR_FORMAT; }
|
if (st != PAZE_OK) { free(der); return PAZE_ERR_FORMAT; }
|
||||||
|
|
||||||
/* 跳过 AlgorithmIdentifier */
|
|
||||||
uint8_t tag; const uint8_t *b; size_t blen;
|
uint8_t tag; const uint8_t *b; size_t blen;
|
||||||
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
|
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
|
||||||
if (st != PAZE_OK) { free(der); return PAZE_ERR_FORMAT; }
|
if (st != PAZE_OK || tag != ASN1_SEQUENCE) { free(der); return PAZE_ERR_FORMAT; }
|
||||||
if (tag != ASN1_SEQUENCE) { free(der); return PAZE_ERR_FORMAT; }
|
|
||||||
/* spki now points past the SEQUENCE content */
|
|
||||||
|
|
||||||
/* BIT STRING */
|
|
||||||
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
|
st = paze_asn1_read_tl(&spki, &tag, &b, &blen);
|
||||||
if (st != PAZE_OK || tag != ASN1_BITSTRING || blen < 2) {
|
if (st != PAZE_OK || tag != ASN1_BITSTRING || blen < 2) { free(der); return PAZE_ERR_FORMAT; }
|
||||||
free(der); return PAZE_ERR_FORMAT;
|
|
||||||
}
|
|
||||||
if (b[0] != 0x00) { free(der); return PAZE_ERR_FORMAT; }
|
if (b[0] != 0x00) { free(der); return PAZE_ERR_FORMAT; }
|
||||||
const uint8_t *pk = b + 1;
|
const uint8_t *pk = b + 1;
|
||||||
size_t pklen = blen - 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);
|
free(der);
|
||||||
return st;
|
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。
|
* RFC 5280 仅允许 Z 时区。转 Unix 秒用 Howard Hinnant days_from_civil。
|
||||||
*/
|
*/
|
||||||
#include "paze/x509.h"
|
#include "paze/x509.h"
|
||||||
|
#include "paze/p384.h"
|
||||||
#include "paze/asn1.h"
|
#include "paze/asn1.h"
|
||||||
#include "paze/encoding.h"
|
#include "paze/encoding.h"
|
||||||
#include "paze/hash.h"
|
#include "paze/hash.h"
|
||||||
@@ -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_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_EC_PUBKEY[] = {0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01};
|
||||||
static const uint8_t OID_ECDSA_SHA256[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02};
|
static const uint8_t OID_ECDSA_SHA256[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02};
|
||||||
|
static const uint8_t OID_ECDSA_SHA384[]= {0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03};
|
||||||
static const uint8_t OID_P256[] = {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07};
|
static const uint8_t OID_P256[] = {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07};
|
||||||
|
static const uint8_t OID_P384[] = {0x2B,0x81,0x04,0x00,0x22};
|
||||||
static const uint8_t OID_SAN[] = {0x55,0x1D,0x11};
|
static const uint8_t OID_SAN[] = {0x55,0x1D,0x11};
|
||||||
|
|
||||||
static int oid_eq(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen) {
|
static int oid_eq(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen) {
|
||||||
@@ -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_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_SHA512_RSA,9)) return PAZE_X509_SIG_SHA512_RSA;
|
||||||
if (oid_eq(o,n,OID_ECDSA_SHA256,8))return PAZE_X509_SIG_ECDSA_SHA256;
|
if (oid_eq(o,n,OID_ECDSA_SHA256,8))return PAZE_X509_SIG_ECDSA_SHA256;
|
||||||
|
if (oid_eq(o,n,OID_ECDSA_SHA384,8))return PAZE_X509_SIG_ECDSA_SHA384;
|
||||||
return PAZE_X509_SIG_UNKNOWN;
|
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 */
|
return paze_rsa_pub_from_der(&cert->rsa_pub, pk, pklen); /* RSAPublicKey */
|
||||||
}
|
}
|
||||||
if (oid_eq(oid, olen, OID_EC_PUBKEY, sizeof(OID_EC_PUBKEY))) {
|
if (oid_eq(oid, olen, OID_EC_PUBKEY, sizeof(OID_EC_PUBKEY))) {
|
||||||
/* 参数须为 prime256v1 OID */
|
/* 参数须为 prime256v1 / secp384r1 OID */
|
||||||
if (plen == 0) return PAZE_ERR_FORMAT;
|
if (plen == 0) return PAZE_ERR_FORMAT;
|
||||||
paze_asn1_reader_t pr; paze_asn1_r_init(&pr, param, plen);
|
paze_asn1_reader_t pr; paze_asn1_r_init(&pr, param, plen);
|
||||||
uint8_t t2; const uint8_t *b2; size_t l2;
|
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 (paze_asn1_read_tl(&pr, &t2, &b2, &l2) != PAZE_OK) return PAZE_ERR_FORMAT;
|
||||||
if (t2 != ASN1_OID) 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 (oid_eq(b2, l2, OID_P256, sizeof(OID_P256))) {
|
||||||
if (pklen != 65 || pk[0] != 0x04) return PAZE_ERR_FORMAT;
|
if (pklen != 65 || pk[0] != 0x04) return PAZE_ERR_FORMAT;
|
||||||
cert->pk_kind = PAZE_X509_PK_ECDSA_P256;
|
cert->pk_kind = PAZE_X509_PK_ECDSA_P256;
|
||||||
return paze_p256_from_affine(&cert->ecdsa_pub.Q, pk, 65);
|
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;
|
return PAZE_ERR_NOTSUP;
|
||||||
}
|
}
|
||||||
@@ -399,9 +414,22 @@ paze_status_t paze_x509_verify_signature(const paze_x509_cert_t *cert,
|
|||||||
break;
|
break;
|
||||||
case PAZE_X509_SIG_ECDSA_SHA256:
|
case PAZE_X509_SIG_ECDSA_SHA256:
|
||||||
if (paze_sha256(cert->tbs_der, cert->tbs_der_len, hash) != PAZE_OK) return PAZE_ERR;
|
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;
|
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_P256)
|
||||||
return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA256,
|
return paze_ecdsa_verify(&issuer->ecdsa_pub, PAZE_RSA_HASH_SHA256,
|
||||||
hash, 32, cert->signature, cert->signature_len);
|
hash, 32, cert->signature, cert->signature_len);
|
||||||
|
if (issuer->pk_kind == PAZE_X509_PK_ECDSA_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:
|
default:
|
||||||
return PAZE_ERR_NOTSUP;
|
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;
|
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=相等 */
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,6 +706,38 @@ done:
|
|||||||
return st;
|
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,
|
paze_status_t paze_x509_sign_cert(uint8_t *out, size_t *outlen,
|
||||||
const uint8_t *subject_spki, size_t spki_len,
|
const uint8_t *subject_spki, size_t spki_len,
|
||||||
const uint8_t *subject_dn, size_t subj_len,
|
const uint8_t *subject_dn, size_t subj_len,
|
||||||
@@ -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;
|
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) {
|
} 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;
|
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;
|
} else return PAZE_ERR_INVALID;
|
||||||
|
|
||||||
char nb[32], na[32];
|
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);
|
paze_asn1_w_free(&tbs);
|
||||||
if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; }
|
if (st != PAZE_OK) { paze_asn1_w_free(&tbsfull); return st; }
|
||||||
|
|
||||||
/* SHA-256(tbs) */
|
/* 签名(曲线决定哈希:P-256→SHA-256, P-384→SHA-384) */
|
||||||
uint8_t hsh[32];
|
|
||||||
paze_sha256(tbsfull.buf, tbsfull.len, hsh);
|
|
||||||
|
|
||||||
/* 签名 */
|
|
||||||
uint8_t sig[4096];
|
uint8_t sig[4096];
|
||||||
size_t sig_len = sizeof(sig);
|
size_t sig_len = sizeof(sig);
|
||||||
if (issuer_priv->kind == PAZE_X509_PK_RSA) {
|
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);
|
sig_len = paze_rsa_modulus_len(&issuer_priv->rsa.n);
|
||||||
if (sig_len > sizeof(sig)) { paze_asn1_w_free(&tbsfull); return PAZE_ERR_OVERFLOW; }
|
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);
|
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_t ek;
|
||||||
paze_ecdsa_priv_set_d(&ek, issuer_priv->ecdsa_d);
|
paze_ecdsa_priv_set_d(&ek, issuer_priv->ecdsa_d);
|
||||||
st = paze_ecdsa_sign(&ek, PAZE_RSA_HASH_SHA256, hsh, 32, sig, &sig_len);
|
st = paze_ecdsa_sign(&ek, PAZE_RSA_HASH_SHA256, hsh, 32, sig, &sig_len);
|
||||||
|
} else { /* P-384 */
|
||||||
|
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; }
|
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_t epub;
|
||||||
paze_ecdsa_pub_from_priv(&epub, priv->ecdsa_d);
|
paze_ecdsa_pub_from_priv(&epub, priv->ecdsa_d);
|
||||||
st = paze_x509_build_spki(spki, &sl, PAZE_X509_PK_ECDSA_P256, NULL, &epub);
|
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;
|
} else return PAZE_ERR_INVALID;
|
||||||
if (st != PAZE_OK) return st;
|
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) {
|
paze_status_t paze_tls_config_set_kex_group(paze_tls_config_t *cfg, uint16_t group) {
|
||||||
if (!cfg) return PAZE_ERR_INVALID;
|
if (!cfg) return PAZE_ERR_INVALID;
|
||||||
if (group != PAZE_TLS_GROUP_X25519 && group != PAZE_TLS_GROUP_SECP256R1)
|
if (group != PAZE_TLS_GROUP_X25519 && group != PAZE_TLS_GROUP_SECP256R1 &&
|
||||||
|
group != PAZE_TLS_GROUP_SECP384R1)
|
||||||
return PAZE_ERR_INVALID;
|
return PAZE_ERR_INVALID;
|
||||||
cfg->kex_group = group;
|
cfg->kex_group = group;
|
||||||
return PAZE_OK;
|
return PAZE_OK;
|
||||||
@@ -136,6 +137,20 @@ static paze_status_t build_cert_chain_from_pem(const char *cert_pem,
|
|||||||
return PAZE_OK;
|
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,
|
paze_status_t paze_tls_config_set_cert_chain(paze_tls_config_t *cfg,
|
||||||
const char *cert_pem,
|
const char *cert_pem,
|
||||||
const char *privkey_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);
|
free(cfg->cert_der);
|
||||||
cfg->cert_der = der; cfg->cert_der_len = dlen;
|
cfg->cert_der = der; cfg->cert_der_len = dlen;
|
||||||
|
|
||||||
/* 解析私钥:支持 RSA PKCS#1 和 ECDSA P-256 */
|
/* 解析私钥:支持 RSA PKCS#1、ECDSA P-256 与 ECDSA P-384 */
|
||||||
if (strstr(privkey_pem, "RSA PRIVATE KEY")) {
|
if (strstr(privkey_pem, "RSA PRIVATE KEY")) {
|
||||||
cfg->privkey.kind = PAZE_X509_PK_RSA;
|
cfg->privkey.kind = PAZE_X509_PK_RSA;
|
||||||
return paze_rsa_priv_from_pem(&cfg->privkey.rsa, privkey_pem);
|
return paze_rsa_priv_from_pem(&cfg->privkey.rsa, privkey_pem);
|
||||||
}
|
}
|
||||||
if (strstr(privkey_pem, "EC PRIVATE KEY")) {
|
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_ecdsa_priv_t ek;
|
||||||
paze_status_t ps = paze_ecdsa_priv_from_pem(&ek, privkey_pem);
|
paze_status_t ps = paze_ecdsa_priv_from_pem(&ek, privkey_pem);
|
||||||
if (ps != PAZE_OK) return ps;
|
if (ps == PAZE_OK) {
|
||||||
memcpy(cfg->privkey.ecdsa_d, ek.d, 32);
|
cfg->privkey.kind = PAZE_X509_PK_ECDSA_P256;
|
||||||
return PAZE_OK;
|
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")) {
|
if (strstr(privkey_pem, "PRIVATE KEY")) {
|
||||||
return PAZE_ERR_NOTSUP; /* PKCS#8 暂不支持 */
|
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) {
|
size_t paze_tls_ext_write_supported_groups(uint8_t *buf) {
|
||||||
uint8_t *p = buf + 4;
|
uint8_t *p = buf + 4;
|
||||||
p[0] = 0; p[1] = 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 + 2, PAZE_TLS_GROUP_X25519);
|
||||||
paze_store16_be(p + 4, PAZE_TLS_GROUP_SECP256R1);
|
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;
|
return put_ext_header(buf, PAZE_TLS_EXT_SUPPORTED_GROUPS, body) + body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 解析 supported_groups:
|
/* 解析 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) {
|
uint16_t paze_tls_ext_parse_supported_groups(const uint8_t *data, size_t len) {
|
||||||
if (len < 2) return 0;
|
if (len < 2) return 0;
|
||||||
size_t ll = paze_load16_be(data);
|
size_t ll = paze_load16_be(data);
|
||||||
if (len != 2 + ll || (ll & 1)) return 0;
|
if (len != 2 + ll || (ll & 1)) return 0;
|
||||||
int have_x25519 = 0, have_p256 = 0;
|
int have_x25519 = 0, have_p256 = 0, have_p384 = 0;
|
||||||
for (size_t i = 0; i < ll; i += 2) {
|
for (size_t i = 0; i < ll; i += 2) {
|
||||||
uint16_t g = paze_load16_be(data + 2 + i);
|
uint16_t g = paze_load16_be(data + 2 + i);
|
||||||
if (g == PAZE_TLS_GROUP_X25519) have_x25519 = 1;
|
if (g == PAZE_TLS_GROUP_X25519) have_x25519 = 1;
|
||||||
if (g == PAZE_TLS_GROUP_SECP256R1) have_p256 = 1;
|
if (g == PAZE_TLS_GROUP_SECP256R1) have_p256 = 1;
|
||||||
|
if (g == PAZE_TLS_GROUP_SECP384R1) have_p384 = 1;
|
||||||
}
|
}
|
||||||
if (have_x25519) return PAZE_TLS_GROUP_X25519;
|
if (have_x25519) return PAZE_TLS_GROUP_X25519;
|
||||||
if (have_p256) return PAZE_TLS_GROUP_SECP256R1;
|
if (have_p256) return PAZE_TLS_GROUP_SECP256R1;
|
||||||
|
if (have_p384) return PAZE_TLS_GROUP_SECP384R1;
|
||||||
return 0;
|
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_SHA256,
|
||||||
PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384,
|
PAZE_TLS_SIG_RSA_PSS_RSAE_SHA384,
|
||||||
PAZE_TLS_SIG_RSA_PKCS1_SHA256,
|
PAZE_TLS_SIG_RSA_PKCS1_SHA256,
|
||||||
PAZE_TLS_SIG_RSA_PKCS1_SHA384
|
PAZE_TLS_SIG_RSA_PKCS1_SHA384,
|
||||||
|
PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384
|
||||||
};
|
};
|
||||||
int n = sizeof(algs)/sizeof(algs[0]);
|
int n = sizeof(algs)/sizeof(algs[0]);
|
||||||
uint16_t ll = (uint16_t)(n * 2);
|
uint16_t ll = (uint16_t)(n * 2);
|
||||||
@@ -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;
|
paze_store16_be(p, 65); p += 2;
|
||||||
memcpy(p, kex->p256_pub, 65); p += 65;
|
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 可写 */
|
if (p == s + 2) return 0; /* 无 share 可写 */
|
||||||
bodylen = (size_t)(p - s);
|
bodylen = (size_t)(p - s);
|
||||||
paze_store16_be(s, (uint16_t)(bodylen - 2)); /* client_shares 长度 */
|
paze_store16_be(s, (uint16_t)(bodylen - 2)); /* client_shares 长度 */
|
||||||
|
|||||||
@@ -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];
|
size_t cl = ((size_t)body[p] << 16) | ((size_t)body[p+1] << 8) | body[p+2];
|
||||||
p += 3;
|
p += 3;
|
||||||
if (blen < p + cl) return PAZE_ERR_FORMAT;
|
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;
|
if (st != PAZE_OK) return PAZE_ERR_FORMAT;
|
||||||
tls->peer_chain_len++; i++; p += cl;
|
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;
|
const uint8_t *pub; size_t plen;
|
||||||
if (tls->neg.group == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; }
|
if (tls->neg.group == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; }
|
||||||
else if (tls->neg.group == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; }
|
else if (tls->neg.group == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; }
|
||||||
|
else if (tls->neg.group == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; }
|
||||||
else { paze_tls_set_err(tls, "1.2 group %04x not supported", tls->neg.group); return PAZE_ERR_NOTSUP; }
|
else { paze_tls_set_err(tls, "1.2 group %04x not supported", tls->neg.group); return PAZE_ERR_NOTSUP; }
|
||||||
if (1 + plen > 128) return PAZE_ERR_OVERFLOW;
|
if (1 + plen > 128) return PAZE_ERR_OVERFLOW;
|
||||||
out[0] = (uint8_t)plen; /* RFC 5246 §7.4.7:ECDHE point 用 1 字节长度 */
|
out[0] = (uint8_t)plen; /* RFC 5246 §7.4.7:ECDHE point 用 1 字节长度 */
|
||||||
@@ -606,6 +607,7 @@ static paze_status_t tls12_server_build_ske(paze_tls_t *tls,
|
|||||||
const uint8_t *pub; size_t plen;
|
const uint8_t *pub; size_t plen;
|
||||||
if (nc == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; }
|
if (nc == PAZE_TLS_GROUP_X25519) { pub = tls->kex.x25519_pub; plen = 32; }
|
||||||
else if (nc == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; }
|
else if (nc == PAZE_TLS_GROUP_SECP256R1) { pub = tls->kex.p256_pub; plen = 65; }
|
||||||
|
else if (nc == PAZE_TLS_GROUP_SECP384R1) { pub = tls->kex.p384_pub; plen = 97; }
|
||||||
else return PAZE_ERR_NOTSUP;
|
else return PAZE_ERR_NOTSUP;
|
||||||
|
|
||||||
out[0] = 0x03;
|
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;
|
tls->neg.group = ex.group ? ex.group : PAZE_TLS_GROUP_SECP256R1;
|
||||||
if (tls12_is_ecdhe(cipher)) {
|
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;
|
if (st != PAZE_OK) return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
-9
@@ -9,6 +9,7 @@
|
|||||||
* 所有 C++ lambda 已转为静态 C 回调函数。
|
* 所有 C++ lambda 已转为静态 C 回调函数。
|
||||||
*/
|
*/
|
||||||
#include "tls_internal.h"
|
#include "tls_internal.h"
|
||||||
|
#include "paze/p384.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.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_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_status_t paze_tls_kex_generate(paze_tls_kex_t *kex, uint16_t group_hint) {
|
||||||
paze_memzero(kex, sizeof(*kex));
|
paze_memzero(kex, sizeof(*kex));
|
||||||
int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1);
|
int prefer_p256 = (group_hint == PAZE_TLS_GROUP_SECP256R1);
|
||||||
|
int prefer_p384 = (group_hint == PAZE_TLS_GROUP_SECP384R1);
|
||||||
int only_x = (group_hint == PAZE_TLS_GROUP_X25519);
|
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) {
|
if (only_x) {
|
||||||
/* 仅生成 X25519 密钥对(其余清零) */
|
/* 仅生成 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;
|
if (paze_x25519_public(kex->x25519_pub, kex->x25519_priv) != 0) return PAZE_ERR;
|
||||||
return PAZE_OK;
|
return PAZE_OK;
|
||||||
}
|
}
|
||||||
|
if (prefer_p384) {
|
||||||
|
return paze_tls_kex_gen_p384(kex);
|
||||||
|
}
|
||||||
if (prefer_p256) {
|
if (prefer_p256) {
|
||||||
/* 仅生成 P-256 密钥对 */
|
/* 仅生成 P-256 密钥对 */
|
||||||
return paze_tls_kex_gen_p256(kex);
|
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;
|
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,
|
paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group,
|
||||||
const uint8_t *peer_pub, size_t peer_pub_len,
|
const uint8_t *peer_pub, size_t peer_pub_len,
|
||||||
uint8_t *shared_out, size_t *shared_len) {
|
uint8_t *shared_out, size_t *shared_len) {
|
||||||
@@ -85,6 +109,29 @@ paze_status_t paze_tls_kex_ecdh(paze_tls_kex_t *mine, uint16_t server_group,
|
|||||||
*shared_len = 32;
|
*shared_len = 32;
|
||||||
return PAZE_OK;
|
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;
|
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;
|
*sig_alg = PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256;
|
||||||
return PAZE_OK;
|
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;
|
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;
|
paze_rsa_hash_t rh = PAZE_RSA_HASH_SHA256;
|
||||||
switch (sig_alg) {
|
switch (sig_alg) {
|
||||||
case PAZE_TLS_SIG_RSA_PSS_RSAE_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_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_SHA256: rh = PAZE_RSA_HASH_SHA256; break;
|
||||||
case PAZE_TLS_SIG_RSA_PKCS1_SHA384: rh = PAZE_RSA_HASH_SHA384; break;
|
case PAZE_TLS_SIG_RSA_PKCS1_SHA384: rh = PAZE_RSA_HASH_SHA384; break;
|
||||||
case PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256: rh = PAZE_RSA_HASH_SHA256; break;
|
case PAZE_TLS_SIG_ECDSA_SECP256R1_SHA256: rh = PAZE_RSA_HASH_SHA256; break;
|
||||||
|
case PAZE_TLS_SIG_ECDSA_SECP384R1_SHA384: rh = PAZE_RSA_HASH_SHA384; break;
|
||||||
default: return PAZE_ERR_NOTSUP;
|
default: return PAZE_ERR_NOTSUP;
|
||||||
}
|
}
|
||||||
uint8_t h[64]; size_t hl = 0;
|
uint8_t h[64]; size_t hl = 0;
|
||||||
@@ -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) */
|
/* 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);
|
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;
|
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");
|
paze_tls_set_err(tls, "HRR missing required ext");
|
||||||
return PAZE_ERR_PROTOCOL;
|
return PAZE_ERR_PROTOCOL;
|
||||||
}
|
}
|
||||||
if (hx.g != PAZE_TLS_GROUP_X25519 && hx.g != PAZE_TLS_GROUP_SECP256R1) {
|
if (hx.g != PAZE_TLS_GROUP_X25519 && hx.g != PAZE_TLS_GROUP_SECP256R1 &&
|
||||||
|
hx.g != PAZE_TLS_GROUP_SECP384R1) {
|
||||||
paze_tls_set_err(tls, "HRR selected unsupported group %d", hx.g);
|
paze_tls_set_err(tls, "HRR selected unsupported group %d", hx.g);
|
||||||
return PAZE_ERR_NOTSUP;
|
return PAZE_ERR_NOTSUP;
|
||||||
}
|
}
|
||||||
@@ -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];
|
size_t cl = ((size_t)body[p] << 16) | ((size_t)body[p+1] << 8) | body[p+2];
|
||||||
p += 3;
|
p += 3;
|
||||||
if (blen < p + cl) return PAZE_ERR_FORMAT;
|
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;
|
if (st != PAZE_OK) return PAZE_ERR_FORMAT;
|
||||||
tls->peer_chain_len++; i++; p += cl;
|
tls->peer_chain_len++; i++; p += cl;
|
||||||
if (tls->neg.version == PAZE_TLS_VERSION_1_3) {
|
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 (have_share) {
|
||||||
if (select_group == PAZE_TLS_GROUP_X25519)
|
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);
|
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);
|
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;
|
sp += n;
|
||||||
}
|
}
|
||||||
if (tls->psk_mode) {
|
if (tls->psk_mode) {
|
||||||
|
|||||||
+13
-2
@@ -75,7 +75,8 @@ typedef struct {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
PAZE_KEX_NONE = 0,
|
PAZE_KEX_NONE = 0,
|
||||||
PAZE_KEX_X25519,
|
PAZE_KEX_X25519,
|
||||||
PAZE_KEX_P256
|
PAZE_KEX_P256,
|
||||||
|
PAZE_KEX_P384
|
||||||
} paze_tls_kex_kind_t;
|
} paze_tls_kex_kind_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -86,6 +87,9 @@ typedef struct {
|
|||||||
/* P-256 */
|
/* P-256 */
|
||||||
uint8_t p256_priv[32];
|
uint8_t p256_priv[32];
|
||||||
uint8_t p256_pub[65]; /* 0x04||X||Y */
|
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;
|
} paze_tls_kex_t;
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -139,7 +143,8 @@ struct paze_tls_config {
|
|||||||
/* 0-RTT: 客户端启用(服务端默认接受,1=接受) */
|
/* 0-RTT: 客户端启用(服务端默认接受,1=接受) */
|
||||||
int enable_early;
|
int enable_early;
|
||||||
/* 客户端 key_share 限制:0=默认(X25519 优先);
|
/* 客户端 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;
|
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,
|
const uint8_t *peer_pub, size_t peer_pub_len,
|
||||||
uint8_t *shared_out, size_t *shared_len);
|
uint8_t *shared_out, size_t *shared_len);
|
||||||
|
|
||||||
|
/* 解析对端证书 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 调用) */
|
/* 1.3 握手 (由 tls_client/tls_server 调用) */
|
||||||
paze_status_t paze_tls13_client_handshake(paze_tls_t *tls);
|
paze_status_t paze_tls13_client_handshake(paze_tls_t *tls);
|
||||||
paze_status_t paze_tls13_server_handshake(paze_tls_t *tls);
|
paze_status_t paze_tls13_server_handshake(paze_tls_t *tls);
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户