3b462a8495944eb3c496ac25d1d9362dadee2e84
[BearSSL] / tools / client.c
1 /*
2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <errno.h>
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <sys/poll.h>
39
40 #include "brssl.h"
41 #include "bearssl.h"
42
43 static int
44 host_connect(const char *host, const char *port, int verbose)
45 {
46 struct addrinfo hints, *si, *p;
47 int fd;
48 int err;
49
50 memset(&hints, 0, sizeof hints);
51 hints.ai_family = PF_UNSPEC;
52 hints.ai_socktype = SOCK_STREAM;
53 err = getaddrinfo(host, port, &hints, &si);
54 if (err != 0) {
55 fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
56 gai_strerror(err));
57 return -1;
58 }
59 fd = -1;
60 for (p = si; p != NULL; p = p->ai_next) {
61 struct sockaddr *sa;
62 void *addr;
63 char tmp[INET6_ADDRSTRLEN + 50];
64
65 sa = (struct sockaddr *)p->ai_addr;
66 if (sa->sa_family == AF_INET) {
67 addr = &((struct sockaddr_in *)sa)->sin_addr;
68 } else if (sa->sa_family == AF_INET6) {
69 addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
70 } else {
71 addr = NULL;
72 }
73 if (addr != NULL) {
74 inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
75 } else {
76 sprintf(tmp, "<unknown family: %d>",
77 (int)sa->sa_family);
78 }
79 if (verbose) {
80 fprintf(stderr, "connecting to: %s\n", tmp);
81 }
82 fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
83 if (fd < 0) {
84 if (verbose) {
85 perror("socket()");
86 }
87 continue;
88 }
89 if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
90 if (verbose) {
91 perror("connect()");
92 }
93 close(fd);
94 continue;
95 }
96 break;
97 }
98 if (p == NULL) {
99 freeaddrinfo(si);
100 fprintf(stderr, "ERROR: failed to connect\n");
101 return -1;
102 }
103 freeaddrinfo(si);
104 if (verbose) {
105 fprintf(stderr, "connected.\n");
106 }
107
108 /*
109 * We make the socket non-blocking, since we are going to use
110 * poll() to organise I/O.
111 */
112 fcntl(fd, F_SETFL, O_NONBLOCK);
113 return fd;
114 }
115
116 static void
117 usage_client(void)
118 {
119 fprintf(stderr,
120 "usage: brssl client server[:port] [ options ]\n");
121 fprintf(stderr,
122 "options:\n");
123 fprintf(stderr,
124 " -q suppress verbose messages\n");
125 fprintf(stderr,
126 " -trace activate extra debug messages (dump of all packets)\n");
127 fprintf(stderr,
128 " -sni name use this specific name for SNI\n");
129 fprintf(stderr,
130 " -nosni do not send any SNI\n");
131 fprintf(stderr,
132 " -mono use monodirectional buffering\n");
133 fprintf(stderr,
134 " -buf length set the I/O buffer length (in bytes)\n");
135 fprintf(stderr,
136 " -CA file add certificates in 'file' to trust anchors\n");
137 fprintf(stderr,
138 " -list list supported names (protocols, algorithms...)\n");
139 fprintf(stderr,
140 " -vmin name set minimum supported version (default: TLS-1.0)\n");
141 fprintf(stderr,
142 " -vmax name set maximum supported version (default: TLS-1.2)\n");
143 fprintf(stderr,
144 " -cs names set list of supported cipher suites (comma-separated)\n");
145 fprintf(stderr,
146 " -hf names add support for some hash functions (comma-separated)\n");
147 }
148
149 /* see brssl.h */
150 int
151 do_client(int argc, char *argv[])
152 {
153 int retcode;
154 int verbose;
155 int trace;
156 int i, bidi;
157 const char *server_name;
158 char *host;
159 char *port;
160 const char *sni;
161 anchor_list anchors = VEC_INIT;
162 unsigned vmin, vmax;
163 cipher_suite *suites;
164 size_t num_suites;
165 uint16_t *suite_ids;
166 unsigned hfuns;
167 size_t u;
168 br_ssl_client_context cc;
169 br_x509_minimal_context xc;
170 x509_noanchor_context xwc;
171 const br_hash_class *dnhash;
172 unsigned char *iobuf;
173 size_t iobuf_len;
174 int fd;
175
176 retcode = 0;
177 verbose = 1;
178 trace = 0;
179 server_name = NULL;
180 host = NULL;
181 port = NULL;
182 sni = NULL;
183 bidi = 1;
184 vmin = 0;
185 vmax = 0;
186 suites = NULL;
187 num_suites = 0;
188 hfuns = 0;
189 suite_ids = NULL;
190 iobuf = NULL;
191 iobuf_len = 0;
192 fd = -1;
193 for (i = 0; i < argc; i ++) {
194 const char *arg;
195
196 arg = argv[i];
197 if (arg[0] != '-') {
198 if (server_name != NULL) {
199 fprintf(stderr,
200 "ERROR: duplicate server name\n");
201 usage_client();
202 goto client_exit_error;
203 }
204 server_name = arg;
205 continue;
206 }
207 if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
208 verbose = 1;
209 } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
210 verbose = 0;
211 } else if (eqstr(arg, "-trace")) {
212 trace = 1;
213 } else if (eqstr(arg, "-sni")) {
214 if (++ i >= argc) {
215 fprintf(stderr,
216 "ERROR: no argument for '-sni'\n");
217 usage_client();
218 goto client_exit_error;
219 }
220 if (sni != NULL) {
221 fprintf(stderr, "ERROR: duplicate SNI\n");
222 usage_client();
223 goto client_exit_error;
224 }
225 sni = argv[i];
226 } else if (eqstr(arg, "-nosni")) {
227 if (sni != NULL) {
228 fprintf(stderr, "ERROR: duplicate SNI\n");
229 usage_client();
230 goto client_exit_error;
231 }
232 sni = "";
233 } else if (eqstr(arg, "-mono")) {
234 bidi = 0;
235 } else if (eqstr(arg, "-buf")) {
236 if (++ i >= argc) {
237 fprintf(stderr,
238 "ERROR: no argument for '-buf'\n");
239 usage_client();
240 goto client_exit_error;
241 }
242 arg = argv[i];
243 if (iobuf_len != 0) {
244 fprintf(stderr,
245 "ERROR: duplicate I/O buffer length\n");
246 usage_client();
247 goto client_exit_error;
248 }
249 iobuf_len = strtoul(arg, 0, 10);
250 } else if (eqstr(arg, "-CA")) {
251 if (++ i >= argc) {
252 fprintf(stderr,
253 "ERROR: no argument for '-CA'\n");
254 usage_client();
255 goto client_exit_error;
256 }
257 arg = argv[i];
258 if (read_trust_anchors(&anchors, arg) == 0) {
259 usage_client();
260 goto client_exit_error;
261 }
262 } else if (eqstr(arg, "-list")) {
263 list_names();
264 goto client_exit;
265 } else if (eqstr(arg, "-vmin")) {
266 if (++ i >= argc) {
267 fprintf(stderr,
268 "ERROR: no argument for '-vmin'\n");
269 usage_client();
270 goto client_exit_error;
271 }
272 arg = argv[i];
273 if (vmin != 0) {
274 fprintf(stderr,
275 "ERROR: duplicate minimum version\n");
276 usage_client();
277 goto client_exit_error;
278 }
279 vmin = parse_version(arg, strlen(arg));
280 if (vmin == 0) {
281 fprintf(stderr,
282 "ERROR: unrecognised version '%s'\n",
283 arg);
284 usage_client();
285 goto client_exit_error;
286 }
287 } else if (eqstr(arg, "-vmax")) {
288 if (++ i >= argc) {
289 fprintf(stderr,
290 "ERROR: no argument for '-vmax'\n");
291 usage_client();
292 goto client_exit_error;
293 }
294 arg = argv[i];
295 if (vmax != 0) {
296 fprintf(stderr,
297 "ERROR: duplicate maximum version\n");
298 usage_client();
299 goto client_exit_error;
300 }
301 vmax = parse_version(arg, strlen(arg));
302 if (vmax == 0) {
303 fprintf(stderr,
304 "ERROR: unrecognised version '%s'\n",
305 arg);
306 usage_client();
307 goto client_exit_error;
308 }
309 } else if (eqstr(arg, "-cs")) {
310 if (++ i >= argc) {
311 fprintf(stderr,
312 "ERROR: no argument for '-cs'\n");
313 usage_client();
314 goto client_exit_error;
315 }
316 arg = argv[i];
317 if (suites != NULL) {
318 fprintf(stderr, "ERROR: duplicate list"
319 " of cipher suites\n");
320 usage_client();
321 goto client_exit_error;
322 }
323 suites = parse_suites(arg, &num_suites);
324 if (suites == NULL) {
325 usage_client();
326 goto client_exit_error;
327 }
328 } else if (eqstr(arg, "-hf")) {
329 unsigned x;
330
331 if (++ i >= argc) {
332 fprintf(stderr,
333 "ERROR: no argument for '-hf'\n");
334 usage_client();
335 goto client_exit_error;
336 }
337 arg = argv[i];
338 x = parse_hash_functions(arg);
339 if (x == 0) {
340 usage_client();
341 goto client_exit_error;
342 }
343 hfuns |= x;
344 } else {
345 fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
346 usage_client();
347 goto client_exit_error;
348 }
349 }
350 if (server_name == NULL) {
351 fprintf(stderr, "ERROR: no server name/address provided\n");
352 usage_client();
353 goto client_exit_error;
354 }
355 for (u = strlen(server_name); u > 0; u --) {
356 int c = server_name[u - 1];
357 if (c == ':') {
358 break;
359 }
360 if (c < '0' || c > '9') {
361 u = 0;
362 break;
363 }
364 }
365 if (u == 0) {
366 host = xstrdup(server_name);
367 port = "443";
368 } else {
369 port = xstrdup(server_name + u);
370 host = xmalloc(u);
371 memcpy(host, server_name, u - 1);
372 host[u - 1] = 0;
373 }
374 if (sni == NULL) {
375 sni = host;
376 }
377
378 if (vmin == 0) {
379 vmin = BR_TLS10;
380 }
381 if (vmax == 0) {
382 vmax = BR_TLS12;
383 }
384 if (vmax < vmin) {
385 fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
386 " version combination\n");
387 usage_client();
388 goto client_exit_error;
389 }
390 if (suites == NULL) {
391 num_suites = 0;
392
393 for (u = 0; cipher_suites[u].name; u ++) {
394 if ((cipher_suites[u].req & REQ_TLS12) == 0
395 || vmax >= BR_TLS12)
396 {
397 num_suites ++;
398 }
399 }
400 suites = xmalloc(num_suites * sizeof *suites);
401 num_suites = 0;
402 for (u = 0; cipher_suites[u].name; u ++) {
403 if ((cipher_suites[u].req & REQ_TLS12) == 0
404 || vmax >= BR_TLS12)
405 {
406 suites[num_suites ++] = cipher_suites[u];
407 }
408 }
409 }
410 if (hfuns == 0) {
411 hfuns = (unsigned)-1;
412 }
413 if (iobuf_len == 0) {
414 if (bidi) {
415 iobuf_len = BR_SSL_BUFSIZE_BIDI;
416 } else {
417 iobuf_len = BR_SSL_BUFSIZE_MONO;
418 }
419 }
420 iobuf = xmalloc(iobuf_len);
421
422 /*
423 * Compute implementation requirements and inject implementations.
424 */
425 suite_ids = xmalloc(num_suites * sizeof *suite_ids);
426 br_ssl_client_zero(&cc);
427 br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
428 dnhash = NULL;
429 for (u = 0; hash_functions[u].name; u ++) {
430 const br_hash_class *hc;
431 int id;
432
433 hc = hash_functions[u].hclass;
434 id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
435 if ((hfuns & ((unsigned)1 << id)) != 0) {
436 dnhash = hc;
437 }
438 }
439 if (dnhash == NULL) {
440 fprintf(stderr, "ERROR: no supported hash function\n");
441 goto client_exit_error;
442 }
443 br_x509_minimal_init(&xc, dnhash,
444 &VEC_ELT(anchors, 0), VEC_LEN(anchors));
445 if (vmin <= BR_TLS11) {
446 if (!(hfuns & (1 << br_md5_ID))) {
447 fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
448 goto client_exit_error;
449 }
450 if (!(hfuns & (1 << br_sha1_ID))) {
451 fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
452 goto client_exit_error;
453 }
454 }
455 for (u = 0; u < num_suites; u ++) {
456 unsigned req;
457
458 req = suites[u].req;
459 suite_ids[u] = suites[u].suite;
460 if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
461 fprintf(stderr,
462 "ERROR: cipher suite %s requires TLS 1.2\n",
463 suites[u].name);
464 goto client_exit_error;
465 }
466 if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
467 fprintf(stderr,
468 "ERROR: cipher suite %s requires SHA-1\n",
469 suites[u].name);
470 goto client_exit_error;
471 }
472 if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
473 fprintf(stderr,
474 "ERROR: cipher suite %s requires SHA-256\n",
475 suites[u].name);
476 goto client_exit_error;
477 }
478 if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
479 fprintf(stderr,
480 "ERROR: cipher suite %s requires SHA-384\n",
481 suites[u].name);
482 goto client_exit_error;
483 }
484 /* TODO: algorithm implementation selection */
485 if ((req & REQ_AESCBC) != 0) {
486 br_ssl_engine_set_aes_cbc(&cc.eng,
487 &br_aes_ct_cbcenc_vtable,
488 &br_aes_ct_cbcdec_vtable);
489 br_ssl_engine_set_cbc(&cc.eng,
490 &br_sslrec_in_cbc_vtable,
491 &br_sslrec_out_cbc_vtable);
492 }
493 if ((req & REQ_AESGCM) != 0) {
494 br_ssl_engine_set_aes_ctr(&cc.eng,
495 &br_aes_ct_ctr_vtable);
496 br_ssl_engine_set_ghash(&cc.eng,
497 &br_ghash_ctmul);
498 br_ssl_engine_set_gcm(&cc.eng,
499 &br_sslrec_in_gcm_vtable,
500 &br_sslrec_out_gcm_vtable);
501 }
502 if ((req & REQ_3DESCBC) != 0) {
503 br_ssl_engine_set_des_cbc(&cc.eng,
504 &br_des_ct_cbcenc_vtable,
505 &br_des_ct_cbcdec_vtable);
506 br_ssl_engine_set_cbc(&cc.eng,
507 &br_sslrec_in_cbc_vtable,
508 &br_sslrec_out_cbc_vtable);
509 }
510 if ((req & REQ_RSAKEYX) != 0) {
511 br_ssl_client_set_rsapub(&cc, &br_rsa_i31_public);
512 }
513 if ((req & REQ_ECDHE_RSA) != 0) {
514 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
515 br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy);
516 }
517 if ((req & REQ_ECDHE_ECDSA) != 0) {
518 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
519 br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1);
520 }
521 if ((req & REQ_ECDH) != 0) {
522 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
523 }
524 }
525 br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
526
527 for (u = 0; hash_functions[u].name; u ++) {
528 const br_hash_class *hc;
529 int id;
530
531 hc = hash_functions[u].hclass;
532 id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
533 if ((hfuns & ((unsigned)1 << id)) != 0) {
534 br_ssl_engine_set_hash(&cc.eng, id, hc);
535 br_x509_minimal_set_hash(&xc, id, hc);
536 }
537 }
538 if (vmin <= BR_TLS11) {
539 br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
540 }
541 if (vmax >= BR_TLS12) {
542 if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
543 br_ssl_engine_set_prf_sha256(&cc.eng,
544 &br_tls12_sha256_prf);
545 }
546 if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
547 br_ssl_engine_set_prf_sha384(&cc.eng,
548 &br_tls12_sha384_prf);
549 }
550 }
551 br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy);
552 br_x509_minimal_set_ecdsa(&xc,
553 &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
554
555 /*
556 * If there is no provided trust anchor, then certificate validation
557 * will always fail. In that situation, we use our custom wrapper
558 * that tolerates unknown anchors.
559 */
560 if (VEC_LEN(anchors) == 0) {
561 if (verbose) {
562 fprintf(stderr,
563 "WARNING: no configured trust anchor\n");
564 }
565 x509_noanchor_init(&xwc, &xc.vtable);
566 br_ssl_engine_set_x509(&cc.eng, &xwc.vtable);
567 } else {
568 br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
569 }
570
571 br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
572 br_ssl_client_reset(&cc, sni, 0);
573
574 /*
575 * Connect to the peer.
576 */
577 fd = host_connect(host, port, verbose);
578 if (fd < 0) {
579 goto client_exit_error;
580 }
581
582 /*
583 * Run the engine until completion.
584 */
585 if (run_ssl_engine(&cc.eng, fd,
586 (verbose ? RUN_ENGINE_VERBOSE : 0)
587 | (trace ? RUN_ENGINE_TRACE : 0)) != 0)
588 {
589 goto client_exit_error;
590 } else {
591 goto client_exit;
592 }
593
594 /*
595 * Release allocated structures.
596 */
597 client_exit:
598 xfree(host);
599 xfree(suites);
600 xfree(suite_ids);
601 VEC_CLEAREXT(anchors, &free_ta_contents);
602 xfree(iobuf);
603 if (fd >= 0) {
604 close(fd);
605 }
606 return retcode;
607
608 client_exit_error:
609 retcode = -1;
610 goto client_exit;
611 }