From 9f2bfb5ad0be8d46eed8c32284025372eb54c629 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Mon, 5 Feb 2024 17:01:09 +0800 Subject: [PATCH] Add more options to TLS add `-get` and `-quiet` option to `tlcp_client` --- include/gmssl/tls.h | 3 ++ src/tlcp.c | 34 +++++++++++-------- src/tls.c | 2 ++ src/tls12.c | 7 ++-- src/tls13.c | 11 +++++-- src/tls_trace.c | 52 +++++++++++++---------------- tools/tlcp_client.c | 80 +++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 135 insertions(+), 54 deletions(-) diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index fee27c3b4..c03b0c1a1 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -684,6 +684,8 @@ typedef struct { SM2_KEY signkey; SM2_KEY kenckey; int verify_depth; + + int quiet; } TLS_CTX; int tls_ctx_init(TLS_CTX *ctx, int protocol, int is_client); @@ -751,6 +753,7 @@ typedef struct { BLOCK_CIPHER_KEY client_write_key; BLOCK_CIPHER_KEY server_write_key; + int quiet; } TLS_CONNECT; diff --git a/src/tlcp.c b/src/tlcp.c index 014734f10..a3308c6e9 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2024 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. @@ -28,15 +28,6 @@ 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]); -void printbyte(uint8_t *ptr, int len, char *name) { - fprintf(stderr, "%s", name); - for (int i = 0; i < len; i++) { - if (i % 16 == 0) - fprintf(stderr, "\n"); - fprintf(stderr, "0x%02X ", ptr[i]); - } - fprintf(stderr, "\n"); -} int tlcp_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int format, int indent) { @@ -46,6 +37,19 @@ 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: + digitall-signed struct { + opaque client_random[32]; + opaque server_random[32]; + opaque ASN1.Cert<1..2^24-1>; + } signed_params; + } +} ServerKeyExchange; + +-- in TLCP 1.1, the `signed_params` is DER signature encoded in uint16array +*/ int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *recordlen, const uint8_t *sig, size_t siglen) { @@ -66,8 +70,6 @@ int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *r return -1; } p = tls_handshake_data(tls_record_data(record)); - // 注意TLCP的ServerKeyExchange中的签名值需要封装在uint16array中 - // 但是CertificateVerify中直接装载签名值DER tls_uint16array_to_bytes(sig, siglen, &p, &len); tls_record_set_handshake(record, recordlen, type, NULL, len); return 1; @@ -556,7 +558,9 @@ int tlcp_do_connect(TLS_CONNECT *conn) tls_send_alert(conn, TLS_alert_decrypt_error); goto end; } - fprintf(stderr, "Connection established!\n"); + + if (!conn->quiet) + fprintf(stderr, "Connection established!\n"); conn->protocol = TLS_protocol_tlcp; @@ -996,7 +1000,9 @@ int tlcp_do_accept(TLS_CONNECT *conn) conn->protocol = TLS_protocol_tlcp; - fprintf(stderr, "Connection Established!\n\n"); + if (!conn->quiet) + fprintf(stderr, "Connection Established!\n\n"); + ret = 1; end: diff --git a/src/tls.c b/src/tls.c index acd4a852e..54d4047c4 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2298,6 +2298,8 @@ int tls_init(TLS_CONNECT *conn, const TLS_CTX *ctx) conn->sign_key = ctx->signkey; conn->kenc_key = ctx->kenckey; + conn->quiet = ctx->quiet; + return 1; } diff --git a/src/tls12.c b/src/tls12.c index 9238df100..72b196ada 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -630,8 +630,9 @@ int tls12_do_connect(TLS_CONNECT *conn) tls_send_alert(conn, TLS_alert_decrypt_error); goto end; } - fprintf(stderr, "Connection established!\n"); + if (!conn->quiet) + fprintf(stderr, "Connection established!\n"); conn->protocol = conn->protocol; conn->cipher_suite = cipher_suite; @@ -1061,7 +1062,9 @@ int tls12_do_accept(TLS_CONNECT *conn) conn->protocol = conn->protocol; - fprintf(stderr, "Connection Established!\n\n"); + if (!conn->quiet) + fprintf(stderr, "Connection Established!\n\n"); + ret = 1; end: diff --git a/src/tls13.c b/src/tls13.c index 1890cc088..a6c6c6697 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2024 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. @@ -1887,7 +1887,10 @@ int tls13_do_connect(TLS_CONNECT *conn) format_bytes(stderr, 0, 4, "client_write_iv", conn->client_write_iv, 12); format_print(stderr, 0, 0, "\n"); */ - fprintf(stderr, "Connection established\n"); + + if (!conn->quiet) + fprintf(stderr, "Connection established\n"); + ret = 1; end: @@ -2354,7 +2357,9 @@ int tls13_do_accept(TLS_CONNECT *conn) format_print(stderr, 0, 0, "\n"); */ - fprintf(stderr, "Connection Established!\n\n"); + if (!conn->quiet) + fprintf(stderr, "Connection Established!\n\n"); + ret = 1; end: gmssl_secure_clear(&server_ecdhe, sizeof(server_ecdhe)); diff --git a/src/tls_trace.c b/src/tls_trace.c index 372d2237e..81a4b992f 100644 --- a/src/tls_trace.c +++ b/src/tls_trace.c @@ -344,7 +344,23 @@ int tls_pre_master_secret_print(FILE *fp, const uint8_t pre_master_secret[48], i return 1; } -// supported_versions 的格式还受到 handshake_type 影响 +/* + * SupportedVersions Extension (only defined in TLS 1.3) + * + * In ClientHello: + * struct { + * ProtocolVersion versions<2..254>; + * } SupportedVersions; + * + * In ServerHello: + * struct { + * ProtocolVersion selected_version; + * } SupportedVersions; + * + +这个函数需要一个参数表示扩展是在ClientHello还是在ServerHello中 + + */ int tls_extension_print(FILE *fp, int type, const uint8_t *data, size_t datalen, int format, int indent) { const uint8_t *p; @@ -354,6 +370,7 @@ int tls_extension_print(FILE *fp, int type, const uint8_t *data, size_t datalen, indent += 4; switch (type) { + // FIXME: 不支持ServerHello case TLS_extension_supported_versions: if (tls_uint16array_from_bytes(&p, &len, &data, &datalen) != 1 || tls_length_is_zero(datalen) != 1 @@ -846,6 +863,7 @@ int tls_finished_print(FILE *fp, const uint8_t *data, size_t datalen, int format return 1; } +// FIXME: 应该将这个函数融合到 tls_handshake_print 中 int tls13_handshake_print(FILE *fp, int fmt, int ind, const uint8_t *handshake, size_t handshake_len) { const uint8_t *p = handshake; @@ -1052,6 +1070,7 @@ int tls13_record_print(FILE *fp, int format, int indent, const uint8_t *record, } +// FIXME: 需要根据RFC来考虑这个函数的参数,从底向上逐步修改每个函数的接口参数 // 仅从record数据是不能判断这个record是TLS 1.2还是TLS 1.3 // 不同协议上,同名的握手消息,其格式也是不一样的。这真是太恶心了!!!! @@ -1130,34 +1149,6 @@ int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int for fprintf(fp, "\n"); return 1; - - - - - - - - - - - - - - - - - - - - - - - - - - - - } int tls_secrets_print(FILE *fp, @@ -1168,6 +1159,9 @@ int tls_secrets_print(FILE *fp, int format, int indent) { // 应该检查一下key_block_len的值,判断是否支持,或者算法选择, 或者要求输入一个cipher_suite参数 + // 这个函数不支持GCM模式套件,使用GCM模式时key_block_len更短 + // 可以考虑通过key_block_len判断CBC还是GCM,或者在参数上增加cipher_suite + // FIXME: 如果增加了GCM套件,需要更新这个函数 format_bytes(stderr, format, indent, "pre_master_secret", pre_master_secret, pre_master_secret_len); format_bytes(stderr, format, indent, "client_random", client_random, 32); format_bytes(stderr, format, indent, "server_random", server_random, 32); diff --git a/tools/tlcp_client.c b/tools/tlcp_client.c index a4aecc235..dfe146d8f 100644 --- a/tools/tlcp_client.c +++ b/tools/tlcp_client.c @@ -13,17 +13,19 @@ #include #include #include +#include #include +#define TIMEOUT_SECONDS 1 + static int client_ciphers[] = { TLS_cipher_ecc_sm4_cbc_sm3, }; -static const char *http_get = - "GET / HTTP/1.1\r\n" - "Hostname: aaa\r\n" - "\r\n\r\n"; -static const char *options = "-host str [-port num] [-cacert file] [-cert file -key file -pass str]"; +static const char *options = "-host str [-port num] [-cacert file] [-cert file -key file -pass str]" + " -quiet" + " -get [path]" + " [-outcerts file]"; int tlcp_client_main(int argc, char *argv[]) { @@ -35,6 +37,9 @@ int tlcp_client_main(int argc, char *argv[]) char *certfile = NULL; char *keyfile = NULL; char *pass = NULL; + char *get = NULL; + char *outcertsfile = NULL; + int quiet = 0; struct hostent *hp; struct sockaddr_in server; tls_socket_t sock; @@ -44,6 +49,7 @@ int tlcp_client_main(int argc, char *argv[]) char buf[1024] = {0}; size_t len = sizeof(buf); char send_buf[1024] = {0}; + size_t sentlen; argc--; argv++; @@ -73,6 +79,14 @@ int tlcp_client_main(int argc, char *argv[]) } else if (!strcmp(*argv, "-pass")) { if (--argc < 1) goto bad; pass = *(++argv); + } else if (!strcmp(*argv, "-get")) { + if (--argc < 1) goto bad; + get = *(++argv); + } else if (!strcmp(*argv, "-outcerts")) { + if (--argc < 1) goto bad; + outcertsfile = *(++argv); + } else if (!strcmp(*argv, "-quiet")) { + quiet = 1; } else { fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv); return 1; @@ -135,6 +149,9 @@ int tlcp_client_main(int argc, char *argv[]) goto end; } } + if (quiet || get) { + ctx.quiet = 1; + } if (tls_init(&conn, &ctx) != 1 || tls_set_socket(&conn, sock) != 1 @@ -143,9 +160,60 @@ int tlcp_client_main(int argc, char *argv[]) goto end; } + if (outcertsfile) { + FILE *outcertsfp; + if (!(outcertsfp = fopen(outcertsfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure\n", prog, outcertsfile); + perror("fopen"); + goto end; + } + if (x509_certs_to_pem(conn.server_certs, conn.server_certs_len, outcertsfp) != 1) { + fprintf(stderr, "%s: x509_certs_to_pem error\n", prog); + fclose(outcertsfp); + goto end; + } + fclose(outcertsfp); + } + + if (get) { + struct timeval timeout; + timeout.tv_sec = TIMEOUT_SECONDS; + timeout.tv_usec = 0; + + snprintf(buf, sizeof(buf), "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", get, host); + + if (tls_send(&conn, (uint8_t *)buf, strlen(buf), &len) != 1) { + fprintf(stderr, "%s: send error\n", prog); + goto end; + } + + if (setsockopt(conn.sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) != 0) { + perror("setsockopt"); + fprintf(stderr, "%s: set socket timeout error\n", prog); + goto end; + } + + for (;;) { + int ret; + if ((ret = tls_recv(&conn, (uint8_t *)buf, sizeof(buf), &len)) != 1) { + if (ret == 0) { + fprintf(stderr, "%s: TLCP connection is closed by remote host\n", prog); + } else if (ret != -EAGAIN) { + fprintf(stderr, "%s: recv error\n", prog); + } + break; + } + fwrite(buf, 1, len, stdout); + fflush(stdout); + } + + tls_shutdown(&conn); + goto end; + } + + for (;;) { fd_set fds; - size_t sentlen; if (!fgets(send_buf, sizeof(send_buf), stdin)) { if (feof(stdin)) {