• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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