HRR/0-RTT 基础设施: 内部字段、early_data 扩展、key_share 单组模式与 early traffic key 派生; 修复 key_share_client 参数不匹配编译错误; STATUS 命令表改为独立命令名

这个提交包含在:
JGZYES
2026-08-13 22:13:55 +08:00
父节点 5c5517821f
当前提交 bdf98f9d7b
修改 5 个文件,包含 108 行新增20 行删除
+8 -8
查看文件
@@ -58,14 +58,14 @@
| OpenSSH | PazeSSH | 说明 | | OpenSSH | PazeSSH | 说明 |
|---|---|---| |---|---|---|
| `ssh` | `pssh` / `pssh ssh` | 远程 shell / 执行命令 / 端口转发 | | `ssh` | `pssh` | 远程 shell / 执行命令 / 端口转发 |
| `scp` | `pssh scp` | SFTP 优先 + legacy SCP 回退 | | `scp` | `pscp` | SFTP 优先 + legacy SCP 回退 |
| `sftp` | `pssh sshd` 子系统 | 服务端 SFTP v3,互操作通过 | | `sftp` | `psftp` | 独立 SFTP 客户端;服务端为 `psshd` 子系统 |
| `ssh-keygen` | `pssh keygen` | ed25519/rsa/ecdsa | | `ssh-keygen` | `pkeygen` | ed25519/rsa/ecdsa |
| `ssh-keyscan` | `pssh keyscan` | known_hosts 格式 | | `ssh-keyscan` | `pkeyscan` | known_hosts 格式 |
| `ssh-copy-id` | `pssh copy-id` | 安装公钥 | | `ssh-copy-id` | `pcopy-id` | 安装公钥 |
| `ssh-agent` / `ssh-add` | `pssh agent` / `add` | agent 密钥管理 | | `ssh-agent` / `ssh-add` | `pagent` / `padd` | agent 密钥管理 |
| `sshd` | `pssh sshd` | 多用户 + 权限 + 公钥认证 + SFTP | | `sshd` | `psshd` | 多用户 + 权限 + 公钥认证 + SFTP |
## 遗留项(已知) ## 遗留项(已知)
+26 -6
查看文件
@@ -120,7 +120,8 @@ size_t paze_tls_ext_write_signature_algorithms(uint8_t *buf) {
/* ============================================================ /* ============================================================
* key_share (client: 多 share; server: 单 share; HelloRetryRequest: 单 selected_group) * key_share (client: 多 share; server: 单 share; HelloRetryRequest: 单 selected_group)
* ============================================================ */ * ============================================================ */
size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *kex) { size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *kex,
uint16_t only_group) {
uint8_t *p = buf + 4; uint8_t *p = buf + 4;
uint8_t *s = p; uint8_t *s = p;
size_t bodylen = 0; size_t bodylen = 0;
@@ -128,19 +129,23 @@ size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *k
if (kex->kind == PAZE_KEX_NONE) return 0; /* 至少 1 个 share */ if (kex->kind == PAZE_KEX_NONE) return 0; /* 至少 1 个 share */
/* HRR 后(only_group != 0):只发指定组的 share(RFC 8446 §4.1.4)。
* 否则按 kind 全量发送(首次 CH:尽可能避免 HRR 往返)。 */
if (only_group == PAZE_TLS_GROUP_X25519 ||
(only_group == 0 && (kex->kind == PAZE_KEX_X25519 || kex->kind == PAZE_KEX_P256))) {
/* X25519 share */ /* X25519 share */
if (kex->kind == PAZE_KEX_X25519 || kex->kind == PAZE_KEX_P256) {
/* 先写 X25519 */
paze_store16_be(p, PAZE_TLS_GROUP_X25519); p += 2; paze_store16_be(p, PAZE_TLS_GROUP_X25519); p += 2;
paze_store16_be(p, 32); p += 2; paze_store16_be(p, 32); p += 2;
memcpy(p, kex->x25519_pub, 32); p += 32; memcpy(p, kex->x25519_pub, 32); p += 32;
/* 如存在 P-256,也写上(备选) */ }
if (kex->kind == PAZE_KEX_P256) { if (only_group == PAZE_TLS_GROUP_SECP256R1 ||
(only_group == 0 && kex->kind == PAZE_KEX_P256)) {
/* P-256 share(仅 kind==P256 或 HRR 选定组时) */
paze_store16_be(p, PAZE_TLS_GROUP_SECP256R1); p += 2; paze_store16_be(p, PAZE_TLS_GROUP_SECP256R1); p += 2;
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 (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 长度 */
return put_ext_header(buf, PAZE_TLS_EXT_KEY_SHARE, bodylen) + bodylen; return put_ext_header(buf, PAZE_TLS_EXT_KEY_SHARE, bodylen) + bodylen;
@@ -279,6 +284,21 @@ size_t paze_tls_ext_write_renegotiation_info(uint8_t *buf) {
return put_ext_header(buf, PAZE_TLS_EXT_RENEGOTIATION_INFO, body) + body; return put_ext_header(buf, PAZE_TLS_EXT_RENEGOTIATION_INFO, body) + body;
} }
/* ============================================================
* early_data (RFC 8446 §4.2.10)
* ClientHello: 空 body(声明客户端支持 0-RTT)
* EncryptedExtensions: 空 body(服务端接受 0-RTT)
* ============================================================ */
size_t paze_tls_ext_write_early_data(uint8_t *buf) {
return put_ext_header(buf, PAZE_TLS_EXT_EARLY_DATA, 0);
}
/* 解析 early_data 扩展:存在即返回 1(body 应为空,不校验) */
int paze_tls_ext_parse_early_data(const uint8_t *data, size_t len) {
(void)data; (void)len;
return 1;
}
/* ============================================================ /* ============================================================
* PSK 会话恢复扩展 (RFC 8446 §4.2.11) * PSK 会话恢复扩展 (RFC 8446 §4.2.11)
* ============================================================ */ * ============================================================ */
+1 -1
查看文件
@@ -162,7 +162,7 @@ paze_status_t paze_tls13_build_ch(paze_tls_t *tls, uint8_t *out, size_t *outlen)
n = paze_tls_ext_write_supported_versions(p, 1, cfg->enable_1_3, cfg->enable_1_2); p += n; n = paze_tls_ext_write_supported_versions(p, 1, cfg->enable_1_3, cfg->enable_1_2); p += n;
n = paze_tls_ext_write_supported_groups(p); p += n; n = paze_tls_ext_write_supported_groups(p); p += n;
n = paze_tls_ext_write_signature_algorithms(p); p += n; n = paze_tls_ext_write_signature_algorithms(p); p += n;
n = paze_tls_ext_write_key_share_client(p, &tls->kex); n = paze_tls_ext_write_key_share_client(p, &tls->kex, tls->had_hrr ? tls->hrr_group : 0);
if (n == 0) return PAZE_ERR_INVALID; if (n == 0) return PAZE_ERR_INVALID;
p += n; p += n;
n = paze_tls_ext_write_sni(p, cfg->sni); p += n; n = paze_tls_ext_write_sni(p, cfg->sni); p += n;
+32 -1
查看文件
@@ -129,6 +129,9 @@ struct paze_tls_config {
* */ * */
uint8_t ticket_key[32]; uint8_t ticket_key[32];
int ticket_key_ready; int ticket_key_ready;
/* 0-RTT: 客户端启用(服务端默认接受,1=接受) */
int enable_early;
}; };
/* ============================================================ /* ============================================================
@@ -245,6 +248,26 @@ struct paze_tls {
uint8_t *ch1; size_t ch1_len; uint8_t *ch1; size_t ch1_len;
int hello_retry; int hello_retry;
/* HRR(HelloRetryRequest,RFC 8446 §4.1.3/§4.1.4) */
uint8_t *hrr_raw; size_t hrr_raw_len; /* 服务端发送的 / 客户端收到的 HRR 原始 */
uint8_t *ch2; size_t ch2_len; /* 客户端 HRR 后发送的 ClientHello2 原始 */
int had_hrr; /* 本次握手是否发生 HRR */
uint16_t hrr_group; /* HRR 选择的组 */
int sent_hrr; /* 服务端已发送 HRR(等待 CH2) */
/* 0-RTT 状态(RFC 8446 §4.2.10/§4.5) */
int early_offer; /* 客户端 CH 携带 early_data 扩展 */
int early_sent; /* 客户端已发送 0-RTT 数据 */
int early_accepted; /* 服务端 EE 含 early_data(客户端视角) */
int early_accept; /* 服务端接受 0-RTT(服务端视角) */
paze_tls_traffic_key_t early_read;
paze_tls_traffic_key_t early_write;
int early_read_valid;
int early_write_valid;
uint8_t early_buf[2048]; /* 服务端收到的 0-RTT 数据(握手完成后交应用) */
size_t early_len;
size_t early_off;
/* 客户端:TLS 1.2 回退时保存的 ServerHello 原始消息 */ /* 客户端:TLS 1.2 回退时保存的 ServerHello 原始消息 */
uint8_t *sh1; size_t sh1_len; uint8_t *sh1; size_t sh1_len;
@@ -328,6 +351,11 @@ paze_status_t paze_tls_derive_secret(const paze_hash_alg_t *alg,
paze_status_t paze_tls13_derive_handshake_keys(paze_tls_t *tls, paze_status_t paze_tls13_derive_handshake_keys(paze_tls_t *tls,
const uint8_t *shared, size_t shared_len); const uint8_t *shared, size_t shared_len);
paze_status_t paze_tls13_derive_app_keys(paze_tls_t *tls); paze_status_t paze_tls13_derive_app_keys(paze_tls_t *tls);
/* 0-RTT early traffic key:
* client: early_secret + hash(CH) "c e traffic" early_write
* server: early_read
* is_client ;aead / */
paze_status_t paze_tls13_derive_early_key(paze_tls_t *tls, int is_client);
/* 由 traffic secret 派生 traffic key 对象 */ /* 由 traffic secret 派生 traffic key 对象 */
paze_status_t paze_tls13_make_traffic_key(paze_tls_traffic_key_t *tk, paze_status_t paze_tls13_make_traffic_key(paze_tls_traffic_key_t *tk,
const paze_hash_alg_t *alg, const paze_hash_alg_t *alg,
@@ -367,10 +395,13 @@ paze_status_t paze_tls12_prf(const paze_hash_alg_t *alg,
size_t paze_tls_ext_write_supported_versions(uint8_t *buf, int is_client, int v13, int v12); size_t paze_tls_ext_write_supported_versions(uint8_t *buf, int is_client, int v13, int v12);
size_t paze_tls_ext_write_supported_groups(uint8_t *buf); size_t paze_tls_ext_write_supported_groups(uint8_t *buf);
size_t paze_tls_ext_write_signature_algorithms(uint8_t *buf); size_t paze_tls_ext_write_signature_algorithms(uint8_t *buf);
size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *kex); size_t paze_tls_ext_write_key_share_client(uint8_t *buf, const paze_tls_kex_t *kex,
uint16_t only_group);
size_t paze_tls_ext_write_sni(uint8_t *buf, const char *host); size_t paze_tls_ext_write_sni(uint8_t *buf, const char *host);
size_t paze_tls_ext_write_alpn(uint8_t *buf, char *const *alpn, int n); size_t paze_tls_ext_write_alpn(uint8_t *buf, char *const *alpn, int n);
size_t paze_tls_ext_write_renegotiation_info(uint8_t *buf); size_t paze_tls_ext_write_renegotiation_info(uint8_t *buf);
size_t paze_tls_ext_write_early_data(uint8_t *buf);
int paze_tls_ext_parse_early_data(const uint8_t *data, size_t len);
/* 服务端:构造 key_share 扩展(单 group) */ /* 服务端:构造 key_share 扩展(单 group) */
size_t paze_tls_ext_write_key_share_server(uint8_t *buf, uint16_t group, size_t paze_tls_ext_write_key_share_server(uint8_t *buf, uint16_t group,
+37
查看文件
@@ -243,6 +243,43 @@ paze_status_t paze_tls13_psk_early_secret(paze_tls_t *tls,
return paze_tls_derive_secret(H, tls->early_secret, hl, "res binder", NULL, tls->binder_key); return paze_tls_derive_secret(H, tls->early_secret, hl, "res binder", NULL, tls->binder_key);
} }
/* 0-RTT early traffic key (RFC 8446 §7.1):
* client_early_traffic_secret = Derive-Secret(early_secret, "c e traffic", hash(CH))
* client early_write;server early_read
* hash PSK hash;transcript "最终 ClientHello"(,
* early_secret hash transcript hash)
* aead tls->neg.aead() */
paze_status_t paze_tls13_derive_early_key(paze_tls_t *tls, int is_client) {
const paze_hash_alg_t *H = psk_hash_of(tls->psk_hash);
size_t hl = H->digest_len;
const uint8_t *ch = tls->ch1 ? tls->ch1 : NULL;
size_t chl = tls->ch1 ? tls->ch1_len : 0;
/* HRR 后:early key 基于最终 ClientHello(本实现 HRR 时客户端放弃 0-RTT,
* CH2 ch1 CH1;) */
if (tls->had_hrr && tls->ch2 && is_client == 0) { ch = tls->ch2; chl = tls->ch2_len; }
if (!ch || chl == 0) return PAZE_ERR_PROTOCOL;
uint8_t th[64];
if (H->digest_len == 48) paze_sha384(ch, chl, th);
else paze_sha256(ch, chl, th);
uint8_t c_e[64];
paze_status_t st = paze_tls_hkdf_expand_label(H, tls->early_secret, hl,
"c e traffic", th, hl, c_e, hl);
if (st != PAZE_OK) return st;
/* 客户端在收到 ServerHello 前派生:aead 用 CH 首选套件(1301 → AES-128-GCM) */
paze_tls_aead_kind_t aead = tls->neg.aead;
if (is_client && aead == PAZE_AEAD_NONE) aead = PAZE_AEAD_AES_128_GCM;
st = paze_tls13_make_traffic_key(is_client ? &tls->early_write : &tls->early_read,
H, c_e, hl, aead);
paze_memzero(c_e, hl);
if (st == PAZE_OK) {
if (is_client) tls->early_write_valid = 1;
else tls->early_read_valid = 1;
}
return st;
}
/* binder = HMAC(binder_key, transcript_hash); 输出长度 = H->digest_len */ /* binder = HMAC(binder_key, transcript_hash); 输出长度 = H->digest_len */
paze_status_t paze_tls13_compute_binder(paze_tls_t *tls, paze_status_t paze_tls13_compute_binder(paze_tls_t *tls,
const uint8_t *tr_hash, size_t tr_hash_len, const uint8_t *tr_hash, size_t tr_hash_len,