Fixed buffer overflow, and also NULL pointer dereference, in ECDSA signature handling.
[BearSSL] / tools / server.c
index fc16692..ea247ab 100644 (file)
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <errno.h>
+#include <signal.h>
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -35,7 +36,6 @@
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <sys/poll.h>
 
 #include "brssl.h"
 #include "bearssl.h"
@@ -63,7 +63,6 @@ host_bind(const char *host, const char *port, int verbose)
                struct sockaddr_in6 sa6;
                size_t sa_len;
                void *addr;
-               char tmp[INET6_ADDRSTRLEN + 50];
                int opt;
 
                sa = (struct sockaddr *)p->ai_addr;
@@ -87,13 +86,19 @@ host_bind(const char *host, const char *port, int verbose)
                        addr = NULL;
                        sa_len = p->ai_addrlen;
                }
-               if (addr != NULL) {
-                       inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
-               } else {
-                       sprintf(tmp, "<unknown family: %d>",
-                               (int)sa->sa_family);
-               }
                if (verbose) {
+                       char tmp[INET6_ADDRSTRLEN + 50];
+
+                       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, "binding to: %s\n", tmp);
                }
                fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
@@ -162,8 +167,8 @@ accept_client(int server_fd, int verbose)
                                tmp, sizeof tmp);
                        break;
                case AF_INET6:
-                       name = inet_ntop(AF_INET,
-                               &((struct sockaddr_in *)&sa)->sin_addr,
+                       name = inet_ntop(AF_INET6,
+                               &((struct sockaddr_in6 *)&sa)->sin6_addr,
                                tmp, sizeof tmp);
                        break;
                }
@@ -329,6 +334,9 @@ sp_choose(const br_ssl_server_policy_class **pctx,
                case BR_SSLKEYX_ECDHE_RSA:
                        if (pc->sk->key_type == BR_KEYTYPE_RSA) {
                                choices->cipher_suite = st[u][0];
+                               if (cc->eng.session.version < BR_TLS12) {
+                                       hash_id = 0;
+                               }
                                choices->hash_id = hash_id;
                                goto choose_ok;
                        }
@@ -336,6 +344,9 @@ sp_choose(const br_ssl_server_policy_class **pctx,
                case BR_SSLKEYX_ECDHE_ECDSA:
                        if (pc->sk->key_type == BR_KEYTYPE_EC) {
                                choices->cipher_suite = st[u][0];
+                               if (cc->eng.session.version < BR_TLS12) {
+                                       hash_id = br_sha1_ID;
+                               }
                                choices->hash_id = hash_id;
                                goto choose_ok;
                        }
@@ -638,7 +649,11 @@ do_server(int argc, char *argv[])
                                usage_server();
                                goto server_exit_error;
                        }
-                       iobuf_len = strtoul(arg, 0, 10);
+                       iobuf_len = parse_size(arg);
+                       if (iobuf_len == (size_t)-1) {
+                               usage_server();
+                               goto server_exit_error;
+                       }
                } else if (eqstr(arg, "-cache")) {
                        if (++ i >= argc) {
                                fprintf(stderr,
@@ -653,7 +668,11 @@ do_server(int argc, char *argv[])
                                usage_server();
                                goto server_exit_error;
                        }
-                       cache_len = strtoul(arg, 0, 10);
+                       cache_len = parse_size(arg);
+                       if (cache_len == (size_t)-1) {
+                               usage_server();
+                               goto server_exit_error;
+                       }
                } else if (eqstr(arg, "-cert")) {
                        if (++ i >= argc) {
                                fprintf(stderr,
@@ -774,6 +793,8 @@ do_server(int argc, char *argv[])
                        hfuns |= x;
                } else if (eqstr(arg, "-serverpref")) {
                        flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
+               } else if (eqstr(arg, "-noreneg")) {
+                       flags |= BR_OPT_NO_RENEGOTIATION;
                } else {
                        fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
                        usage_server();
@@ -883,7 +904,7 @@ do_server(int argc, char *argv[])
        suite_ids = xmalloc(num_suites * sizeof *suite_ids);
        br_ssl_server_zero(&cc);
        br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
-       br_ssl_server_set_all_flags(&cc, flags);
+       br_ssl_engine_set_all_flags(&cc.eng, flags);
        if (vmin <= BR_TLS11) {
                if (!(hfuns & (1 << br_md5_ID))) {
                        fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
@@ -992,6 +1013,11 @@ do_server(int argc, char *argv[])
 
        br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
 
+       /*
+        * We need to ignore SIGPIPE.
+        */
+       signal(SIGPIPE, SIG_IGN);
+
        /*
         * Open the server socket.
         */
@@ -1037,9 +1063,7 @@ server_exit:
                }
                xfree(chain);
        }
-       if (sk != NULL) {
-               free_private_key(sk);
-       }
+       free_private_key(sk);
        xfree(iobuf);
        xfree(cache);
        if (fd >= 0) {