• 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 
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_ecdhe_sm4_cbc_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 
tls12_client_main(int argc,char * argv[])37 int tls12_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("tls12_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_tls12, 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 
140 	if (tls_init(&conn, &ctx) != 1
141 		|| tls_set_socket(&conn, sock) != 1
142 		|| tls_do_handshake(&conn) != 1) {
143 		fprintf(stderr, "%s: error\n", prog);
144 		goto end;
145 	}
146 
147 	for (;;) {
148 		fd_set fds;
149 		size_t sentlen;
150 
151 		FD_ZERO(&fds);
152 		FD_SET(conn.sock, &fds);
153 		FD_SET(STDIN_FILENO, &fds);
154 
155 		if (select(conn.sock + 1, &fds, NULL, NULL, NULL) < 0) {
156 			fprintf(stderr, "%s: select failed\n", prog);
157 			goto end;
158 		}
159 
160 		if (FD_ISSET(conn.sock, &fds)) {
161 			for (;;) {
162 				memset(buf, 0, sizeof(buf));
163 				if (tls_recv(&conn, (uint8_t *)buf, sizeof(buf), &len) != 1) {
164 					goto end;
165 				}
166 				fwrite(buf, 1, len, stdout);
167 				fflush(stdout);
168 
169 				// 应该调整tls_recv 逻辑、API或者其他方式
170 				if (conn.datalen == 0) {
171 					break;
172 				}
173 			}
174 
175 		}
176 		if (FD_ISSET(STDIN_FILENO, &fds)) {
177 			memset(send_buf, 0, sizeof(send_buf));
178 
179 			if (!fgets(send_buf, sizeof(send_buf), stdin)) {
180 				if (feof(stdin)) {
181 					tls_shutdown(&conn);
182 					goto end;
183 				} else {
184 					continue;
185 				}
186 			}
187 			if (tls_send(&conn, (uint8_t *)send_buf, strlen(send_buf), &sentlen) != 1) {
188 				fprintf(stderr, "%s: send error\n", prog);
189 				goto end;
190 			}
191 		}
192 	}
193 
194 
195 end:
196 	close(sock);
197 	tls_ctx_cleanup(&ctx);
198 	tls_cleanup(&conn);
199 	return 0;
200 }
201