1 /*
2 * Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the License); you may
5 * not use this file except in compliance with the License.
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 */
9
10
11 #include <stdio.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <stdlib.h>
15
16 #include <unistd.h>
17 #include <netdb.h>
18 #include <sys/types.h>
19 #include <arpa/inet.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <gmssl/tls.h>
23 #include <gmssl/error.h>
24
25
26 // TLSv1.2客户单和TLCP客户端可能没有什么区别
27
28 static int client_ciphers[] = { TLS_cipher_sm4_gcm_sm3 };
29
30 static const char *http_get =
31 "GET / HTTP/1.1\r\n"
32 "Hostname: aaa\r\n"
33 "\r\n\r\n";
34
35 static const char *options = "-host str [-port num] [-cacert file] [-cert file -key file -pass str]";
36
tls13_client_main(int argc,char * argv[])37 int tls13_client_main(int argc, char *argv[])
38 {
39 int ret = -1;
40 char *prog = argv[0];
41 char *host = NULL;
42 int port = 443;
43 char *cacertfile = NULL;
44 char *certfile = NULL;
45 char *keyfile = NULL;
46 char *pass = NULL;
47 struct hostent *hp;
48 struct sockaddr_in server;
49 int sock;
50 TLS_CTX ctx;
51 TLS_CONNECT conn;
52 char buf[1024] = {0};
53 size_t len = sizeof(buf);
54 char send_buf[1024] = {0};
55 size_t send_len;
56
57 argc--;
58 argv++;
59 if (argc < 1) {
60 fprintf(stderr, "usage: %s %s\n", prog, options);
61 return 1;
62 }
63 while (argc >= 1) {
64 if (!strcmp(*argv, "-help")) {
65 printf("usage: %s %s\n", prog, options);
66 return 0;
67 } else if (!strcmp(*argv, "-host")) {
68 if (--argc < 1) goto bad;
69 host = *(++argv);
70 } else if (!strcmp(*argv, "-port")) {
71 if (--argc < 1) goto bad;
72 port = atoi(*(++argv));
73 } else if (!strcmp(*argv, "-cacert")) {
74 if (--argc < 1) goto bad;
75 cacertfile = *(++argv);
76 } else if (!strcmp(*argv, "-cert")) {
77 if (--argc < 1) goto bad;
78 certfile = *(++argv);
79 } else if (!strcmp(*argv, "-key")) {
80 if (--argc < 1) goto bad;
81 keyfile = *(++argv);
82 } else if (!strcmp(*argv, "-pass")) {
83 if (--argc < 1) goto bad;
84 pass = *(++argv);
85 } else {
86 fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv);
87 return 1;
88 bad:
89 fprintf(stderr, "%s: option '%s' argument required\n", prog, *argv);
90 return 0;
91 }
92 argc--;
93 argv++;
94 }
95
96 if (!host) {
97 fprintf(stderr, "%s: '-in' option required\n", prog);
98 return -1;
99 }
100 if (!(hp = gethostbyname(host))) {
101 herror("tls13_client: '-host' invalid");
102 goto end;
103 }
104
105 memset(&ctx, 0, sizeof(ctx));
106 memset(&conn, 0, sizeof(conn));
107
108 server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
109 server.sin_family = AF_INET;
110 server.sin_port = htons(port);
111
112
113 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
114 fprintf(stderr, "%s: open socket error : %s\n", prog, strerror(errno));
115 goto end;
116 }
117 if (connect(sock, (struct sockaddr *)&server , sizeof(server)) < 0) {
118 fprintf(stderr, "%s: connect error : %s\n", prog, strerror(errno));
119 goto end;
120 }
121
122 if (tls_ctx_init(&ctx, TLS_protocol_tls13, TLS_client_mode) != 1
123 || tls_ctx_set_cipher_suites(&ctx, client_ciphers, sizeof(client_ciphers)/sizeof(client_ciphers[0])) != 1) {
124 fprintf(stderr, "%s: context init error\n", prog);
125 goto end;
126 }
127 if (cacertfile) {
128 if (tls_ctx_set_ca_certificates(&ctx, cacertfile, TLS_DEFAULT_VERIFY_DEPTH) != 1) {
129 fprintf(stderr, "%s: context init error\n", prog);
130 goto end;
131 }
132 }
133 if (certfile) {
134 if (tls_ctx_set_certificate_and_key(&ctx, certfile, keyfile, pass) != 1) {
135 fprintf(stderr, "%s: context init error\n", prog);
136 goto end;
137 }
138 }
139 if (tls_init(&conn, &ctx) != 1
140 || tls_set_socket(&conn, sock) != 1
141 || tls_do_handshake(&conn) != 1) {
142 fprintf(stderr, "%s: error\n", prog);
143 goto end;
144 }
145
146 for (;;) {
147 fd_set fds;
148 size_t sentlen;
149
150 FD_ZERO(&fds);
151 FD_SET(conn.sock, &fds);
152 FD_SET(STDIN_FILENO, &fds);
153
154 if (select(conn.sock + 1, &fds, NULL, NULL, NULL) < 0) {
155 fprintf(stderr, "%s: select failed\n", prog);
156 goto end;
157 }
158
159 if (FD_ISSET(conn.sock, &fds)) {
160 for (;;) {
161 memset(buf, 0, sizeof(buf));
162 if (tls13_recv(&conn, (uint8_t *)buf, sizeof(buf), &len) != 1) {
163 goto end;
164 }
165 fwrite(buf, 1, len, stdout);
166 fflush(stdout);
167
168 // 应该调整tls_recv 逻辑、API或者其他方式
169 if (conn.datalen == 0) {
170 break;
171 }
172 }
173
174 }
175 if (FD_ISSET(STDIN_FILENO, &fds)) {
176 memset(send_buf, 0, sizeof(send_buf));
177
178 if (!fgets(send_buf, sizeof(send_buf), stdin)) {
179 if (feof(stdin)) {
180 tls_shutdown(&conn);
181 goto end;
182 } else {
183 continue;
184 }
185 }
186 if (tls13_send(&conn, (uint8_t *)send_buf, strlen(send_buf), &sentlen) != 1) {
187 fprintf(stderr, "%s: send error\n", prog);
188 goto end;
189 }
190 }
191 }
192
193 end:
194 close(sock);
195 tls_ctx_cleanup(&ctx);
196 tls_cleanup(&conn);
197 return 0;
198 }
199