Added support for TLS_FALLBACK_SCSV.
[BearSSL] / tools / client.c
index 692b60f..2c2985f 100644 (file)
@@ -57,25 +57,29 @@ host_connect(const char *host, const char *port, int verbose)
        }
        fd = -1;
        for (p = si; p != NULL; p = p->ai_next) {
-               struct sockaddr *sa;
-               void *addr;
-               char tmp[INET6_ADDRSTRLEN + 50];
-
-               sa = (struct sockaddr *)p->ai_addr;
-               if (sa->sa_family == AF_INET) {
-                       addr = &((struct sockaddr_in *)sa)->sin_addr;
-               } else if (sa->sa_family == AF_INET6) {
-                       addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
-               } else {
-                       addr = NULL;
-               }
-               if (addr != NULL) {
-                       inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
-               } else {
-                       sprintf(tmp, "<unknown family: %d>",
-                               (int)sa->sa_family);
-               }
                if (verbose) {
+                       struct sockaddr *sa;
+                       void *addr;
+                       char tmp[INET6_ADDRSTRLEN + 50];
+
+                       sa = (struct sockaddr *)p->ai_addr;
+                       if (sa->sa_family == AF_INET) {
+                               addr = &((struct sockaddr_in *)sa)->sin_addr;
+                       } else if (sa->sa_family == AF_INET6) {
+                               addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+                       } else {
+                               addr = NULL;
+                       }
+                       if (addr != NULL) {
+                               if (!inet_ntop(p->ai_family, addr,
+                                       tmp, sizeof tmp))
+                               {
+                                       strcpy(tmp, "<invalid>");
+                               }
+                       } else {
+                               sprintf(tmp, "<unknown family: %d>",
+                                       (int)sa->sa_family);
+                       }
                        fprintf(stderr, "connecting to: %s\n", tmp);
                }
                fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
@@ -120,29 +124,33 @@ usage_client(void)
        fprintf(stderr,
 "options:\n");
        fprintf(stderr,
-"   -q            suppress verbose messages\n");
+"   -q              suppress verbose messages\n");
+       fprintf(stderr,
+"   -trace          activate extra debug messages (dump of all packets)\n");
+       fprintf(stderr,
+"   -sni name       use this specific name for SNI\n");
        fprintf(stderr,
-"   -trace        activate extra debug messages (dump of all packets)\n");
+"   -nosni          do not send any SNI\n");
        fprintf(stderr,
-"   -sni name     use this specific name for SNI\n");
+"   -mono           use monodirectional buffering\n");
        fprintf(stderr,
-"   -nosni        do not send any SNI\n");
+"   -buf length     set the I/O buffer length (in bytes)\n");
        fprintf(stderr,
-"   -mono         use monodirectional buffering\n");
+"   -CA file        add certificates in 'file' to trust anchors\n");
        fprintf(stderr,
-"   -buf length   set the I/O buffer length (in bytes)\n");
+"   -list           list supported names (protocols, algorithms...)\n");
        fprintf(stderr,
-"   -CA file      add certificates in 'file' to trust anchors\n");
+"   -vmin name      set minimum supported version (default: TLS-1.0)\n");
        fprintf(stderr,
-"   -list         list supported names (protocols, algorithms...)\n");
+"   -vmax name      set maximum supported version (default: TLS-1.2)\n");
        fprintf(stderr,
-"   -vmin name    set minimum supported version (default: TLS-1.0)\n");
+"   -cs names       set list of supported cipher suites (comma-separated)\n");
        fprintf(stderr,
-"   -vmax name    set maximum supported version (default: TLS-1.2)\n");
+"   -hf names       add support for some hash functions (comma-separated)\n");
        fprintf(stderr,
-"   -cs names     set list of supported cipher suites (comma-separated)\n");
+"   -minhello len   set minimum ClientHello length (in bytes)\n");
        fprintf(stderr,
-"   -hf names     add support for some hash functions (comma-separated)\n");
+"   -fallback       send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n");
 }
 
 /* see brssl.h */
@@ -170,6 +178,8 @@ do_client(int argc, char *argv[])
        const br_hash_class *dnhash;
        unsigned char *iobuf;
        size_t iobuf_len;
+       size_t minhello_len;
+       int fallback;
        int fd;
 
        retcode = 0;
@@ -188,6 +198,8 @@ do_client(int argc, char *argv[])
        suite_ids = NULL;
        iobuf = NULL;
        iobuf_len = 0;
+       minhello_len = (size_t)-1;
+       fallback = 0;
        fd = -1;
        for (i = 0; i < argc; i ++) {
                const char *arg;
@@ -344,6 +356,32 @@ do_client(int argc, char *argv[])
                                goto client_exit_error;
                        }
                        hfuns |= x;
+               } else if (eqstr(arg, "-minhello")) {
+                       if (++ i >= argc) {
+                               fprintf(stderr,
+                                       "ERROR: no argument for '-minhello'\n");
+                               usage_client();
+                               goto client_exit_error;
+                       }
+                       arg = argv[i];
+                       if (minhello_len != (size_t)-1) {
+                               fprintf(stderr, "ERROR: duplicate minium"
+                                       " ClientHello length\n");
+                               usage_client();
+                               goto client_exit_error;
+                       }
+                       minhello_len = parse_size(arg);
+                       /*
+                        * Minimum ClientHello length must fit on 16 bits.
+                        */
+                       if (minhello_len == (size_t)-1
+                               || (((minhello_len >> 12) >> 4) != 0))
+                       {
+                               usage_client();
+                               goto client_exit_error;
+                       }
+               } else if (eqstr(arg, "-fallback")) {
+                       fallback = 1;
                } else {
                        fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
                        usage_client();
@@ -425,7 +463,7 @@ do_client(int argc, char *argv[])
        /*
         * Compute implementation requirements and inject implementations.
         */
-       suite_ids = xmalloc(num_suites * sizeof *suite_ids);
+       suite_ids = xmalloc((num_suites + 1) * sizeof *suite_ids);
        br_ssl_client_zero(&cc);
        br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
        dnhash = NULL;
@@ -525,6 +563,9 @@ do_client(int argc, char *argv[])
                        br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
                }
        }
+       if (fallback) {
+               suite_ids[num_suites ++] = 0x5600;
+       }
        br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
 
        for (u = 0; hash_functions[u].name; u ++) {
@@ -571,6 +612,10 @@ do_client(int argc, char *argv[])
                br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
        }
 
+       if (minhello_len != (size_t)-1) {
+               br_ssl_client_set_min_clienthello_len(&cc, minhello_len);
+       }
+
        br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
        br_ssl_client_reset(&cc, sni, 0);