X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=tools%2Fserver.c;h=7d24d6b75f8bd392128ebabf06dedc4f8f4fe82b;hp=a63198244002b0a07b0968b96b6f57e8982fae37;hb=ef318ef83a3a58b0a9e036676b84d11261ed7bb4;hpb=9dc3c9b61d0e8446ff8b8b7a873bbdc3f1c033fe diff --git a/tools/server.c b/tools/server.c index a631982..7d24d6b 100644 --- a/tools/server.c +++ b/tools/server.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -62,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; @@ -86,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, "", - (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, ""); + } + } else { + sprintf(tmp, "", + (int)sa->sa_family); + } fprintf(stderr, "binding to: %s\n", tmp); } fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); @@ -208,6 +214,10 @@ usage_server(void) fprintf(stderr, " -key fname read private key from file 'fname'\n"); fprintf(stderr, +" -CA file add trust anchors from 'file' (for client auth)\n"); + fprintf(stderr, +" -anon_ok request but do not require a client certificate\n"); + fprintf(stderr, " -list list supported names (protocols, algorithms...)\n"); fprintf(stderr, " -vmin name set minimum supported version (default: TLS-1.0)\n"); @@ -218,7 +228,15 @@ usage_server(void) fprintf(stderr, " -hf names add support for some hash functions (comma-separated)\n"); fprintf(stderr, +" -cbhash test hashing in policy callback\n"); + fprintf(stderr, " -serverpref enforce server's preferences for cipher suites\n"); + fprintf(stderr, +" -noreneg prohibit renegotiations\n"); + fprintf(stderr, +" -alpn name add protocol name to list of protocols (ALPN extension)\n"); + fprintf(stderr, +" -strictalpn fail on ALPN mismatch\n"); exit(EXIT_FAILURE); } @@ -229,22 +247,46 @@ typedef struct { size_t chain_len; int cert_signer_algo; private_key *sk; + int cbhash; } policy_context; -static int -get_cert_signer_algo(br_x509_certificate *xc) +static void +print_hashes(unsigned chashes) { - br_x509_decoder_context dc; - int err; + int i; - br_x509_decoder_init(&dc, 0, 0); - br_x509_decoder_push(&dc, xc->data, xc->data_len); - err = br_x509_decoder_last_error(&dc); - if (err != 0) { - return -err; - } else { - return br_x509_decoder_get_signer_key_type(&dc); + for (i = 2; i <= 6; i ++) { + if ((chashes >> i) & 1) { + int z; + + switch (i) { + case 3: z = 224; break; + case 4: z = 256; break; + case 5: z = 384; break; + case 6: z = 512; break; + default: + z = 1; + break; + } + fprintf(stderr, " sha%d", z); + } + } +} + +static unsigned +choose_hash(unsigned chashes) +{ + unsigned hash_id; + + for (hash_id = 6; hash_id >= 2; hash_id --) { + if (((chashes >> hash_id) & 1) != 0) { + return hash_id; + } } + /* + * Normally unreachable. + */ + return 0; } static int @@ -256,16 +298,10 @@ sp_choose(const br_ssl_server_policy_class **pctx, const br_suite_translated *st; size_t u, st_num; unsigned chashes; - int hash_id; pc = (policy_context *)pctx; st = br_ssl_server_get_client_suites(cc, &st_num); chashes = br_ssl_server_get_client_hashes(cc); - for (hash_id = 6; hash_id >= 2; hash_id --) { - if ((chashes >> hash_id) & 1) { - break; - } - } if (pc->verbose) { fprintf(stderr, "Client parameters:\n"); fprintf(stderr, " Maximum version: "); @@ -295,24 +331,17 @@ sp_choose(const br_ssl_server_policy_class **pctx, get_suite_name_ext(st[u][0], csn, sizeof csn); fprintf(stderr, " %s\n", csn); } - fprintf(stderr, " Common hash functions:"); - for (u = 2; u <= 6; u ++) { - if ((chashes >> u) & 1) { - int z; - - switch (u) { - case 3: z = 224; break; - case 4: z = 256; break; - case 5: z = 384; break; - case 6: z = 512; break; - default: - z = 1; - break; - } - fprintf(stderr, " sha%d", z); - } + fprintf(stderr, " Common sign+hash functions:\n"); + if ((chashes & 0xFF) != 0) { + fprintf(stderr, " with RSA:"); + print_hashes(chashes); + fprintf(stderr, "\n"); + } + if ((chashes >> 8) != 0) { + fprintf(stderr, " with ECDSA:"); + print_hashes(chashes >> 8); + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); } for (u = 0; u < st_num; u ++) { unsigned tt; @@ -328,14 +357,52 @@ 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]; - choices->hash_id = hash_id; + if (br_ssl_engine_get_version(&cc->eng) + < BR_TLS12) + { + if (pc->cbhash) { + choices->algo_id = 0x0001; + } else { + choices->algo_id = 0xFF00; + } + } else { + unsigned id; + + id = choose_hash(chashes); + if (pc->cbhash) { + choices->algo_id = + (id << 8) + 0x01; + } else { + choices->algo_id = 0xFF00 + id; + } + } goto choose_ok; } break; case BR_SSLKEYX_ECDHE_ECDSA: if (pc->sk->key_type == BR_KEYTYPE_EC) { choices->cipher_suite = st[u][0]; - choices->hash_id = hash_id; + if (br_ssl_engine_get_version(&cc->eng) + < BR_TLS12) + { + if (pc->cbhash) { + choices->algo_id = 0x0203; + } else { + choices->algo_id = + 0xFF00 + br_sha1_ID; + } + } else { + unsigned id; + + id = choose_hash(chashes >> 8); + if (pc->cbhash) { + choices->algo_id = + (id << 8) + 0x03; + } else { + choices->algo_id = + 0xFF00 + id; + } + } goto choose_ok; } break; @@ -393,64 +460,42 @@ sp_do_keyx(const br_ssl_server_policy_class **pctx, } } -/* - * OID for hash functions in RSA signatures. - */ -static const unsigned char HASH_OID_SHA1[] = { - 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A -}; - -static const unsigned char HASH_OID_SHA224[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 -}; - -static const unsigned char HASH_OID_SHA256[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 -}; - -static const unsigned char HASH_OID_SHA384[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 -}; - -static const unsigned char HASH_OID_SHA512[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 -}; - -static const unsigned char *HASH_OID[] = { - HASH_OID_SHA1, - HASH_OID_SHA224, - HASH_OID_SHA256, - HASH_OID_SHA384, - HASH_OID_SHA512 -}; - -static const br_hash_class * -get_hash_impl(int hash_id) -{ - size_t u; - - for (u = 0; hash_functions[u].name; u ++) { - const br_hash_class *hc; - int id; - - hc = hash_functions[u].hclass; - id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; - if (id == hash_id) { - return hc; - } - } - return NULL; -} - static size_t sp_do_sign(const br_ssl_server_policy_class **pctx, - int hash_id, size_t hv_len, unsigned char *data, size_t len) + unsigned algo_id, unsigned char *data, size_t hv_len, size_t len) { policy_context *pc; unsigned char hv[64]; pc = (policy_context *)pctx; - memcpy(hv, data, hv_len); + if (algo_id >= 0xFF00) { + algo_id &= 0xFF; + memcpy(hv, data, hv_len); + } else { + const br_hash_class *hc; + br_hash_compat_context zc; + + if (pc->verbose) { + fprintf(stderr, "Callback hashing, algo = 0x%04X," + " data_len = %lu\n", + algo_id, (unsigned long)hv_len); + } + algo_id >>= 8; + hc = get_hash_impl(algo_id); + if (hc == NULL) { + if (pc->verbose) { + fprintf(stderr, + "ERROR: unsupported hash function %u\n", + algo_id); + } + return 0; + } + hc->init(&zc.vtable); + hc->update(&zc.vtable, data, hv_len); + hc->out(&zc.vtable, hv); + hv_len = (hc->desc >> BR_HASHDESC_OUT_OFF) + & BR_HASHDESC_OUT_MASK; + } switch (pc->sk->key_type) { size_t sig_len; uint32_t x; @@ -458,15 +503,12 @@ sp_do_sign(const br_ssl_server_policy_class **pctx, const br_hash_class *hc; case BR_KEYTYPE_RSA: - if (hash_id == 0) { - hash_oid = NULL; - } else if (hash_id >= 2 && hash_id <= 6) { - hash_oid = HASH_OID[hash_id - 2]; - } else { + hash_oid = get_hash_oid(algo_id); + if (hash_oid == NULL && algo_id != 0) { if (pc->verbose) { fprintf(stderr, "ERROR: cannot RSA-sign with" - " unknown hash function: %d\n", - hash_id); + " unknown hash function: %u\n", + algo_id); } return 0; } @@ -492,12 +534,12 @@ sp_do_sign(const br_ssl_server_policy_class **pctx, return sig_len; case BR_KEYTYPE_EC: - hc = get_hash_impl(hash_id); + hc = get_hash_impl(algo_id); if (hc == NULL) { if (pc->verbose) { - fprintf(stderr, "ERROR: cannot RSA-sign with" - " unknown hash function: %d\n", - hash_id); + fprintf(stderr, "ERROR: cannot ECDSA-sign with" + " unknown hash function: %u\n", + algo_id); } return 0; } @@ -531,6 +573,12 @@ static const br_ssl_server_policy_class policy_vtable = { sp_do_sign }; +void +free_alpn(void *alpn) +{ + xfree(*(char **)alpn); +} + /* see brssl.h */ int do_server(int argc, char *argv[]) @@ -546,10 +594,15 @@ do_server(int argc, char *argv[]) size_t num_suites; uint16_t *suite_ids; unsigned hfuns; + int cbhash; br_x509_certificate *chain; size_t chain_len; int cert_signer_algo; private_key *sk; + anchor_list anchors = VEC_INIT; + VECTOR(const char *) alpn_names = VEC_INIT; + br_x509_minimal_context xc; + const br_hash_class *dnhash; size_t u; br_ssl_server_context cc; policy_context pc; @@ -570,6 +623,7 @@ do_server(int argc, char *argv[]) suites = NULL; num_suites = 0; hfuns = 0; + cbhash = 0; suite_ids = NULL; chain = NULL; chain_len = 0; @@ -637,7 +691,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, @@ -652,7 +710,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, @@ -689,6 +751,20 @@ do_server(int argc, char *argv[]) if (sk == NULL) { goto server_exit_error; } + } else if (eqstr(arg, "-CA")) { + if (++ i >= argc) { + fprintf(stderr, + "ERROR: no argument for '-CA'\n"); + usage_server(); + goto server_exit_error; + } + arg = argv[i]; + if (read_trust_anchors(&anchors, arg) == 0) { + usage_server(); + goto server_exit_error; + } + } else if (eqstr(arg, "-anon_ok")) { + flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH; } else if (eqstr(arg, "-list")) { list_names(); goto server_exit; @@ -771,8 +847,22 @@ do_server(int argc, char *argv[]) goto server_exit_error; } hfuns |= x; + } else if (eqstr(arg, "-cbhash")) { + cbhash = 1; } else if (eqstr(arg, "-serverpref")) { flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES; + } else if (eqstr(arg, "-noreneg")) { + flags |= BR_OPT_NO_RENEGOTIATION; + } else if (eqstr(arg, "-alpn")) { + if (++ i >= argc) { + fprintf(stderr, + "ERROR: no argument for '-alpn'\n"); + usage_server(); + goto server_exit_error; + } + VEC_ADD(alpn_names, xstrdup(argv[i])); + } else if (eqstr(arg, "-strictalpn")) { + flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH; } else { fprintf(stderr, "ERROR: unknown option: '%s'\n", arg); usage_server(); @@ -846,11 +936,10 @@ do_server(int argc, char *argv[]) break; } cert_signer_algo = get_cert_signer_algo(chain); - if (cert_signer_algo < 0) { - fprintf(stderr, "ERROR: server certificate cannot be" - " decoded (err=%d)\n", -cert_signer_algo); + if (cert_signer_algo == 0) { goto server_exit_error; - } else if (verbose) { + } + if (verbose) { const char *csas; switch (cert_signer_algo) { @@ -882,7 +971,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"); @@ -940,6 +1029,15 @@ do_server(int argc, char *argv[]) &br_sslrec_in_gcm_vtable, &br_sslrec_out_gcm_vtable); } + if ((req & REQ_CHAPOL) != 0) { + br_ssl_engine_set_chacha20(&cc.eng, + &br_chacha20_ct_run); + br_ssl_engine_set_poly1305(&cc.eng, + &br_poly1305_ctmul_run); + br_ssl_engine_set_chapol(&cc.eng, + &br_sslrec_in_chapol_vtable, + &br_sslrec_out_chapol_vtable); + } if ((req & REQ_3DESCBC) != 0) { br_ssl_engine_set_des_cbc(&cc.eng, &br_des_ct_cbcenc_vtable, @@ -954,6 +1052,7 @@ do_server(int argc, char *argv[]) } br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites); + dnhash = NULL; for (u = 0; hash_functions[u].name; u ++) { const br_hash_class *hc; int id; @@ -961,6 +1060,7 @@ do_server(int argc, char *argv[]) hc = hash_functions[u].hclass; id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; if ((hfuns & ((unsigned)1 << id)) != 0) { + dnhash = hc; br_ssl_engine_set_hash(&cc.eng, id, hc); } } @@ -981,16 +1081,62 @@ do_server(int argc, char *argv[]) br_ssl_session_cache_lru_init(&lru, cache, cache_len); br_ssl_server_set_cache(&cc, &lru.vtable); + if (VEC_LEN(alpn_names) != 0) { + br_ssl_engine_set_protocol_names(&cc.eng, + &VEC_ELT(alpn_names, 0), VEC_LEN(alpn_names)); + } + + /* + * Set the policy handler (that chooses the actual cipher suite, + * selects the certificate chain, and runs the private key + * operations). + */ pc.vtable = &policy_vtable; pc.verbose = verbose; pc.chain = chain; pc.chain_len = chain_len; pc.cert_signer_algo = cert_signer_algo; pc.sk = sk; + pc.cbhash = cbhash; br_ssl_server_set_policy(&cc, &pc.vtable); + /* + * If trust anchors have been configured, then set an X.509 + * validation engine and activate client certificate + * authentication. + */ + if (VEC_LEN(anchors) != 0) { + br_x509_minimal_init(&xc, dnhash, + &VEC_ELT(anchors, 0), VEC_LEN(anchors)); + for (u = 0; hash_functions[u].name; u ++) { + const br_hash_class *hc; + int id; + + hc = hash_functions[u].hclass; + id = (hc->desc >> BR_HASHDESC_ID_OFF) + & BR_HASHDESC_ID_MASK; + if ((hfuns & ((unsigned)1 << id)) != 0) { + br_x509_minimal_set_hash(&xc, id, hc); + } + } + br_ssl_engine_set_rsavrfy(&cc.eng, &br_rsa_i31_pkcs1_vrfy); + br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31); + br_ssl_engine_set_ecdsa(&cc.eng, &br_ecdsa_i31_vrfy_asn1); + br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy); + br_x509_minimal_set_ecdsa(&xc, + &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); + br_ssl_engine_set_x509(&cc.eng, &xc.vtable); + br_ssl_server_set_trust_anchor_names_alt(&cc, + &VEC_ELT(anchors, 0), VEC_LEN(anchors)); + } + br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi); + /* + * We need to ignore SIGPIPE. + */ + signal(SIGPIPE, SIG_IGN); + /* * Open the server socket. */ @@ -1030,13 +1176,10 @@ do_server(int argc, char *argv[]) server_exit: xfree(suites); xfree(suite_ids); - if (chain != NULL) { - for (u = 0; u < chain_len; u ++) { - xfree(chain[u].data); - } - xfree(chain); - } + free_certificates(chain, chain_len); free_private_key(sk); + VEC_CLEAREXT(anchors, &free_ta_contents); + VEC_CLEAREXT(alpn_names, &free_alpn); xfree(iobuf); xfree(cache); if (fd >= 0) {