文件
PazeSSH/src/ssl/tls_conn.c
T
JGZYES 3e8a5442fa 实现 TLS 1.3 PSK 会话恢复,构建输出移至 bin/ 并新增 standalone/psftp 命令
TLS 1.3 PSK 会话恢复: NewSessionTicket 签发/解析、ticket+binder 校验、selected_identity 回选、恢复握手免证书(pazessl -sess_in/-sess_out 端到端验证); 构建脚本输出 bin/ 并支持独立命令与 psftp; 修复 SFTP 二进制传输与 copy_id -P; 补充 tests/ 调试与 verify_tls
2026-08-13 19:30:07 +08:00

485 行
18 KiB
C

/* tls_conn.c —— PazeSSL 高层 API: 配置 + 连接对象生命周期 + 应用数据读写
*
* 同时包含 tls_client/tls_server 握手入口(版本协商:先尝试 1.3,失败则回退 1.2)。
* TLS 1.2 回退状态机在 tls_handshake12.c 中实现。
*/
#include "tls_internal.h"
#include "paze/encoding.h"
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifndef strdup
#ifdef _WIN32
#define strdup _strdup
#endif
#endif
/* ============================================================
* 配置
* ============================================================ */
paze_tls_config_t *paze_tls_config_new(paze_tls_role_t role) {
paze_tls_config_t *c = (paze_tls_config_t *)calloc(1, sizeof(*c));
if (!c) return NULL;
c->role = role;
c->enable_1_3 = 1;
c->enable_1_2 = 1;
c->verify_mode = PAZE_TLS_VERIFY_REQUIRED;
return c;
}
void paze_tls_config_free(paze_tls_config_t *cfg) {
if (!cfg) return;
for (int i = 0; i < cfg->alpn_count; i++) free(cfg->alpn[i]);
if (cfg->cert_der) free(cfg->cert_der);
if (cfg->anchors) {
for (int i = 0; i < cfg->anchor_count; i++) paze_x509_free(&cfg->anchors[i]);
free(cfg->anchors);
}
if (cfg->anchors_owned) free(cfg->anchors_owned);
/* 私钥:rsa 大数字段由 calloc 内存清零后释放即可(不持 malloc) */
free(cfg);
}
paze_status_t paze_tls_config_set_sni(paze_tls_config_t *cfg, const char *host) {
if (!cfg || !host) return PAZE_ERR_INVALID;
size_t n = strlen(host);
if (n > PAZE_TLS_SNI_MAX) return PAZE_ERR_OVERFLOW;
memcpy(cfg->sni, host, n); cfg->sni[n] = '\0';
return PAZE_OK;
}
paze_status_t paze_tls_config_set_alpn(paze_tls_config_t *cfg, const char *const *alpn, int n) {
if (!cfg || !alpn || n <= 0 || n > PAZE_TLS_MAX_ALPN) return PAZE_ERR_INVALID;
for (int i = 0; i < n; i++) {
cfg->alpn[i] = strdup(alpn[i]);
if (!cfg->alpn[i]) return PAZE_ERR_NOMEM;
}
cfg->alpn_count = n;
return PAZE_OK;
}
/* 由证书 PEM 文本构造证书链(CertificateEntry 序列)。
* 支持多张证书串联:依次拼接 [3字节长度前缀 + DER]。
* 返回 malloc 的缓冲区,*outlen 为长度。 */
static paze_status_t build_cert_chain_from_pem(const char *cert_pem,
uint8_t **out, size_t *outlen) {
/* 统计证书数量 */
int count = 0;
const char *p = cert_pem;
while ((p = strstr(p, "-----BEGIN CERTIFICATE-----")) != NULL) {
count++; p++;
}
if (count == 0) return PAZE_ERR_FORMAT;
/* 分配缓冲区:每张证书 3 + DER 长度 */
size_t alloc = 16384;
uint8_t *buf = (uint8_t *)malloc(alloc);
if (!buf) return PAZE_ERR_NOMEM;
size_t total = 0;
/* 逐张解析 */
const char *rest = cert_pem;
for (int i = 0; i < count; i++) {
const char *b = strstr(rest, "-----BEGIN CERTIFICATE-----");
if (!b) break;
const char *e = strstr(b, "-----END CERTIFICATE-----");
if (!e) break;
e += strlen("-----END CERTIFICATE-----");
/* 提取本张 PEM 文本 */
size_t blklen = (size_t)(e - b);
char *blk = (char *)malloc(blklen + 1);
if (!blk) { free(buf); return PAZE_ERR_NOMEM; }
memcpy(blk, b, blklen);
blk[blklen] = '\0';
size_t dlen = 0;
uint8_t *der = paze_pem_decode(blk, "CERTIFICATE", &dlen);
free(blk);
if (!der) { free(buf); return PAZE_ERR_FORMAT; }
/* 扩容 */
if (total + 3 + dlen > alloc) {
alloc = (total + 3 + dlen) * 2;
uint8_t *nb = (uint8_t *)realloc(buf, alloc);
if (!nb) { free(der); free(buf); return PAZE_ERR_NOMEM; }
buf = nb;
}
buf[total] = (uint8_t)(dlen >> 16);
buf[total + 1] = (uint8_t)(dlen >> 8);
buf[total + 2] = (uint8_t)(dlen);
memcpy(buf + total + 3, der, dlen);
total += 3 + dlen;
free(der);
rest = e;
}
*out = buf; *outlen = total;
return PAZE_OK;
}
paze_status_t paze_tls_config_set_cert_chain(paze_tls_config_t *cfg,
const char *cert_pem,
const char *privkey_pem) {
if (!cfg || !cert_pem || !privkey_pem) return PAZE_ERR_INVALID;
uint8_t *der = NULL; size_t dlen = 0;
paze_status_t st = build_cert_chain_from_pem(cert_pem, &der, &dlen);
if (st != PAZE_OK) return st;
free(cfg->cert_der);
cfg->cert_der = der; cfg->cert_der_len = dlen;
/* 解析私钥:支持 RSA PKCS#1 和 ECDSA P-256 */
if (strstr(privkey_pem, "RSA PRIVATE KEY")) {
cfg->privkey.kind = PAZE_X509_PK_RSA;
return paze_rsa_priv_from_pem(&cfg->privkey.rsa, privkey_pem);
}
if (strstr(privkey_pem, "EC PRIVATE KEY")) {
cfg->privkey.kind = PAZE_X509_PK_ECDSA_P256;
paze_ecdsa_priv_t ek;
paze_status_t ps = paze_ecdsa_priv_from_pem(&ek, privkey_pem);
if (ps != PAZE_OK) return ps;
memcpy(cfg->privkey.ecdsa_d, ek.d, 32);
return PAZE_OK;
}
if (strstr(privkey_pem, "PRIVATE KEY")) {
return PAZE_ERR_NOTSUP; /* PKCS#8 暂不支持 */
}
return PAZE_ERR_NOTSUP;
}
paze_status_t paze_tls_config_set_trust_roots(paze_tls_config_t *cfg,
const char *roots_pem) {
if (!cfg || !roots_pem) return PAZE_ERR_INVALID;
/* 统计证书数量 */
int count = 0;
const char *p = roots_pem;
while ((p = strstr(p, "-----BEGIN CERTIFICATE-----")) != NULL) {
count++; p++;
}
if (count == 0) return PAZE_ERR_FORMAT;
paze_x509_cert_t *roots = (paze_x509_cert_t *)calloc((size_t)count, sizeof(paze_x509_cert_t));
if (!roots) return PAZE_ERR_NOMEM;
const char *rest = roots_pem;
int loaded = 0;
for (int i = 0; i < count; i++) {
const char *b = strstr(rest, "-----BEGIN CERTIFICATE-----");
if (!b) break;
const char *e = strstr(b, "-----END CERTIFICATE-----");
if (!e) break;
e += strlen("-----END CERTIFICATE-----");
size_t blklen = (size_t)(e - b);
char *blk = (char *)malloc(blklen + 1);
if (!blk) { free(roots); return PAZE_ERR_NOMEM; }
memcpy(blk, b, blklen);
blk[blklen] = '\0';
paze_status_t st = paze_x509_load_pem(&roots[loaded], blk);
free(blk);
if (st == PAZE_OK) loaded++;
rest = e;
}
if (loaded == 0) { free(roots); return PAZE_ERR_FORMAT; }
if (cfg->anchors) {
for (int i = 0; i < cfg->anchor_count; i++) paze_x509_free(&cfg->anchors[i]);
free(cfg->anchors);
}
cfg->anchors = roots; cfg->anchor_count = loaded;
return PAZE_OK;
}
paze_status_t paze_tls_config_set_verify(paze_tls_config_t *cfg,
paze_tls_verify_mode_t mode,
paze_tls_verify_cb cb, void *ctx) {
if (!cfg) return PAZE_ERR_INVALID;
cfg->verify_mode = mode;
cfg->verify_cb = cb;
cfg->verify_ctx = ctx;
return PAZE_OK;
}
paze_status_t paze_tls_config_set_versions(paze_tls_config_t *cfg,
int enable_1_3, int enable_1_2) {
if (!cfg) return PAZE_ERR_INVALID;
cfg->enable_1_3 = enable_1_3 ? 1 : 0;
cfg->enable_1_2 = enable_1_2 ? 1 : 0;
return PAZE_OK;
}
/* ============================================================
* TLS 1.3 PSK 会话恢复公开 API
* ============================================================ */
paze_status_t paze_tls_config_set_session(paze_tls_config_t *cfg,
const paze_tls_session_t *sess) {
if (!cfg || !sess) return PAZE_ERR_INVALID;
if (sess->valid && (sess->ticket_len == 0 || sess->ticket_len > sizeof(sess->ticket) ||
sess->psk_len == 0 || sess->psk_len > sizeof(sess->psk)))
return PAZE_ERR_INVALID;
cfg->session = *sess; /* 值拷贝 */
return PAZE_OK;
}
/* 握手后获取服务端下发的会话(客户端在收到 NewSessionTicket 后有效)。
* 未收到 ticket 或非 1.3 时返回 valid=0。 */
paze_status_t paze_tls_get_session(const paze_tls_t *tls, paze_tls_session_t *sess) {
if (!tls || !sess) return PAZE_ERR_INVALID;
memset(sess, 0, sizeof(*sess));
if (tls->neg.version != PAZE_TLS_VERSION_1_3 || !tls->have_ticket ||
tls->recv_ticket_len == 0 || tls->psk_len == 0)
return PAZE_OK;
if (tls->recv_ticket_len > sizeof(sess->ticket) || tls->psk_len > sizeof(sess->psk))
return PAZE_OK;
memcpy(sess->ticket, tls->recv_ticket, tls->recv_ticket_len);
sess->ticket_len = tls->recv_ticket_len;
memcpy(sess->psk, tls->psk, tls->psk_len);
sess->psk_len = tls->psk_len;
sess->age_add = tls->ticket_age_add;
sess->recv_time = tls->ticket_recv_time;
sess->hash = tls->psk_hash;
sess->valid = 1;
return PAZE_OK;
}
/* 本次握手是否通过 PSK 会话恢复(客户端/服务端均适用) */
int paze_tls_session_resumed(const paze_tls_t *tls) {
return tls ? (tls->psk_mode && tls->handshake_done) : 0;
}
/* 服务端:导出 session ticket key(位于 cfg,cfg_owned 在 paze_tls_new 时拷贝) */
paze_status_t paze_tls_get_session_ticket_key(const paze_tls_t *tls,
uint8_t key[32], int *ready) {
if (!tls || !key || !ready) return PAZE_ERR_INVALID;
paze_tls_config_t *cfg = tls->cfg_owned ? tls->cfg_owned : (paze_tls_config_t *)tls->cfg;
*ready = cfg->ticket_key_ready;
if (cfg->ticket_key_ready) memcpy(key, cfg->ticket_key, 32);
return PAZE_OK;
}
paze_status_t paze_tls_config_set_session_ticket_key(paze_tls_config_t *cfg,
const uint8_t key[32]) {
if (!cfg || !key) return PAZE_ERR_INVALID;
memcpy(cfg->ticket_key, key, 32);
cfg->ticket_key_ready = 1;
return PAZE_OK;
}
/* ============================================================
* 连接对象
* ============================================================ */
paze_tls_t *paze_tls_new(const paze_tls_config_t *cfg) {
if (!cfg) return NULL;
paze_tls_t *t = (paze_tls_t *)calloc(1, sizeof(*t));
if (!t) return NULL;
/* 配置深拷贝(配置对象是用户的,但连接需独立拥有,避免悬挂) */
t->cfg_owned = paze_tls_config_new(cfg->role);
if (!t->cfg_owned) { free(t); return NULL; }
*t->cfg_owned = *cfg; /* struct 拷贝(指针浅拷贝,所以需要重分配 alpn/cert/anchors) */
t->cfg_owned->alpn_count = 0;
for (int i = 0; i < cfg->alpn_count; i++) {
t->cfg_owned->alpn[i] = strdup(cfg->alpn[i] ? cfg->alpn[i] : "");
if (t->cfg_owned->alpn[i]) t->cfg_owned->alpn_count++;
}
if (cfg->cert_der && cfg->cert_der_len) {
t->cfg_owned->cert_der = (uint8_t *)malloc(cfg->cert_der_len);
if (t->cfg_owned->cert_der) {
memcpy(t->cfg_owned->cert_der, cfg->cert_der, cfg->cert_der_len);
t->cfg_owned->cert_der_len = cfg->cert_der_len;
}
}
/* private key:struct 赋值即可(bignum 不持 malloc) */
t->cfg_owned->privkey = cfg->privkey;
/* anchors: 不深拷贝(共享指针,要求用户 cfg 寿命 ≥ tls) */
t->cfg_owned->anchors = cfg->anchors;
t->cfg_owned->anchor_count = cfg->anchor_count;
t->cfg = t->cfg_owned;
t->role = cfg->role;
t->hs_state = PAZE_HS_INIT;
return t;
}
void paze_tls_free(paze_tls_t *tls) {
if (!tls) return;
for (int i = 0; i < tls->peer_chain_len; i++) paze_x509_free(&tls->peer_chain[i]);
/* traffic keys:aes 字段不持外部资源 */
paze_memzero(&tls->handshake_secret, sizeof(tls->handshake_secret));
paze_memzero(&tls->master_secret, sizeof(tls->master_secret));
paze_tls_config_free(tls->cfg_owned);
free(tls->ch1);
free(tls->sh1);
paze_memzero(tls, sizeof(*tls));
free(tls);
}
paze_status_t paze_tls_set_bio(paze_tls_t *tls, paze_tls_bio_t bio) {
if (!tls) return PAZE_ERR_INVALID;
tls->bio = bio;
return PAZE_OK;
}
/* ============================================================
* 握手入口(版本协商:先 1.3 → 失败返回 NOTSUP → 尝试 1.2)
* ============================================================ */
paze_status_t paze_tls_handshake(paze_tls_t *tls) {
if (!tls || !tls->bio.read || !tls->bio.write) return PAZE_ERR_INVALID;
paze_tls_config_t *cfg = tls->cfg_owned;
/* 若已完成 */
if (tls->handshake_done) return PAZE_OK;
if (cfg->enable_1_3) {
paze_status_t st;
if (cfg->role == PAZE_TLS_CLIENT) {
st = paze_tls13_client_handshake(tls);
} else {
st = paze_tls13_server_handshake(tls);
}
if (st == PAZE_OK) return PAZE_OK;
if (st != PAZE_ERR_NOTSUP) return st;
/* 1.3 不可用 → 回退 1.2 */
if (!cfg->enable_1_2) return st;
}
if (cfg->enable_1_2) {
/* 1.2 实现(tls_handshake12.c) */
if (cfg->role == PAZE_TLS_CLIENT)
return paze_tls12_client_handshake(tls);
else
return paze_tls12_server_handshake(tls);
}
return PAZE_ERR_NOTSUP;
}
/* ============================================================
* 应用数据读写
* ============================================================ */
int paze_tls_read(paze_tls_t *tls, uint8_t *buf, size_t len) {
if (!tls || !buf || len == 0) return PAZE_ERR_INVALID;
/* 先消费 app_buf 中已有的未读明文 */
if (tls->app_off < tls->app_len) {
size_t n = len < tls->app_len - tls->app_off ? len : tls->app_len - tls->app_off;
memcpy(buf, tls->app_buf + tls->app_off, n);
tls->app_off += n;
return (int)n;
}
for (;;) {
const uint8_t *data; size_t n; uint8_t ct;
paze_status_t st = paze_tls_record_read(tls, &data, &n, &ct);
if (st != PAZE_OK) {
if (st == PAZE_ERR_VERIFY) {
/* bad record MAC: 发 alert */
uint8_t al[2] = { PAZE_TLS_ALERT_FATAL, PAZE_TLS_ALERT_BAD_RECORD_MAC };
paze_tls_record_send(tls, PAZE_TLS_CT_ALERT, al, 2);
}
if (st == PAZE_ERR_IO && tls->close_recv) return 0;
return -1;
}
if (ct == PAZE_TLS_CT_APPLICATION_DATA) {
size_t take = len < n ? len : n;
memcpy(buf, data, take);
/* 剩余缓冲到 app_buf */
if (take < n) {
size_t rem = n - take;
if (rem > sizeof(tls->app_buf)) rem = sizeof(tls->app_buf);
memcpy(tls->app_buf, data + take, rem);
tls->app_len = rem; tls->app_off = 0;
}
return (int)take;
}
if (ct == PAZE_TLS_CT_ALERT) {
if (n >= 2) {
if (data[1] == PAZE_TLS_ALERT_CLOSE_NOTIFY) {
tls->close_recv = 1;
/* 回复 close_notify */
if (!tls->close_sent) {
uint8_t al[2] = { PAZE_TLS_ALERT_WARNING, PAZE_TLS_ALERT_CLOSE_NOTIFY };
paze_tls_record_send(tls, PAZE_TLS_CT_ALERT, al, 2);
tls->close_sent = 1;
}
return 0;
}
paze_tls_set_err(tls, "recv fatal alert %d", data[1]);
return -1;
}
continue;
}
if (ct == 0xFF) {
/* 已在 record_read 里被返回 app data (不应发生) */
continue;
}
/* 握手完成后不应再收到握手消息(除非 KeyUpdate/Post-Handshake Auth 等,不处理) */
}
}
int paze_tls_write(paze_tls_t *tls, const uint8_t *buf, size_t len) {
if (!tls || (!buf && len)) return PAZE_ERR_INVALID;
size_t done = 0;
while (done < len) {
size_t chunk = len - done;
if (chunk > PAZE_TLS_MAX_RECORD) chunk = PAZE_TLS_MAX_RECORD;
paze_status_t st = paze_tls_record_send(tls, PAZE_TLS_CT_APPLICATION_DATA,
buf + done, chunk);
if (st != PAZE_OK) return -1;
done += chunk;
}
return (int)done;
}
int paze_tls_is_handshake_done(const paze_tls_t *tls) {
return tls ? tls->handshake_done : 0;
}
paze_status_t paze_tls_close(paze_tls_t *tls) {
if (!tls) return PAZE_ERR_INVALID;
if (!tls->close_sent && tls->handshake_done) {
uint8_t al[2] = { PAZE_TLS_ALERT_WARNING, PAZE_TLS_ALERT_CLOSE_NOTIFY };
paze_tls_record_send(tls, PAZE_TLS_CT_ALERT, al, 2);
tls->close_sent = 1;
}
return PAZE_OK;
}
/* ============================================================
* 查询
* ============================================================ */
int paze_tls_get_version(const paze_tls_t *tls) {
return tls ? tls->neg.version : 0;
}
uint16_t paze_tls_get_cipher_suite(const paze_tls_t *tls) {
return tls ? tls->neg.cipher : 0;
}
const char *paze_tls_get_alpn(const paze_tls_t *tls) {
if (!tls || !tls->neg.alpn[0]) return NULL;
return tls->neg.alpn;
}
const char *paze_tls_get_sni(const paze_tls_t *tls) {
if (!tls) return NULL;
paze_tls_config_t *cfg = tls->cfg_owned ? tls->cfg_owned : (paze_tls_config_t *)tls->cfg;
return cfg->sni[0] ? cfg->sni : NULL;
}
const char *paze_tls_last_error(const paze_tls_t *tls) {
if (!tls || !tls->errbuf[0]) {
const char *g = paze_last_err();
return g ? g : "ok";
}
return tls->errbuf;
}
/* ============================================================
* 错误记录(外部声明见 tls_internal.h)
* ============================================================ */
void paze_tls_set_err(paze_tls_t *tls, const char *fmt, ...) {
if (!tls) return;
va_list ap;
va_start(ap, fmt);
vsnprintf(tls->errbuf, sizeof(tls->errbuf), fmt, ap);
va_end(ap);
PAZE_LOGE("TLS: %s", tls->errbuf);
}