Update TLCP to state machine

This commit is contained in:
Zhi Guan
2026-02-27 09:11:49 +08:00
parent cac8f394a0
commit ee2fa409f2
9 changed files with 1169 additions and 55 deletions

View File

@@ -652,6 +652,7 @@ int tls_record_get_handshake_finished(const uint8_t *record,
int tls_finished_print(FILE *fp, const uint8_t *a, size_t len, int format, int indent);
// Alert
typedef struct {
uint8_t level;
@@ -739,14 +740,52 @@ void tls_ctx_cleanup(TLS_CTX *ctx);
#define TLS_ERROR_SYSCALL -1003 // SSL_ERROR_SYSCALL
enum {
TLS_state_handshake_init = 0,
TLS_state_client_hello,
TLS_state_server_hello,
TLS_state_server_certificate,
TLS_state_server_key_exchange,
TLS_state_certificate_request,
TLS_state_server_hello_done,
TLS_state_client_certificate,
TLS_state_client_key_exchange,
TLS_state_certificate_verify,
TLS_state_generate_keys,
TLS_state_client_change_cipher_spec,
TLS_state_client_finished,
TLS_state_server_change_cipher_spec,
TLS_state_server_finished,
TLS_state_handshake_over,
};
typedef struct {
int protocol;
int is_client;
int protocol;
/*
服务器端在初始化之后会创建一个server_ciphers列表
在接收到client_ciphers之后和自己的server_ciphers对比选择出conn->cipher
也可能没有找到一致的cipher那么就失败了
实际上服务器端的ciphers可以完全来自CTX并不需要缓存
客户端在初始化之后创建client_ciphers发送给服务器
在接收到服务器的cipher后要判断这个cipher是否在自己的client_ciphers之中
但是客户端是需要缓存ciphers的这样才能够判断返回的cipher是否在自己的ciphers之中
下面的问题是在CONN中要维护哪些信息
*/
int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
size_t cipher_suites_cnt;
int cipher_suite;
tls_socket_t sock;
uint8_t enced_record[TLS_MAX_RECORD_SIZE];
@@ -764,7 +803,6 @@ typedef struct {
uint8_t *data;
size_t datalen;
int cipher_suite;
uint8_t session_id[32];
size_t session_id_len;
uint8_t server_certs[TLS_MAX_CERTIFICATES_SIZE]; // TODO: use ptr and malloc
@@ -775,9 +813,11 @@ typedef struct {
size_t ca_certs_len;
X509_KEY sign_key;
X509_KEY kenc_key;
X509_KEY kenc_key; // 应该作为服务器的SM2加密
X509_KEY server_enc_key;
int verify_result;
uint8_t pre_master_secret[48]; // 是否可以重用master_secret作为pre_master_secret呢
uint8_t master_secret[48];
uint8_t key_block[96];
@@ -833,6 +873,45 @@ typedef struct {
#define TLS_MAX_EXTENSIONS_SIZE 512 // FIXME: no reason to give fixed max length
int tls_send_client_hello(TLS_CONNECT *conn);
int tls_recv_client_hello(TLS_CONNECT *conn);
int tls_send_server_hello(TLS_CONNECT *conn);
int tls_recv_server_hello(TLS_CONNECT *conn);
int tls_send_server_certificate(TLS_CONNECT *conn);
int tls_recv_server_certificate(TLS_CONNECT *conn);
int tls_send_server_key_exchange(TLS_CONNECT *conn);
int tls_recv_server_key_exchange(TLS_CONNECT *conn);
int tls_send_certificate_request(TLS_CONNECT *conn);
int tls_recv_certificate_request(TLS_CONNECT *conn);
int tls_send_server_hello_done(TLS_CONNECT *conn);
int tls_recv_server_hello_done(TLS_CONNECT *conn);
int tls_send_client_certificate(TLS_CONNECT *conn);
int tls_recv_client_certificate(TLS_CONNECT *conn);
int tls_generate_keys(TLS_CONNECT *conn);
int tls_send_client_key_exchange(TLS_CONNECT *conn);
int tls_recv_client_key_exchange(TLS_CONNECT *conn);
int tls_send_certificate_verify(TLS_CONNECT *conn);
int tls_recv_certificate_verify(TLS_CONNECT *conn);
int tls_send_change_cipher_spec(TLS_CONNECT *conn);
int tls_recv_change_cipher_spec(TLS_CONNECT *conn);
int tls_send_client_finished(TLS_CONNECT *conn);
int tls_recv_client_finished(TLS_CONNECT *conn);
int tls_send_server_finished(TLS_CONNECT *conn);
int tls_recv_server_finished(TLS_CONNECT *conn);
int tlcp_send_client_hello(TLS_CONNECT *conn);
int tlcp_recv_client_hello(TLS_CONNECT *conn);
int tlcp_send_server_key_exchange(TLS_CONNECT *conn);
int tlcp_recv_server_key_exchange(TLS_CONNECT *conn);
int tlcp_generate_keys(TLS_CONNECT *conn);
int tlcp_send_client_key_exchange(TLS_CONNECT *conn);
int tlcp_recv_client_key_exchange(TLS_CONNECT *conn);
void tls_clean_record(TLS_CONNECT *conn);
int tls_init(TLS_CONNECT *conn, const TLS_CTX *ctx);
int tls_set_socket(TLS_CONNECT *conn, tls_socket_t sock);
int tls_do_handshake(TLS_CONNECT *conn);
@@ -916,6 +995,17 @@ int tls13_gcm_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
int tls_encrypted_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int format, int indent);
#ifdef __cplusplus
}
#endif

View File

@@ -600,9 +600,6 @@ int sm2_sign_finish_fixlen(SM2_SIGN_CTX *ctx, size_t siglen, uint8_t *sig)
return -1;
}
sm3_finish(&ctx->sm3_ctx, dgst);
format_bytes(stderr, 0, 4, "signed dgst", dgst, 32);
if (sm2_sign_fixlen(&ctx->key, dgst, siglen, sig) != 1) {
error_print();
return -1;

View File

@@ -25,6 +25,21 @@
#include <gmssl/tls.h>
// sign_master_public_key, enc_master_public_key, sign_key, enc_key
int tls_ctx_set_sm9_keys(TLS_CTX *ctx, const char *masterfile,
const char *keyfile, const char *keypass)
{
// 从masterfile中读取两个
// 从keyfile中读取两个密钥
return -1;
}
// TLCP的套件和TLS12不一样我们现在只支持一种
static const int tlcp_ciphers[] = { TLS_cipher_ecc_sm4_cbc_sm3 };
static const size_t tlcp_ciphers_count = sizeof(tlcp_ciphers)/sizeof(tlcp_ciphers[0]);
@@ -37,6 +52,8 @@ int tlcp_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int fo
return tls_record_print(fp, record, recordlen, format, indent);
}
/*
select (KeyExchangeAlgorithm) {
case ECC:
@@ -49,6 +66,11 @@ select (KeyExchangeAlgorithm) {
} ServerKeyExchange;
-- in TLCP 1.1, the `signed_params` is DER signature encoded in uint16array
在TLS12中ServerKeyExchange中是有ECDH公钥的但是在TLCP中
*/
int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *recordlen,
const uint8_t *sig, size_t siglen)
@@ -128,7 +150,7 @@ int tlcp_server_key_exchange_pke_print(FILE *fp, const uint8_t *data, size_t dat
return 1;
}
int tlcp_do_connect(TLS_CONNECT *conn)
int _tlcp_do_connect(TLS_CONNECT *conn)
{
int ret = -1;
uint8_t *record = conn->record;
@@ -174,7 +196,7 @@ int tlcp_do_connect(TLS_CONNECT *conn)
int verify_result;
// 初始化记录缓冲
// 初始化记录缓冲,这里的主要区别在于,版本号是确定的!
tls_record_set_protocol(record, TLS_protocol_tlcp);
tls_record_set_protocol(finished_record, TLS_protocol_tlcp);
@@ -256,9 +278,11 @@ int tlcp_do_connect(TLS_CONNECT *conn)
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
// verify ServerCertificate
if (conn->ca_certs_len) {
if (conn->ca_certs_len) { // 这里不对啊如果没准备CA证书难道就不验证服务器证书了吗
// 只有提供了CA证书才验证服务器证书链
// FIXME: 逻辑需要再检查
// 这里验证证书链的逻辑和TLS12不同
// 但是证书链的验证逻辑可以根据协议的差异来选择
if (x509_certs_verify_tlcp(conn->server_certs, conn->server_certs_len, X509_cert_chain_server,
conn->ca_certs, conn->ca_certs_len, depth, &verify_result) != 1) {
error_print();
@@ -276,6 +300,7 @@ int tlcp_do_connect(TLS_CONNECT *conn)
goto end;
}
tlcp_record_trace(stderr, record, recordlen, 0, 0);
// 显然这是一个TLCP独特的版本
if (tlcp_record_get_handshake_server_key_exchange_pke(record, &sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
@@ -284,6 +309,7 @@ int tlcp_do_connect(TLS_CONNECT *conn)
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
// verify ServerKeyExchange
// 这个策略应该没有什么不同,因为都是用第一个证书来验证签名
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 0, &cp, &len) != 1
|| x509_cert_get_subject_public_key(cp, len, &server_sign_key) != 1
|| x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 1, &server_enc_cert, &server_enc_cert_len) != 1
@@ -419,8 +445,10 @@ int tlcp_do_connect(TLS_CONNECT *conn)
// send ClientKeyExchange
tls_trace("send ClientKeyExchange\n");
// 这里是比较特殊的这里应该改为用X509_KEY的API这样可以支持SM9等
if (sm2_encrypt(&server_enc_key.u.sm2_key, pre_master_secret, 48,
enced_pre_master_secret, &enced_pre_master_secret_len) != 1
// 这个函数是TLCP专属的
|| tls_record_set_handshake_client_key_exchange_pke(record, &recordlen,
enced_pre_master_secret, enced_pre_master_secret_len) != 1) {
error_print();
@@ -580,7 +608,7 @@ end:
return ret;
}
int tlcp_do_accept(TLS_CONNECT *conn)
int _tlcp_do_accept(TLS_CONNECT *conn)
{
int ret = -1;
@@ -738,6 +766,7 @@ int tlcp_do_accept(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
// 需要检查一下TLCP和TLS12在这个消息上的差异是什么
if (tlcp_record_set_handshake_server_key_exchange_pke(record, &recordlen, sigbuf, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
@@ -819,11 +848,13 @@ int tlcp_do_accept(TLS_CONNECT *conn)
goto end;
}
tlcp_record_trace(stderr, record, recordlen, 0, 0);
// tls_record_get_handshake_client_key_exchange_pke 这个函数有问题只用于TLCP的应该放在TLCP文件中
if (tls_record_get_handshake_client_key_exchange_pke(record, &enced_pms, &enced_pms_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
// 这个处理是TLCP专属的
if (sm2_decrypt(&conn->kenc_key.u.sm2_key, enced_pms, enced_pms_len,
pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
@@ -1021,3 +1052,379 @@ end:
gmssl_secure_clear(pre_master_secret, sizeof(pre_master_secret));
return ret;
}
/*
SM9_SM4_CBC_SM3
opaque SM9SignMasterPublicKey<0..2^24-1>;
struct {
opaque id<1..2^16-1>; // server's domain name, equivalent to entity cert
SM9SignMasterPublicKey sign_params; // equavalent to ca root cert, optional
} Certificate;
opaque SM9EncMasterPublicKey<0..2^24-1>;
struct {
SM9EncMasterPublicKey enc_params;
digitally-signed struct {
opaque client_random[32];
opaque server_random[32];
SM9EncMasterPublicKey enc_params;
opaque id<1..2^16-1>;
} signed_params;
} ServerKeyExchange;
struct {
opaque encrypted_pre_master_secret<0..2^16-1>;
} ClientKeyExchange
*/
/*
Client Server
ClientHello -------->
ServerHello
Certificate
ServerKeyExchange
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
*/
int tlcp_do_client_handshake(TLS_CONNECT *conn)
{
int ret;
int next_state;
switch (conn->state) {
case TLS_state_client_hello:
ret = tlcp_send_client_hello(conn);
next_state = TLS_state_server_hello;
break;
case TLS_state_server_hello:
ret = tls_recv_server_hello(conn);
next_state = TLS_state_server_certificate;
break;
case TLS_state_server_certificate:
ret = tls_recv_server_certificate(conn);
next_state = TLS_state_server_key_exchange;
break;
case TLS_state_server_key_exchange:
ret = tlcp_recv_server_key_exchange(conn);
next_state = TLS_state_certificate_request;
break;
case TLS_state_certificate_request:
ret = tls_recv_certificate_request(conn);
if (ret == 1) conn->client_certificate_verify = 1;
next_state = TLS_state_server_hello_done;
break;
case TLS_state_server_hello_done:
ret = tls_recv_server_hello_done(conn);
if (conn->client_certificate_verify)
next_state = TLS_state_client_certificate;
else next_state = TLS_state_client_key_exchange;
break;
case TLS_state_client_certificate:
ret = tls_send_client_certificate(conn);
next_state = TLS_state_client_key_exchange;
break;
case TLS_state_client_key_exchange:
ret = tlcp_send_client_key_exchange(conn);
next_state = TLS_state_generate_keys;
break;
case TLS_state_generate_keys:
ret = tlcp_generate_keys(conn);
if (conn->client_certificate_verify)
next_state = TLS_state_certificate_verify;
else next_state = TLS_state_client_change_cipher_spec;
break;
case TLS_state_certificate_verify:
ret = tls_send_certificate_verify(conn);
next_state = TLS_state_client_change_cipher_spec;
case TLS_state_client_change_cipher_spec:
ret = tls_send_change_cipher_spec(conn);
next_state = TLS_state_client_finished;
break;
case TLS_state_client_finished:
ret = tls_send_client_finished(conn);
next_state = TLS_state_server_change_cipher_spec;
break;
case TLS_state_server_change_cipher_spec:
ret = tls_recv_change_cipher_spec(conn);
next_state = TLS_state_server_finished;
break;
case TLS_state_server_finished:
ret = tls_recv_server_finished(conn);
next_state = TLS_state_handshake_over;
break;
default:
error_print();
return -1;
}
if (ret < 0) {
if (ret == TLS_ERROR_RECV_AGAIN || ret == TLS_ERROR_SEND_AGAIN) {
return ret;
} else {
error_print();
return ret;
}
}
conn->state = next_state;
// ret == 0 means this step is bypassed
if (ret == 1) {
tls_clean_record(conn);
}
return 1;
}
int tlcp_do_server_handshake(TLS_CONNECT *conn)
{
int ret;
int next_state;
switch (conn->state) {
case TLS_state_client_hello:
ret = tlcp_recv_client_hello(conn);
next_state = TLS_state_server_hello;
break;
case TLS_state_server_hello:
ret = tls_send_server_hello(conn);
next_state = TLS_state_server_certificate;
break;
case TLS_state_server_certificate:
ret = tls_send_server_certificate(conn);
next_state = TLS_state_server_key_exchange;
break;
case TLS_state_server_key_exchange:
ret = tlcp_send_server_key_exchange(conn);
if (conn->client_certificate_verify)
next_state = TLS_state_certificate_request;
else next_state = TLS_state_server_hello_done;
break;
case TLS_state_certificate_request:
ret = tls_send_certificate_request(conn);
next_state = TLS_state_server_hello_done;
break;
case TLS_state_server_hello_done:
ret = tls_send_server_hello_done(conn);
if (conn->client_certificate_verify)
next_state = TLS_state_client_certificate;
else next_state = TLS_state_client_key_exchange;
break;
case TLS_state_client_certificate:
ret = tls_recv_client_certificate(conn);
next_state = TLS_state_client_key_exchange;
break;
case TLS_state_client_key_exchange:
ret = tlcp_recv_client_key_exchange(conn);
if (conn->client_certificate_verify)
next_state = TLS_state_certificate_verify;
else next_state = TLS_state_generate_keys;
break;
case TLS_state_certificate_verify:
ret = tls_recv_certificate_verify(conn);
next_state = TLS_state_generate_keys;
break;
case TLS_state_generate_keys:
ret = tlcp_generate_keys(conn);
next_state = TLS_state_client_change_cipher_spec;
break;
case TLS_state_client_change_cipher_spec:
ret = tls_recv_change_cipher_spec(conn);
next_state = TLS_state_client_finished;
break;
case TLS_state_client_finished:
ret = tls_recv_client_finished(conn);
next_state = TLS_state_server_change_cipher_spec;
break;
case TLS_state_server_change_cipher_spec:
ret = tls_send_change_cipher_spec(conn);
next_state = TLS_state_server_finished;
break;
case TLS_state_server_finished:
ret = tls_send_server_finished(conn);
next_state = TLS_state_handshake_over;
break;
default:
error_print();
return -1;
}
if (ret != 1) {
if (ret == TLS_ERROR_RECV_AGAIN || ret == TLS_ERROR_SEND_AGAIN) {
return ret;
} else {
error_print();
return ret;
}
}
conn->state = next_state;
tls_clean_record(conn);
return 1;
}
int tlcp_client_handshake(TLS_CONNECT *conn)
{
int ret;
while (conn->state != TLS_state_handshake_over) {
ret = tlcp_do_client_handshake(conn);
if (ret != 1) {
if (ret != TLS_ERROR_RECV_AGAIN && ret != TLS_ERROR_SEND_AGAIN) {
error_print();
}
return ret;
}
}
// TODO: cleanup conn?
return 1;
}
int tlcp_server_handshake(TLS_CONNECT *conn)
{
int ret;
while (conn->state != TLS_state_handshake_over) {
ret = tlcp_do_server_handshake(conn);
if (ret != 1) {
if (ret != TLS_ERROR_RECV_AGAIN && ret != TLS_ERROR_SEND_AGAIN) {
error_print();
}
return ret;
}
}
// TODO: cleanup conn?
return 1;
}
int tlcp_do_connect(TLS_CONNECT *conn)
{
int ret;
fd_set rfds;
fd_set wfds;
// 应该把protocol_version的初始化放在这里
conn->state = TLS_state_client_hello;
sm3_init(&conn->sm3_ctx);
while (1) {
ret = tlcp_client_handshake(conn);
if (ret == 1) {
break;
} else if (ret == TLS_ERROR_SEND_AGAIN) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(conn->sock, &rfds);
select(conn->sock + 1, &rfds, &wfds, NULL, NULL);
} else if (ret == TLS_ERROR_RECV_AGAIN) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(conn->sock, &wfds);
select(conn->sock + 1, &rfds, &wfds, NULL, NULL);
} else {
error_print();
return -1;
}
}
return 1;
}
int tlcp_do_accept(TLS_CONNECT *conn)
{
int ret;
fd_set rfds;
fd_set wfds;
conn->state = TLS_state_client_hello;
sm3_init(&conn->sm3_ctx);
while (1) {
ret = tlcp_server_handshake(conn);
if (ret == 1) {
break;
} else if (ret == TLS_ERROR_SEND_AGAIN) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(conn->sock, &rfds);
select(conn->sock + 1, &rfds, &wfds, NULL, NULL);
} else if (ret == TLS_ERROR_RECV_AGAIN) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(conn->sock, &wfds);
select(conn->sock + 1, &rfds, &wfds, NULL, NULL);
} else {
error_print();
return -1;
}
}
return 1;
}

View File

@@ -2096,6 +2096,8 @@ int tls_ctx_init(TLS_CTX *ctx, int protocol, int is_client)
return 1;
}
// FIXME: 根据protocol核对输入的ciphers是否满足protocol的条件
int tls_ctx_set_cipher_suites(TLS_CTX *ctx, const int *cipher_suites, size_t cipher_suites_cnt)
{
size_t i;
@@ -2314,8 +2316,11 @@ int tls_init(TLS_CONNECT *conn, const TLS_CTX *ctx)
size_t i;
memset(conn, 0, sizeof(*conn));
conn->protocol = ctx->protocol;
conn->is_client = ctx->is_client;
conn->protocol = ctx->protocol;
for (i = 0; i < ctx->cipher_suites_cnt; i++) {
conn->cipher_suites[i] = ctx->cipher_suites[i];
}
@@ -2348,6 +2353,7 @@ int tls_init(TLS_CONNECT *conn, const TLS_CTX *ctx)
conn->verify_depth = ctx->verify_depth;
return 1;
}

View File

@@ -27,14 +27,13 @@
#include <errno.h>
#include <sys/select.h>
static const int tls12_ciphers[] = {
TLS_cipher_ecdhe_sm4_cbc_sm3,
TLS_cipher_ecdhe_sm4_gcm_sm3,
TLS_cipher_ecdhe_ecdsa_with_aes_128_cbc_sha256,
};
// 现在client_certificate_verify做的是不好的
/*
是否要求客户端提供证书是服务器决定的服务器方需要提供相应的CA证书
@@ -194,24 +193,11 @@ int tls_named_curve_from_oid(int oid)
return 0;
}
enum {
TLS_state_handshake_init = 0,
TLS_state_client_hello,
TLS_state_server_hello,
TLS_state_server_certificate,
TLS_state_server_key_exchange,
TLS_state_certificate_request,
TLS_state_server_hello_done,
TLS_state_client_certificate,
TLS_state_client_key_exchange,
TLS_state_certificate_verify,
TLS_state_generate_keys,
TLS_state_client_change_cipher_spec,
TLS_state_client_finished,
TLS_state_server_change_cipher_spec,
TLS_state_server_finished,
TLS_state_handshake_over,
};
// 这个是必选的
const int ec_point_formats[] = { TLS_point_uncompressed };
@@ -256,6 +242,7 @@ int tls_record_set_handshake_server_key_exchange(uint8_t *record, size_t *record
return 1;
}
// 这个函数是有问题的因为tlcp的格式和TLS不一样
int tls_record_get_handshake_server_key_exchange(const uint8_t *record,
uint8_t *curve_type, uint16_t *named_curve,
const uint8_t **point_octets, size_t *point_octets_len,
@@ -373,6 +360,13 @@ int tls_handshake_init(TLS_CONNECT *conn)
return 1;
}
/*
TLCP协议中ClientHello中不包含扩展并且cipher_suites使用的是TLCP的cipher_suites
ciphers我觉得应该在设置ctx的时候设置好
exts
*/
int tls_send_client_hello(TLS_CONNECT *conn)
{
int ret;
@@ -383,12 +377,23 @@ int tls_send_client_hello(TLS_CONNECT *conn)
uint8_t *p = client_exts;
size_t client_exts_len = 0;
switch (conn->protocol) {
case TLS_protocol_tls12:
tls_record_set_protocol(record, TLS_protocol_tls1);
break;
case TLS_protocol_tlcp:
tls_record_set_protocol(record, TLS_protocol_tlcp);
break;
default:
error_print();
return -1;
}
if (tls_random_generate(conn->client_random) != 1) {
error_print();
return -1;
}
if (tls_ec_point_formats_ext_to_bytes(ec_point_formats, ec_point_formats_cnt, &p, &client_exts_len) != 1
|| tls_supported_groups_ext_to_bytes(supported_groups, supported_groups_cnt, &p, &client_exts_len) != 1
|| tls_signature_algorithms_ext_to_bytes(signature_algors, signature_algors_cnt, &p, &client_exts_len) != 1) {
@@ -397,7 +402,7 @@ int tls_send_client_hello(TLS_CONNECT *conn)
}
if (tls_record_set_handshake_client_hello(conn->record, &conn->recordlen,
conn->protocol, conn->client_random, NULL, 0,
tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0]),
conn->cipher_suites, conn->cipher_suites_cnt,
client_exts, client_exts_len) != 1) {
error_print();
return -1;
@@ -427,8 +432,160 @@ int tls_send_client_hello(TLS_CONNECT *conn)
return 1;
}
//static const int tlcp_ciphers[] = { TLS_cipher_ecc_sm4_cbc_sm3 };
int tlcp_send_client_hello(TLS_CONNECT *conn)
{
int ret;
uint8_t *record = conn->record;
if (!conn->recordlen) {
tls_record_set_protocol(record, TLS_protocol_tlcp);
if (tls_random_generate(conn->client_random) != 1) {
error_print();
return -1;
}
if (tls_record_set_handshake_client_hello(conn->record, &conn->recordlen,
conn->protocol, conn->client_random, NULL, 0,
conn->cipher_suites, conn->cipher_suites_cnt,
NULL, 0) != 1) {
error_print();
return -1;
}
// offset = 0, recordlen > 0
tls_trace("send ClientHello\n");
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
}
if (conn->client_certificate_verify) {
sm2_sign_update(&conn->sign_ctx, conn->record + 5, conn->recordlen - 5);
}
if ((ret = tls_send_record(conn)) != 1) {
if (ret != TLS_ERROR_SEND_AGAIN) {
error_print();
}
return ret;
}
tls_clean_record(conn);
return 1;
}
int tlcp_recv_client_hello(TLS_CONNECT *conn)
{
int ret;
uint8_t *record = conn->record;
size_t recordlen;
int client_verify = 0;
int protocol;
const uint8_t *client_random;
const uint8_t *session_id;
size_t session_id_len;
const uint8_t *client_ciphers;
size_t client_ciphers_len;
const uint8_t *client_exts;
size_t client_exts_len;
sm3_init(&conn->sm3_ctx);
// 服务器端如果设置了CA
if (conn->ca_certs_len)
client_verify = 1;
// 这个判断应该改为一个函数
if (client_verify)
tls_client_verify_init(&conn->client_verify_ctx);
tls_trace("recv ClientHello\n");
if ((ret = tls_recv_record(conn)) != 1) {
if (ret != TLS_ERROR_RECV_AGAIN) {
error_print();
}
return ret;
}
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
// 这里TLCP和TLS12是不一样的
if (tls_record_protocol(record) != conn->protocol) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
if (tls_record_get_handshake_client_hello(record,
&protocol, &client_random, &session_id, &session_id_len,
&client_ciphers, &client_ciphers_len,
&client_exts, &client_exts_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
if (protocol != conn->protocol) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
memcpy(conn->client_random, client_random, 32);
if (tls_cipher_suites_select(client_ciphers, client_ciphers_len,
conn->cipher_suites, conn->cipher_suites_cnt,
&conn->cipher_suite) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_insufficient_security);
return -1;
}
switch (conn->cipher_suite) {
case TLS_cipher_ecc_sm4_cbc_sm3:
conn->sig_alg = TLS_sig_sm2sig_sm3;
conn->ecdh_named_curve = 0;
break;
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
default:
error_print();
return -1;
}
if (client_exts) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
if (client_verify)
tls_client_verify_update(&conn->client_verify_ctx, conn->record + 5, conn->recordlen - 5);
fprintf(stderr, "end of recv_client_hello\n");
tls_clean_record(conn);
return 1;
}
/*
const int server_ciphers[] = { TLS_cipher_ecdhe_sm4_cbc_sm3 };
const size_t server_ciphers_cnt = 1;
*/
const int curve = TLS_curve_sm2p256v1;
@@ -473,6 +630,8 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
tls12_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
if (tls_record_protocol(record) != conn->protocol
&& tls_record_protocol(record) != TLS_protocol_tls1) {
error_print();
@@ -498,7 +657,7 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
// 服务器选择的cipher_suites需要和服务器准备的证书和公钥匹配
if (tls_cipher_suites_select(client_ciphers, client_ciphers_len,
server_ciphers, server_ciphers_cnt,
conn->cipher_suites, conn->cipher_suites_cnt,
&conn->cipher_suite) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_insufficient_security);
@@ -539,17 +698,26 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
int tls_send_server_hello(TLS_CONNECT *conn)
{
int ret;
tls_trace("send ServerHello\n");
if (conn->recordlen == 0) {
const uint8_t *server_exts = NULL;
size_t server_exts_len = 0;
tls_record_set_protocol(conn->record, conn->protocol);
if (tls_random_generate(conn->server_random) != 1) {
error_print();
return -1;
}
if (conn->server_exts_len) {
server_exts = conn->server_exts;
server_exts_len = conn->server_exts_len;
}
if (tls_record_set_handshake_server_hello(conn->record, &conn->recordlen,
conn->protocol, conn->server_random, NULL, 0,
conn->cipher_suite, conn->server_exts, conn->server_exts_len) != 1) {
conn->cipher_suite,
server_exts, server_exts_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
@@ -617,17 +785,25 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
// tls12_ciphers 应该改为conn的内部变量
if (tls_cipher_suite_in_list(cipher_suite, tls12_ciphers, sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0])) != 1) {
if (tls_cipher_suite_in_list(cipher_suite, conn->cipher_suites, conn->cipher_suites_cnt) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_handshake_failure);
return -1;
}
if (!server_exts) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
/*
对于扩展的处理
首先扩展是由客户端ClientHello进行设定服务器选择最后由Client验证的一个过程。
因此客户端和服务器端都需要存储扩展相应的数据。
扩展的初始化是如何实现的我觉得也应该在CTX中完成。
现在对扩展的处理逻辑是有问题的服务器ServerHello是否包含扩展是取决于ClientHello的
*/
if (server_exts) {
if (tls_process_server_hello_exts(server_exts, server_exts_len, &ec_point_format, &supported_group, &signature_algor) != 1
|| ec_point_format < 0
|| supported_group < 0
@@ -636,6 +812,7 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
}
memcpy(conn->server_random, server_random, 32);
memcpy(conn->session_id, session_id, session_id_len);
@@ -648,6 +825,10 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
return 1;
}
// TLS12 发送的是常规的证书链
// TLCP SM2 发送的是SM2的双证书链但是在数据格式上没有区别
// TLCP SM9 发送的是服务器的ID和SM9公开参数这个格式是不同的但是存储上可能也是一样的
// 我不确定SM2和SM9的格式是否是相容的
int tls_send_server_certificate(TLS_CONNECT *conn)
{
int ret;
@@ -708,6 +889,8 @@ int tls_recv_server_certificate(TLS_CONNECT *conn)
return -1;
}
// 这下面是对获取的证书链的处理
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 0,
&server_cert, &server_cert_len) != 1) {
error_print();
@@ -720,6 +903,9 @@ int tls_recv_server_certificate(TLS_CONNECT *conn)
return -1;
}
// 这里的逻辑需要统筹考虑
// cipher_suite扩展证书之间的关系
// set conn->server_sig_alg (decided by cipher_suite and server_cert.sign_key.algor, algor_param)
if (server_sign_key.algor != OID_ec_public_key) {
error_print();
@@ -757,12 +943,92 @@ int tls_recv_server_certificate(TLS_CONNECT *conn)
assert(conn->verify_depth > 0 && conn->verify_depth < 10);
// verify ServerCertificate
switch (conn->protocol) {
case TLS_protocol_tls12:
if (x509_certs_verify(conn->server_certs, conn->server_certs_len, X509_cert_chain_server,
conn->ca_certs, conn->ca_certs_len, conn->verify_depth, &verify_result) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
break;
case TLS_protocol_tlcp:
if (!conn->ca_certs_len) {
error_print();
return -1;
}
if (x509_certs_verify_tlcp(conn->server_certs, conn->server_certs_len, X509_cert_chain_server,
conn->ca_certs, conn->ca_certs_len, conn->verify_depth, &verify_result) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
break;
default:
error_print();
return -1;
}
return 1;
}
int tlcp_send_server_key_exchange(TLS_CONNECT *conn)
{
SM2_SIGN_CTX sign_ctx;
uint8_t sigbuf[SM2_MAX_SIGNATURE_SIZE];
size_t siglen;
const uint8_t *server_enc_cert;
size_t server_enc_cert_len;
uint8_t server_enc_cert_lenbuf[3];
uint8_t *p;
size_t len;
int ret;
tls_trace("send ServerKeyExchange\n");
if (conn->recordlen == 0) {
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 1,
&server_enc_cert, &server_enc_cert_len) != 1) {
error_print();
return -1;
}
p = server_enc_cert_lenbuf;
len = 0;
tls_uint24_to_bytes((uint24_t)server_enc_cert_len, &p, &len);
if (sm2_sign_init(&sign_ctx, &conn->sign_key.u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, conn->client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, conn->server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_enc_cert_lenbuf, 3) != 1
|| sm2_sign_update(&sign_ctx, server_enc_cert, server_enc_cert_len) != 1
|| sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_server_key_exchange_pke(conn->record, &conn->recordlen, sigbuf, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
}
if ((ret = tls_send_record(conn)) != 1) {
if (ret != TLS_ERROR_SEND_AGAIN) {
error_print();
}
return ret;
}
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
if (conn->client_certificate_verify) {
tls_client_verify_update(&conn->client_verify_ctx, conn->record + 5, conn->recordlen - 5);
}
return 1;
}
@@ -903,6 +1169,8 @@ int tls_signature_scheme_match_cipher_suite(int sig_alg, int cipher_suite)
return 1;
}
// 这里应该给一个新的key_exchange
int tls_recv_server_key_exchange(TLS_CONNECT *conn)
{
int ret;
@@ -942,7 +1210,8 @@ int tls_recv_server_key_exchange(TLS_CONNECT *conn)
}
tls12_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
// 这里应该改为首先获取一个基础的ServerKeyExchange的数据已经经过了验证签名
// 然后再用不同的函数(不同协议)去分解
if (tls_record_get_handshake_server_key_exchange(conn->record,
&curve_type, &named_curve, &point_octets, &point_octets_len,
&server_ecdh_params, &server_ecdh_params_len,
@@ -1051,6 +1320,79 @@ int tls_recv_server_key_exchange(TLS_CONNECT *conn)
return 1;
}
int tlcp_recv_server_key_exchange(TLS_CONNECT *conn)
{
const uint8_t *sig;
size_t siglen;
const uint8_t *cp;
size_t len;
X509_KEY server_sign_key;
const uint8_t *server_enc_cert;
size_t server_enc_cert_len;
uint8_t server_enc_cert_lenbuf[3];
uint8_t *p;
SM2_VERIFY_CTX verify_ctx;
tls_trace("recv ServerKeyExchange\n");
if (tls_record_recv(conn->record, &conn->recordlen, conn->sock) != 1
|| tls_record_protocol(conn->record) != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
if (tlcp_record_get_handshake_server_key_exchange_pke(conn->record, &sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
// verify ServerKeyExchange
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 0, &cp, &len) != 1
|| x509_cert_get_subject_public_key(cp, len, &server_sign_key) != 1
|| x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 1, &server_enc_cert, &server_enc_cert_len) != 1
|| x509_cert_get_subject_public_key(server_enc_cert, server_enc_cert_len, &conn->server_enc_key) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
if (server_sign_key.algor != OID_ec_public_key
|| server_sign_key.algor_param != OID_sm2
|| conn->server_enc_key.algor != OID_ec_public_key
|| conn->server_enc_key.algor_param != OID_sm2) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
p = server_enc_cert_lenbuf;
len = 0;
tls_uint24_to_bytes((uint24_t)server_enc_cert_len, &p, &len);
if (sm2_verify_init(&verify_ctx, &server_sign_key.u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_verify_update(&verify_ctx, conn->client_random, 32) != 1
|| sm2_verify_update(&verify_ctx, conn->server_random, 32) != 1
|| sm2_verify_update(&verify_ctx, server_enc_cert_lenbuf, 3) != 1
|| sm2_verify_update(&verify_ctx, server_enc_cert, server_enc_cert_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_verify_finish(&verify_ctx, sig, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
return 1;
}
int tls_send_certificate_request(TLS_CONNECT *conn)
{
int ret;
@@ -1303,12 +1645,36 @@ int tls_recv_client_certificate(TLS_CONNECT *conn)
return 1;
}
/*
不同密码套件中使用的密钥生成方法不一样,需要的输入也不一样。
应该考虑在CONN中维护union版本的ServerKeyExchange和ClientKeyExchange
ServerKeyExchange ClientKeyExchange
ECDHE Server X509_KEY X509_KEY public
ECDHE Client X509_KEY X509_KEY public
ECC Server N/A SM2Cipher
ECC Client N/A N/A 客户端可能需要服务器公钥的类型
我们现在还不支持SM2的ECDH呢
SM9相关的密码套件呢
*/
int tls_generate_keys(TLS_CONNECT *conn)
{
uint8_t pre_master_secret[32];
size_t pre_master_secret_len;
uint8_t key_block[96];
// 此时已经获得了ServerKeyExchange和ClientKeyExchange
// 但是不同密码套件中这些KeyExchange的数据其实是不一样的
// 我们需要根据不同的套件去解析数据,并且根据不同的数据类型去生成密钥
// 还需要检查 TLS 1.3 的协议
if (x509_key_exchange(&conn->ecdh_key,
conn->peer_ecdh_point, conn->peer_ecdh_point_len,
@@ -1359,6 +1725,51 @@ int tls_generate_keys(TLS_CONNECT *conn)
return 1;
}
// 对于客户端是先发送client_key_exchange在generate_keys
int tlcp_generate_keys(TLS_CONNECT *conn)
{
uint8_t enced_pre_master_secret[SM2_MAX_CIPHERTEXT_SIZE];
size_t enced_pre_master_secret_len;
tls_trace("generate secrets\n");
if (tls_prf(conn->pre_master_secret, 48, "master secret",
conn->client_random, 32,
conn->server_random, 32,
48, conn->master_secret) != 1
|| tls_prf(conn->master_secret, 48, "key expansion",
conn->server_random, 32, // 这里顺序为什么是反的
conn->client_random, 32,
96, conn->key_block) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
// 主力这里是不对的需要为client, server设定不同的加密密钥
sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32);
sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32);
if (conn->is_client) {
sm4_set_encrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_decrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
} else {
sm4_set_decrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_encrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
}
tls_secrets_print(stderr,
conn->pre_master_secret, 48,
conn->client_random, conn->server_random,
conn->master_secret,
conn->key_block, 96,
0, 4);
return 1;
}
int tls_send_client_key_exchange(TLS_CONNECT *conn)
{
int ret;
@@ -1449,6 +1860,80 @@ int tls_recv_client_key_exchange(TLS_CONNECT *conn)
return 1;
}
// 对于TLCP是否应该先执行send_client_key_exchange再生成密钥呢
int tlcp_send_client_key_exchange(TLS_CONNECT *conn)
{
uint8_t enced_pre_master_secret[SM2_MAX_CIPHERTEXT_SIZE];
size_t enced_pre_master_secret_len;
tls_trace("send ClientKeyExchange\n");
if (tls_pre_master_secret_generate(conn->pre_master_secret, TLS_protocol_tlcp) != 1) {
error_print();
return -1;
}
if (sm2_encrypt(&conn->server_enc_key.u.sm2_key, conn->pre_master_secret, 48,
enced_pre_master_secret, &enced_pre_master_secret_len) != 1
|| tls_record_set_handshake_client_key_exchange_pke(conn->record, &conn->recordlen,
enced_pre_master_secret, enced_pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
if (tls_record_send(conn->record, conn->recordlen, conn->sock) != 1) {
error_print();
return -1;
}
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
return 1;
}
int tlcp_recv_client_key_exchange(TLS_CONNECT *conn)
{
const uint8_t *enced_pms;
size_t enced_pms_len;
size_t pre_master_secret_len;
tls_trace("recv ClientKeyExchange\n");
if (tls_record_recv(conn->record, &conn->recordlen, conn->sock) != 1
|| tls_record_protocol(conn->record) != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
tlcp_record_trace(stderr, conn->record, conn->recordlen, 0, 0);
if (tls_record_get_handshake_client_key_exchange_pke(conn->record, &enced_pms, &enced_pms_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
// FIXME:
// 这里需要检查一下密钥的长度,因为输入的长度是确定的,因此输出的密文长度应该也是确定的
if (sm2_decrypt(&conn->kenc_key.u.sm2_key, enced_pms, enced_pms_len,
conn->pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
if (pre_master_secret_len != 48) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
sm3_update(&conn->sm3_ctx, conn->record + 5, conn->recordlen - 5);
return 1;
}
int tls_send_certificate_verify(TLS_CONNECT *conn)
{
int ret;

View File

@@ -46,8 +46,32 @@ static const char *help =
" gmssl tlcp_client -host www.pbc.gov.cn -get / -outcerts certs.pem\n"
"\n"
" gmssl tlcp_client -host www.pbc.gov.cn -port 443\n"
"\n"
"Examples\n"
"\n"
" gmssl sm2keygen -pass 1234 -out rootcakey.pem\n"
" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 -key rootcakey.pem -pass 1234 -out rootcacert.pem -key_usage keyCertSign -key_usage cRLSign -ca\n"
" gmssl sm2keygen -pass 1234 -out cakey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN \"Sub CA\" -key cakey.pem -pass 1234 -out careq.pem\n"
" gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -ca -path_len_constraint 0 -cacert rootcacert.pem -key rootcakey.pem -pass 1234 -out cacert.pem\n"
"\n"
" gmssl sm2keygen -pass 1234 -out signkey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key signkey.pem -pass 1234 -out signreq.pem\n"
" gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem\n"
"\n"
" gmssl sm2keygen -pass 1234 -out enckey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key enckey.pem -pass 1234 -out encreq.pem\n"
" gmssl reqsign -in encreq.pem -days 365 -key_usage keyEncipherment -cacert cacert.pem -key cakey.pem -pass 1234 -out enccert.pem\n"
"\n"
" cat signcert.pem > double_certs.pem\n"
" cat enccert.pem >> double_certs.pem\n"
" cat cacert.pem >> double_certs.pem\n"
"\n"
" sudo gmssl tlcp_server -port 443 -cert double_certs.pem -key signkey.pem -pass 1234 -ex_key enckey.pem -ex_pass 1234\n"
" gmssl tlcp_client -host 127.0.0.1 -cacert rootcacert.pem\n"
"\n";
int tlcp_client_main(int argc, char *argv[])
{
int ret = -1;

View File

@@ -20,6 +20,40 @@
static const char *options = "[-port num] -cert file -key file [-pass str] -ex_key file [-ex_pass str] [-cacert file]";
static const char *help =
"Options\n"
"\n"
" -port num Listening port number, default 443\n"
" -cert file Server's certificate chain in PEM format\n"
" -key file Server's encrypted private key in PEM format\n"
" -pass str Password to decrypt private key\n"
" -cacert file CA certificate for client certificate verification\n"
"\n"
"Examples\n"
"\n"
" gmssl sm2keygen -pass 1234 -out rootcakey.pem\n"
" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 -key rootcakey.pem -pass 1234 -out rootcacert.pem -key_usage keyCertSign -key_usage cRLSign -ca\n"
" gmssl sm2keygen -pass 1234 -out cakey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN \"Sub CA\" -key cakey.pem -pass 1234 -out careq.pem\n"
" gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -ca -path_len_constraint 0 -cacert rootcacert.pem -key rootcakey.pem -pass 1234 -out cacert.pem\n"
"\n"
" gmssl sm2keygen -pass 1234 -out signkey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key signkey.pem -pass 1234 -out signreq.pem\n"
" gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem\n"
"\n"
" gmssl sm2keygen -pass 1234 -out enckey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key enckey.pem -pass 1234 -out encreq.pem\n"
" gmssl reqsign -in encreq.pem -days 365 -key_usage keyEncipherment -cacert cacert.pem -key cakey.pem -pass 1234 -out enccert.pem\n"
"\n"
" cat signcert.pem > double_certs.pem\n"
" cat enccert.pem >> double_certs.pem\n"
" cat cacert.pem >> double_certs.pem\n"
"\n"
" sudo gmssl tlcp_server -port 443 -cert double_certs.pem -key signkey.pem -pass 1234 -ex_key enckey.pem -ex_pass 1234\n"
" gmssl tlcp_client -host 127.0.0.1 -cacert rootcacert.pem\n"
"\n";
int tlcp_server_main(int argc , char **argv)
{
int ret = 1;
@@ -55,6 +89,7 @@ int tlcp_server_main(int argc , char **argv)
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: %s %s\n", prog, options);
printf("%s\n", help);
return 0;
} else if (!strcmp(*argv, "-port")) {
if (--argc < 1) goto bad;

View File

@@ -25,6 +25,40 @@ static const char *http_get =
static const char *options = "-host str [-port num] [-cacert file] [-cert file -key file -pass str]";
static const char *help =
"Options\n"
"\n"
" -host str Server's hostname\n"
" -port num Server's port number, default 443\n"
" -cacert file Root CA certificate\n"
" -cert file Client's certificate chain in PEM format\n"
" -key file Client's encrypted private key in PEM format\n"
" -pass str Password to decrypt private key\n"
"\n"
"Examples\n"
"\n"
" gmssl sm2keygen -pass 1234 -out rootcakey.pem\n"
" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 \\\n"
" -key rootcakey.pem -pass 1234 -out rootcacert.pem \\\n"
" -key_usage keyCertSign -key_usage cRLSign -ca\n"
"\n"
" gmssl sm2keygen -pass 1234 -out cakey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN \"Sub CA\" \\\n"
" -key cakey.pem -pass 1234 -out careq.pem\n"
" gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -cacert rootcacert.pem -key rootcakey.pem -pass 1234 \\\n"
" -out cacert.pem -ca -path_len_constraint 0\n"
"\n"
" gmssl sm2keygen -pass 1234 -out signkey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key signkey.pem -pass 1234 -out signreq.pem\n"
" gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem\n"
"\n"
" cat signcert.pem > certs.pem\n"
" cat cacert.pem >> certs.pem\n"
"\n"
" sudo gmssl tls12_server -port 4430 -cert certs.pem -key signkey.pem -pass 1234\n"
" gmssl tls12_client -host 127.0.0.1 -port 4430 -cacert rootcacert.pem\n"
"\n";
int tls12_client_main(int argc, char *argv[])
{
int ret = -1;
@@ -53,6 +87,7 @@ int tls12_client_main(int argc, char *argv[])
while (argc >= 1) {
if (!strcmp(*argv, "-help")) {
printf("usage: %s %s\n", prog, options);
printf("%s\n", help);
return 0;
} else if (!strcmp(*argv, "-host")) {
if (--argc < 1) goto bad;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
@@ -20,6 +20,40 @@
static const char *options = "[-port num] -cert file -key file -pass str [-cacert file]";
static const char *help =
"Options\n"
"\n"
" -port num Listening port number, default 443\n"
" -cert file Server's certificate chain in PEM format\n"
" -key file Server's encrypted private key in PEM format\n"
" -pass str Password to decrypt private key\n"
" -cacert file CA certificate for client certificate verification\n"
"\n"
"Examples\n"
"\n"
" gmssl sm2keygen -pass 1234 -out rootcakey.pem\n"
" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 \\\n"
" -key rootcakey.pem -pass 1234 -out rootcacert.pem \\\n"
" -key_usage keyCertSign -key_usage cRLSign -ca\n"
"\n"
" gmssl sm2keygen -pass 1234 -out cakey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN \"Sub CA\" \\\n"
" -key cakey.pem -pass 1234 -out careq.pem\n"
" gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -cacert rootcacert.pem -key rootcakey.pem -pass 1234 \\\n"
" -out cacert.pem -ca -path_len_constraint 0\n"
"\n"
" gmssl sm2keygen -pass 1234 -out signkey.pem\n"
" gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key signkey.pem -pass 1234 -out signreq.pem\n"
" gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem\n"
"\n"
" cat signcert.pem > certs.pem\n"
" cat cacert.pem >> certs.pem\n"
"\n"
" sudo gmssl tls12_server -port 4430 -cert certs.pem -key signkey.pem -pass 1234\n"
" gmssl tls12_client -host 127.0.0.1 -port 4430 -cacert rootcacert.pem\n"
"\n";
int tls12_server_main(int argc , char **argv)
{
int ret = 1;
@@ -52,6 +86,7 @@ int tls12_server_main(int argc , char **argv)
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: %s %s\n", prog, options);
printf("%s\n", help);
return 0;
} else if (!strcmp(*argv, "-port")) {
if (--argc < 1) goto bad;