2c2985fca37e73a7cd38faacb97115b79842db56
[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
39 #include "brssl.h"
40 #include "bearssl.h"
41
42 static int
43 host_connect(const char *host, const char *port, int verbose)
44 {
45 struct addrinfo hints, *si, *p;
46 int fd;
47 int err;
48
49 memset(&hints, 0, sizeof hints);
50 hints.ai_family = PF_UNSPEC;
51 hints.ai_socktype = SOCK_STREAM;
52 err = getaddrinfo(host, port, &hints, &si);
53 if (err != 0) {
54 fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
55 gai_strerror(err));
56 return -1;
57 }
58 fd = -1;
59 for (p = si; p != NULL; p = p->ai_next) {
60 if (verbose) {
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 if (!inet_ntop(p->ai_family, addr,
75 tmp, sizeof tmp))
76 {
77 strcpy(tmp, "<invalid>");
78 }
79 } else {
80 sprintf(tmp, "<unknown family: %d>",
81 (int)sa->sa_family);
82 }
83 fprintf(stderr, "connecting to: %s\n", tmp);
84 }
85 fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
86 if (fd < 0) {
87 if (verbose) {
88 perror("socket()");
89 }
90 continue;
91 }
92 if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
93 if (verbose) {
94 perror("connect()");
95 }
96 close(fd);
97 continue;
98 }
99 break;
100 }
101 if (p == NULL) {
102 freeaddrinfo(si);
103 fprintf(stderr, "ERROR: failed to connect\n");
104 return -1;
105 }
106 freeaddrinfo(si);
107 if (verbose) {
108 fprintf(stderr, "connected.\n");
109 }
110
111 /*
112 * We make the socket non-blocking, since we are going to use
113 * poll() to organise I/O.
114 */
115 fcntl(fd, F_SETFL, O_NONBLOCK);
116 return fd;
117 }
118
119 static void
120 usage_client(void)
121 {
122 fprintf(stderr,
123 "usage: brssl client server[:port] [ options ]\n");
124 fprintf(stderr,
125 "options:\n");
126 fprintf(stderr,
127 " -q suppress verbose messages\n");
128 fprintf(stderr,
129 " -trace activate extra debug messages (dump of all packets)\n");
130 fprintf(stderr,
131 " -sni name use this specific name for SNI\n");
132 fprintf(stderr,
133 " -nosni do not send any SNI\n");
134 fprintf(stderr,
135 " -mono use monodirectional buffering\n");
136 fprintf(stderr,
137 " -buf length set the I/O buffer length (in bytes)\n");
138 fprintf(stderr,
139 " -CA file add certificates in 'file' to trust anchors\n");
140 fprintf(stderr,
141 " -list list supported names (protocols, algorithms...)\n");
142 fprintf(stderr,
143 " -vmin name set minimum supported version (default: TLS-1.0)\n");
144 fprintf(stderr,
145 " -vmax name set maximum supported version (default: TLS-1.2)\n");
146 fprintf(stderr,
147 " -cs names set list of supported cipher suites (comma-separated)\n");
148 fprintf(stderr,
149 " -hf names add support for some hash functions (comma-separated)\n");
150 fprintf(stderr,
151 " -minhello len set minimum ClientHello length (in bytes)\n");
152 fprintf(stderr,
153 " -fallback send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n");
154 }
155
156 /* see brssl.h */
157 int
158 do_client(int argc, char *argv[])
159 {
160 int retcode;
161 int verbose;
162 int trace;
163 int i, bidi;
164 const char *server_name;
165 char *host;
166 char *port;
167 const char *sni;
168 anchor_list anchors = VEC_INIT;
169 unsigned vmin, vmax;
170 cipher_suite *suites;
171 size_t num_suites;
172 uint16_t *suite_ids;
173 unsigned hfuns;
174 size_t u;
175 br_ssl_client_context cc;
176 br_x509_minimal_context xc;
177 x509_noanchor_context xwc;
178 const br_hash_class *dnhash;
179 unsigned char *iobuf;
180 size_t iobuf_len;
181 size_t minhello_len;
182 int fallback;
183 int fd;
184
185 retcode = 0;
186 verbose = 1;
187 trace = 0;
188 server_name = NULL;
189 host = NULL;
190 port = NULL;
191 sni = NULL;
192 bidi = 1;
193 vmin = 0;
194 vmax = 0;
195 suites = NULL;
196 num_suites = 0;
197 hfuns = 0;
198 suite_ids = NULL;
199 iobuf = NULL;
200 iobuf_len = 0;
201 minhello_len = (size_t)-1;
202 fallback = 0;
203 fd = -1;
204 for (i = 0; i < argc; i ++) {
205 const char *arg;
206
207 arg = argv[i];
208 if (arg[0] != '-') {
209 if (server_name != NULL) {
210 fprintf(stderr,
211 "ERROR: duplicate server name\n");
212 usage_client();
213 goto client_exit_error;
214 }
215 server_name = arg;
216 continue;
217 }
218 if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
219 verbose = 1;
220 } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
221 verbose = 0;
222 } else if (eqstr(arg, "-trace")) {
223 trace = 1;
224 } else if (eqstr(arg, "-sni")) {
225 if (++ i >= argc) {
226 fprintf(stderr,
227 "ERROR: no argument for '-sni'\n");
228 usage_client();
229 goto client_exit_error;
230 }
231 if (sni != NULL) {
232 fprintf(stderr, "ERROR: duplicate SNI\n");
233 usage_client();
234 goto client_exit_error;
235 }
236 sni = argv[i];
237 } else if (eqstr(arg, "-nosni")) {
238 if (sni != NULL) {
239 fprintf(stderr, "ERROR: duplicate SNI\n");
240 usage_client();
241 goto client_exit_error;
242 }
243 sni = "";
244 } else if (eqstr(arg, "-mono")) {
245 bidi = 0;
246 } else if (eqstr(arg, "-buf")) {
247 if (++ i >= argc) {
248 fprintf(stderr,
249 "ERROR: no argument for '-buf'\n");
250 usage_client();
251 goto client_exit_error;
252 }
253 arg = argv[i];
254 if (iobuf_len != 0) {
255 fprintf(stderr,
256 "ERROR: duplicate I/O buffer length\n");
257 usage_client();
258 goto client_exit_error;
259 }
260 iobuf_len = parse_size(arg);
261 if (iobuf_len == (size_t)-1) {
262 usage_client();
263 goto client_exit_error;
264 }
265 } else if (eqstr(arg, "-CA")) {
266 if (++ i >= argc) {
267 fprintf(stderr,
268 "ERROR: no argument for '-CA'\n");
269 usage_client();
270 goto client_exit_error;
271 }
272 arg = argv[i];
273 if (read_trust_anchors(&anchors, arg) == 0) {
274 usage_client();
275 goto client_exit_error;
276 }
277 } else if (eqstr(arg, "-list")) {
278 list_names();
279 goto client_exit;
280 } else if (eqstr(arg, "-vmin")) {
281 if (++ i >= argc) {
282 fprintf(stderr,
283 "ERROR: no argument for '-vmin'\n");
284 usage_client();
285 goto client_exit_error;
286 }
287 arg = argv[i];
288 if (vmin != 0) {
289 fprintf(stderr,
290 "ERROR: duplicate minimum version\n");
291 usage_client();
292 goto client_exit_error;
293 }
294 vmin = parse_version(arg, strlen(arg));
295 if (vmin == 0) {
296 fprintf(stderr,
297 "ERROR: unrecognised version '%s'\n",
298 arg);
299 usage_client();
300 goto client_exit_error;
301 }
302 } else if (eqstr(arg, "-vmax")) {
303 if (++ i >= argc) {
304 fprintf(stderr,
305 "ERROR: no argument for '-vmax'\n");
306 usage_client();
307 goto client_exit_error;
308 }
309 arg = argv[i];
310 if (vmax != 0) {
311 fprintf(stderr,
312 "ERROR: duplicate maximum version\n");
313 usage_client();
314 goto client_exit_error;
315 }
316 vmax = parse_version(arg, strlen(arg));
317 if (vmax == 0) {
318 fprintf(stderr,
319 "ERROR: unrecognised version '%s'\n",
320 arg);
321 usage_client();
322 goto client_exit_error;
323 }
324 } else if (eqstr(arg, "-cs")) {
325 if (++ i >= argc) {
326 fprintf(stderr,
327 "ERROR: no argument for '-cs'\n");
328 usage_client();
329 goto client_exit_error;
330 }
331 arg = argv[i];
332 if (suites != NULL) {
333 fprintf(stderr, "ERROR: duplicate list"
334 " of cipher suites\n");
335 usage_client();
336 goto client_exit_error;
337 }
338 suites = parse_suites(arg, &num_suites);
339 if (suites == NULL) {
340 usage_client();
341 goto client_exit_error;
342 }
343 } else if (eqstr(arg, "-hf")) {
344 unsigned x;
345
346 if (++ i >= argc) {
347 fprintf(stderr,
348 "ERROR: no argument for '-hf'\n");
349 usage_client();
350 goto client_exit_error;
351 }
352 arg = argv[i];
353 x = parse_hash_functions(arg);
354 if (x == 0) {
355 usage_client();
356 goto client_exit_error;
357 }
358 hfuns |= x;
359 } else if (eqstr(arg, "-minhello")) {
360 if (++ i >= argc) {
361 fprintf(stderr,
362 "ERROR: no argument for '-minhello'\n");
363 usage_client();
364 goto client_exit_error;
365 }
366 arg = argv[i];
367 if (minhello_len != (size_t)-1) {
368 fprintf(stderr, "ERROR: duplicate minium"
369 " ClientHello length\n");
370 usage_client();
371 goto client_exit_error;
372 }
373 minhello_len = parse_size(arg);
374 /*
375 * Minimum ClientHello length must fit on 16 bits.
376 */
377 if (minhello_len == (size_t)-1
378 || (((minhello_len >> 12) >> 4) != 0))
379 {
380 usage_client();
381 goto client_exit_error;
382 }
383 } else if (eqstr(arg, "-fallback")) {
384 fallback = 1;
385 } else {
386 fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
387 usage_client();
388 goto client_exit_error;
389 }
390 }
391 if (server_name == NULL) {
392 fprintf(stderr, "ERROR: no server name/address provided\n");
393 usage_client();
394 goto client_exit_error;
395 }
396 for (u = strlen(server_name); u > 0; u --) {
397 int c = server_name[u - 1];
398 if (c == ':') {
399 break;
400 }
401 if (c < '0' || c > '9') {
402 u = 0;
403 break;
404 }
405 }
406 if (u == 0) {
407 host = xstrdup(server_name);
408 port = "443";
409 } else {
410 port = xstrdup(server_name + u);
411 host = xmalloc(u);
412 memcpy(host, server_name, u - 1);
413 host[u - 1] = 0;
414 }
415 if (sni == NULL) {
416 sni = host;
417 }
418
419 if (vmin == 0) {
420 vmin = BR_TLS10;
421 }
422 if (vmax == 0) {
423 vmax = BR_TLS12;
424 }
425 if (vmax < vmin) {
426 fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
427 " version combination\n");
428 usage_client();
429 goto client_exit_error;
430 }
431 if (suites == NULL) {
432 num_suites = 0;
433
434 for (u = 0; cipher_suites[u].name; u ++) {
435 if ((cipher_suites[u].req & REQ_TLS12) == 0
436 || vmax >= BR_TLS12)
437 {
438 num_suites ++;
439 }
440 }
441 suites = xmalloc(num_suites * sizeof *suites);
442 num_suites = 0;
443 for (u = 0; cipher_suites[u].name; u ++) {
444 if ((cipher_suites[u].req & REQ_TLS12) == 0
445 || vmax >= BR_TLS12)
446 {
447 suites[num_suites ++] = cipher_suites[u];
448 }
449 }
450 }
451 if (hfuns == 0) {
452 hfuns = (unsigned)-1;
453 }
454 if (iobuf_len == 0) {
455 if (bidi) {
456 iobuf_len = BR_SSL_BUFSIZE_BIDI;
457 } else {
458 iobuf_len = BR_SSL_BUFSIZE_MONO;
459 }
460 }
461 iobuf = xmalloc(iobuf_len);
462
463 /*
464 * Compute implementation requirements and inject implementations.
465 */
466 suite_ids = xmalloc((num_suites + 1) * sizeof *suite_ids);
467 br_ssl_client_zero(&cc);
468 br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
469 dnhash = NULL;
470 for (u = 0; hash_functions[u].name; u ++) {
471 const br_hash_class *hc;
472 int id;
473
474 hc = hash_functions[u].hclass;
475 id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
476 if ((hfuns & ((unsigned)1 << id)) != 0) {
477 dnhash = hc;
478 }
479 }
480 if (dnhash == NULL) {
481 fprintf(stderr, "ERROR: no supported hash function\n");
482 goto client_exit_error;
483 }
484 br_x509_minimal_init(&xc, dnhash,
485 &VEC_ELT(anchors, 0), VEC_LEN(anchors));
486 if (vmin <= BR_TLS11) {
487 if (!(hfuns & (1 << br_md5_ID))) {
488 fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
489 goto client_exit_error;
490 }
491 if (!(hfuns & (1 << br_sha1_ID))) {
492 fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
493 goto client_exit_error;
494 }
495 }
496 for (u = 0; u < num_suites; u ++) {
497 unsigned req;
498
499 req = suites[u].req;
500 suite_ids[u] = suites[u].suite;
501 if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
502 fprintf(stderr,
503 "ERROR: cipher suite %s requires TLS 1.2\n",
504 suites[u].name);
505 goto client_exit_error;
506 }
507 if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
508 fprintf(stderr,
509 "ERROR: cipher suite %s requires SHA-1\n",
510 suites[u].name);
511 goto client_exit_error;
512 }
513 if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
514 fprintf(stderr,
515 "ERROR: cipher suite %s requires SHA-256\n",
516 suites[u].name);
517 goto client_exit_error;
518 }
519 if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
520 fprintf(stderr,
521 "ERROR: cipher suite %s requires SHA-384\n",
522 suites[u].name);
523 goto client_exit_error;
524 }
525 /* TODO: algorithm implementation selection */
526 if ((req & REQ_AESCBC) != 0) {
527 br_ssl_engine_set_aes_cbc(&cc.eng,
528 &br_aes_ct_cbcenc_vtable,
529 &br_aes_ct_cbcdec_vtable);
530 br_ssl_engine_set_cbc(&cc.eng,
531 &br_sslrec_in_cbc_vtable,
532 &br_sslrec_out_cbc_vtable);
533 }
534 if ((req & REQ_AESGCM) != 0) {
535 br_ssl_engine_set_aes_ctr(&cc.eng,
536 &br_aes_ct_ctr_vtable);
537 br_ssl_engine_set_ghash(&cc.eng,
538 &br_ghash_ctmul);
539 br_ssl_engine_set_gcm(&cc.eng,
540 &br_sslrec_in_gcm_vtable,
541 &br_sslrec_out_gcm_vtable);
542 }
543 if ((req & REQ_3DESCBC) != 0) {
544 br_ssl_engine_set_des_cbc(&cc.eng,
545 &br_des_ct_cbcenc_vtable,
546 &br_des_ct_cbcdec_vtable);
547 br_ssl_engine_set_cbc(&cc.eng,
548 &br_sslrec_in_cbc_vtable,
549 &br_sslrec_out_cbc_vtable);
550 }
551 if ((req & REQ_RSAKEYX) != 0) {
552 br_ssl_client_set_rsapub(&cc, &br_rsa_i31_public);
553 }
554 if ((req & REQ_ECDHE_RSA) != 0) {
555 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
556 br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy);
557 }
558 if ((req & REQ_ECDHE_ECDSA) != 0) {
559 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
560 br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1);
561 }
562 if ((req & REQ_ECDH) != 0) {
563 br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
564 }
565 }
566 if (fallback) {
567 suite_ids[num_suites ++] = 0x5600;
568 }
569 br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
570
571 for (u = 0; hash_functions[u].name; u ++) {
572 const br_hash_class *hc;
573 int id;
574
575 hc = hash_functions[u].hclass;
576 id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
577 if ((hfuns & ((unsigned)1 << id)) != 0) {
578 br_ssl_engine_set_hash(&cc.eng, id, hc);
579 br_x509_minimal_set_hash(&xc, id, hc);
580 }
581 }
582 if (vmin <= BR_TLS11) {
583 br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
584 }
585 if (vmax >= BR_TLS12) {
586 if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
587 br_ssl_engine_set_prf_sha256(&cc.eng,
588 &br_tls12_sha256_prf);
589 }
590 if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
591 br_ssl_engine_set_prf_sha384(&cc.eng,
592 &br_tls12_sha384_prf);
593 }
594 }
595 br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy);
596 br_x509_minimal_set_ecdsa(&xc,
597 &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
598
599 /*
600 * If there is no provided trust anchor, then certificate validation
601 * will always fail. In that situation, we use our custom wrapper
602 * that tolerates unknown anchors.
603 */
604 if (VEC_LEN(anchors) == 0) {
605 if (verbose) {
606 fprintf(stderr,
607 "WARNING: no configured trust anchor\n");
608 }
609 x509_noanchor_init(&xwc, &xc.vtable);
610 br_ssl_engine_set_x509(&cc.eng, &xwc.vtable);
611 } else {
612 br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
613 }
614
615 if (minhello_len != (size_t)-1) {
616 br_ssl_client_set_min_clienthello_len(&cc, minhello_len);
617 }
618
619 br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
620 br_ssl_client_reset(&cc, sni, 0);
621
622 /*
623 * Connect to the peer.
624 */
625 fd = host_connect(host, port, verbose);
626 if (fd < 0) {
627 goto client_exit_error;
628 }
629
630 /*
631 * Run the engine until completion.
632 */
633 if (run_ssl_engine(&cc.eng, fd,
634 (verbose ? RUN_ENGINE_VERBOSE : 0)
635 | (trace ? RUN_ENGINE_TRACE : 0)) != 0)
636 {
637 goto client_exit_error;
638 } else {
639 goto client_exit;
640 }
641
642 /*
643 * Release allocated structures.
644 */
645 client_exit:
646 xfree(host);
647 xfree(suites);
648 xfree(suite_ids);
649 VEC_CLEAREXT(anchors, &free_ta_contents);
650 xfree(iobuf);
651 if (fd >= 0) {
652 close(fd);
653 }
654 return retcode;
655
656 client_exit_error:
657 retcode = -1;
658 goto client_exit;
659 }