diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index e63fd1f1..2802b589 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -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 diff --git a/src/sm2_sign.c b/src/sm2_sign.c index 6aff3b0a..597a385d 100644 --- a/src/sm2_sign.c +++ b/src/sm2_sign.c @@ -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; diff --git a/src/tlcp.c b/src/tlcp.c index b71da301..67b0ac0a 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -25,6 +25,21 @@ #include +// 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; @@ -680,7 +708,7 @@ int tlcp_do_accept(TLS_CONNECT *conn) goto end; } if (exts) { - // 忽略客户端扩展错误可以兼容错误的TLCP客户端实现 + // 忽略客户端扩展错误可以兼容错误的TLCP客户端实现 error_print(); tls_send_alert(conn, TLS_alert_unexpected_message); goto end; @@ -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; +} + diff --git a/src/tls.c b/src/tls.c index 3a3e22ca..09a776b1 100644 --- a/src/tls.c +++ b/src/tls.c @@ -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; } diff --git a/src/tls12.c b/src/tls12.c index ec7c631a..cac299c7 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -27,14 +27,13 @@ #include #include - - 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; - tls_record_set_protocol(record, TLS_protocol_tls1); + 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,24 +785,33 @@ 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; - } - 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 - || signature_algor < 0) { - 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 + || signature_algor < 0) { + error_print(); + tls_send_alert(conn, TLS_alert_unexpected_message); + return -1; + } } memcpy(conn->server_random, server_random, 32); @@ -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,16 +943,96 @@ int tls_recv_server_certificate(TLS_CONNECT *conn) assert(conn->verify_depth > 0 && conn->verify_depth < 10); // verify ServerCertificate - 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) { + + 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(); - tls_send_alert(conn, TLS_alert_bad_certificate); 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; +} + int tls_send_server_key_exchange(TLS_CONNECT *conn) { int ret; @@ -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; diff --git a/tools/tlcp_client.c b/tools/tlcp_client.c index 87377435..931a66d5 100644 --- a/tools/tlcp_client.c +++ b/tools/tlcp_client.c @@ -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; diff --git a/tools/tlcp_server.c b/tools/tlcp_server.c index 1a1ffdc7..6eb12dea 100644 --- a/tools/tlcp_server.c +++ b/tools/tlcp_server.c @@ -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; diff --git a/tools/tls12_client.c b/tools/tls12_client.c index 5041dea2..c96eaec1 100644 --- a/tools/tls12_client.c +++ b/tools/tls12_client.c @@ -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; diff --git a/tools/tls12_server.c b/tools/tls12_server.c index 944e7cbd..b10cd8f0 100644 --- a/tools/tls12_server.c +++ b/tools/tls12_server.c @@ -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;