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 #include <unistd.h>
16 #include <netdb.h>
17 #include <sys/types.h>
18 #include <arpa/inet.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <gmssl/tls.h>
22 #include <gmssl/error.h>
23
24
25 static int client_ciphers[] = { TLS_cipher_ecc_sm4_cbc_sm3, };
26
27 static const char *http_get =
28 "GET / HTTP/1.1\r\n"
29 "Hostname: aaa\r\n"
30 "\r\n\r\n";
31
32 static const char *options = "-host str [-port num] [-cacert file] [-cert file -key file -pass str]";
33
tlcp_client_main(int argc,char * argv[])34 int tlcp_client_main(int argc, char *argv[])
35 {
36 int ret = -1;
37 char *prog = argv[0];
38 char *host = NULL;
39 int port = 443;
40 char *cacertfile = NULL;
41 char *certfile = NULL;
42 char *keyfile = NULL;
43 char *pass = NULL;
44 struct hostent *hp;
45 struct sockaddr_in server;
46 int sock;
47 TLS_CTX ctx;
48 TLS_CONNECT conn;
49 char buf[1024] = {0};
50 size_t len = sizeof(buf);
51 char send_buf[1024] = {0};
52 size_t send_len;
53
54 argc--;
55 argv++;
56 if (argc < 1) {
57 fprintf(stderr, "usage: %s %s\n", prog, options);
58 return 1;
59 }
60 while (argc >= 1) {
61 if (!strcmp(*argv, "-help")) {
62 printf("usage: %s %s\n", prog, options);
63 return 0;
64 } else if (!strcmp(*argv, "-host")) {
65 if (--argc < 1) goto bad;
66 host = *(++argv);
67 } else if (!strcmp(*argv, "-port")) {
68 if (--argc < 1) goto bad;
69 port = atoi(*(++argv));
70 } else if (!strcmp(*argv, "-cacert")) {
71 if (--argc < 1) goto bad;
72 cacertfile = *(++argv);
73 } else if (!strcmp(*argv, "-cert")) {
74 if (--argc < 1) goto bad;
75 certfile = *(++argv);
76 } else if (!strcmp(*argv, "-key")) {
77 if (--argc < 1) goto bad;
78 keyfile = *(++argv);
79 } else if (!strcmp(*argv, "-pass")) {
80 if (--argc < 1) goto bad;
81 pass = *(++argv);
82 } else {
83 fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv);
84 return 1;
85 bad:
86 fprintf(stderr, "%s: option '%s' argument required\n", prog, *argv);
87 return 0;
88 }
89 argc--;
90 argv++;
91 }
92
93 if (!host) {
94 fprintf(stderr, "%s: '-in' option required\n", prog);
95 return -1;
96 }
97 if (!(hp = gethostbyname(host))) {
98 herror("tlcp_client: '-host' invalid");
99 goto end;
100 }
101
102 memset(&ctx, 0, sizeof(ctx));
103 memset(&conn, 0, sizeof(conn));
104
105 server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
106 server.sin_family = AF_INET;
107 server.sin_port = htons(port);
108
109 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
110 fprintf(stderr, "%s: open socket error : %s\n", prog, strerror(errno));
111 goto end;
112 }
113 if (connect(sock, (struct sockaddr *)&server , sizeof(server)) < 0) {
114 fprintf(stderr, "%s: connect error : %s\n", prog, strerror(errno));
115 goto end;
116 }
117
118 if (tls_ctx_init(&ctx, TLS_protocol_tlcp, TLS_client_mode) != 1
119 || tls_ctx_set_cipher_suites(&ctx, client_ciphers, sizeof(client_ciphers)/sizeof(client_ciphers[0])) != 1) {
120 fprintf(stderr, "%s: context init error\n", prog);
121 goto end;
122 }
123 if (cacertfile) {
124 if (tls_ctx_set_ca_certificates(&ctx, cacertfile, TLS_DEFAULT_VERIFY_DEPTH) != 1) {
125 fprintf(stderr, "%s: context init error\n", prog);
126 goto end;
127 }
128 }
129 if (certfile) {
130 if (tls_ctx_set_certificate_and_key(&ctx, certfile, keyfile, pass) != 1) {
131 fprintf(stderr, "%s: context init error\n", prog);
132 goto end;
133 }
134 }
135
136
137 if (tls_init(&conn, &ctx) != 1
138 || tls_set_socket(&conn, sock) != 1
139 || tls_do_handshake(&conn) != 1) {
140 fprintf(stderr, "%s: error\n", prog);
141 goto end;
142 }
143
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 (tls_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 fprintf(stderr, "recv from stdin\n");
177
178 memset(send_buf, 0, sizeof(send_buf));
179
180 if (!fgets(send_buf, sizeof(send_buf), stdin)) {
181 if (feof(stdin)) {
182 tls_shutdown(&conn);
183 goto end;
184 } else {
185 continue;
186 }
187 }
188 if (tls_send(&conn, (uint8_t *)send_buf, strlen(send_buf), &sentlen) != 1) {
189 fprintf(stderr, "%s: send error\n", prog);
190 goto end;
191 }
192 }
193
194 fprintf(stderr, "end of this round\n");
195 }
196
197
198 end:
199 close(sock);
200 tls_ctx_cleanup(&ctx);
201 tls_cleanup(&conn);
202 return 0;
203 }
204