From: Grigorii Demidov Date: Thu, 17 Jan 2019 13:01:54 +0000 (+0100) Subject: pytests/proxy: support for TLSv1.3 posthadshake reauth X-Git-Tag: v4.0.0~47^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=72b34173ee02f39c8e9749718c16e88f694b031f;p=thirdparty%2Fknot-resolver.git pytests/proxy: support for TLSv1.3 posthadshake reauth --- diff --git a/tests/pytests/proxy/tls-proxy.c b/tests/pytests/proxy/tls-proxy.c index 2e6f9ab1a..0605fe8dc 100644 --- a/tests/pytests/proxy/tls-proxy.c +++ b/tests/pytests/proxy/tls-proxy.c @@ -30,6 +30,7 @@ enum peer_state { enum handshake_state { TLS_HS_NOT_STARTED = 0, TLS_HS_EXPECTED, + TLS_HS_REAUTH_EXPECTED, TLS_HS_IN_PROGRESS, TLS_HS_DONE, TLS_HS_CLOSING, @@ -85,11 +86,15 @@ static void on_upstream_close(uv_handle_t *handle); static int gnutls_references = 0; -static const char * const priorities = +static const char * const tlsv12_priorities = "NORMAL:" /* GnuTLS defaults */ - "-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.3:" /* TLS 1.2 only */ + "-VERS-TLS1.0:-VERS-TLS1.1:+VERS-TLS1.2:-VERS-TLS1.3:" /* TLS 1.2 only */ "-VERS-SSL3.0:-ARCFOUR-128:-COMP-ALL:+COMP-NULL"; +static const char * const tlsv13_priorities = + "NORMAL:" /* GnuTLS defaults */ + "-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2:+VERS-TLS1.3:" /* TLS 1.3 only */ + "-VERS-SSL3.0:-ARCFOUR-128:-COMP-ALL:+COMP-NULL"; static struct tls_proxy_ctx *get_proxy(struct peer *peer) { @@ -133,7 +138,7 @@ static int ip_addr_str(const struct sockaddr *addr, char *buf, size_t *buflen) } int len = strlen(str); str[len] = '#'; - snprintf(&str[len + 1], 6, "%uh", ip_addr_port(addr)); + snprintf(&str[len + 1], 6, "%hu", ip_addr_port(addr)); len += 6; str[len] = 0; if (len >= *buflen) { @@ -383,7 +388,13 @@ static void accept_connection_from_client(uv_stream_t *server) client->tls = tls; const char *errpos = NULL; - err = gnutls_init(&tls->session, GNUTLS_SERVER | GNUTLS_NONBLOCK); + unsigned int gnutls_flags = GNUTLS_SERVER | GNUTLS_NONBLOCK; +#if GNUTLS_VERSION_NUMBER >= 0x030604 + if (proxy->a->tls_13) { + gnutls_flags |= GNUTLS_POST_HANDSHAKE_AUTH; + } +#endif + err = gnutls_init(&tls->session, gnutls_flags); if (err != GNUTLS_E_SUCCESS) { fprintf(stdout, "[client] gnutls_init() failed: (%d) %s\n", err, gnutls_strerror_name(err)); @@ -393,17 +404,24 @@ static void accept_connection_from_client(uv_stream_t *server) fprintf(stdout, "[client] gnutls_priority_set() failed: (%d) %s\n", err, gnutls_strerror_name(err)); } - err = gnutls_priority_set_direct(tls->session, priorities, &errpos); + + const char *direct_priorities = proxy->a->tls_13 ? tlsv13_priorities : tlsv12_priorities; + err = gnutls_priority_set_direct(tls->session, direct_priorities, &errpos); if (err != GNUTLS_E_SUCCESS) { fprintf(stdout, "[client] setting priority '%s' failed at character %zd (...'%s') with %s (%d)\n", - priorities, errpos - priorities, errpos, gnutls_strerror_name(err), err); + direct_priorities, errpos - direct_priorities, errpos, + gnutls_strerror_name(err), err); } err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, proxy->tls_credentials); if (err != GNUTLS_E_SUCCESS) { fprintf(stdout, "[client] gnutls_credentials_set() failed: (%d) %s\n", err, gnutls_strerror_name(err)); } - gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_IGNORE); + if (proxy->a->tls_13) { + gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_REQUEST); + } else { + gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_IGNORE); + } gnutls_handshake_set_timeout(tls->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); gnutls_transport_set_pull_function(tls->session, proxy_gnutls_pull); gnutls_transport_set_push_function(tls->session, proxy_gnutls_push); @@ -679,13 +697,53 @@ static int write_to_client_pending(struct peer *client) fprintf(stdout, "[client] submitted %zd bytes\n", submitted); if (proxy->a->rehandshake) { + int err = GNUTLS_E_SUCCESS; +#if GNUTLS_VERSION_NUMBER >= 0x030604 + if (proxy->a->tls_13) { + int flags = gnutls_session_get_flags(tls_session); + if ((flags & GNUTLS_SFLAGS_POST_HANDSHAKE_AUTH) == 0) { + /* Client doesn't support post-handshake re-authentication, + * nothing to test here */ + fprintf(stdout, "[client] GNUTLS_SFLAGS_POST_HANDSHAKE_AUTH flag not detected\n"); + assert(false); + } + err = gnutls_reauth(tls_session, 0); + if (err != GNUTLS_E_INTERRUPTED && + err != GNUTLS_E_AGAIN && + err != GNUTLS_E_GOT_APPLICATION_DATA) { + fprintf(stdout, "[client] gnutls_reauth() failed: %s (%i)\n", + gnutls_strerror_name(err), err); + } else { + fprintf(stdout, "[client] post-handshake authentication initiated\n"); + } + client->tls->handshake_state = TLS_HS_REAUTH_EXPECTED; + } else { + assert (gnutls_safe_renegotiation_status(tls_session) != 0); + err = gnutls_rehandshake(tls_session); + if (err != GNUTLS_E_SUCCESS) { + fprintf(stdout, "[client] gnutls_rehandshake() failed: %s (%i)\n", + gnutls_strerror_name(err), err); + assert(false); + } else { + fprintf(stdout, "[client] rehandshake started\n"); + } + client->tls->handshake_state = TLS_HS_EXPECTED; + } +#else assert (gnutls_safe_renegotiation_status(tls_session) != 0); - assert (gnutls_rehandshake(tls_session) == GNUTLS_E_SUCCESS); + err = gnutls_rehandshake(tls_session); + if (err != GNUTLS_E_SUCCESS) { + fprintf(stdout, "[client] gnutls_rehandshake() failed: %s (%i)\n", + gnutls_strerror_name(err), err); + assert(false); + } else { + fprintf(stdout, "[client] rehandshake started\n"); + } /* Prevent write-to-client callback from sending next pending chunk. * At the same time tls_process_from_client() must not call gnutls_handshake() * as there can be application data in this direction. */ client->tls->handshake_state = TLS_HS_EXPECTED; - fprintf(stdout, "[client] rehandshake started\n"); +#endif } return submitted; } @@ -746,6 +804,41 @@ int tls_process_handshake(struct peer *peer) return ret; } +#if GNUTLS_VERSION_NUMBER >= 0x030604 +int tls_process_reauth(struct peer *peer) +{ + struct tls_ctx *tls = peer->tls; + int ret = 1; + while (tls->handshake_state == TLS_HS_REAUTH_EXPECTED) { + fprintf(stdout, "[tls] TLS re-authentication in progress...\n"); + int err = gnutls_reauth(tls->session, 0); + if (err == GNUTLS_E_SUCCESS) { + tls->handshake_state = TLS_HS_DONE; + fprintf(stdout, "[tls] TLS re-authentication has completed\n"); + ret = 1; + if (peer->pending_buf.len != 0) { + write_to_client_pending(peer); + } + } else if (err != GNUTLS_E_INTERRUPTED && + err != GNUTLS_E_AGAIN && + err != GNUTLS_E_GOT_APPLICATION_DATA) { + /* these are listed as nonfatal errors there + * https://www.gnutls.org/manual/gnutls.html#gnutls_005freauth */ + fprintf(stdout, "[tls] gnutls_reauth failed: %s (%d)\n", + gnutls_strerror_name(err), err); + ret = -1; + break; + } else { + fprintf(stdout, "[tls] gnutls_reauth nonfatal error: %s (%d)\n", + gnutls_strerror_name(err), err); + ret = 0; + break; + } + } + return ret; +} +#endif + int tls_process_from_client(struct peer *client, const uint8_t *buf, ssize_t nread) { struct tls_ctx *tls = client->tls; @@ -756,7 +849,12 @@ int tls_process_from_client(struct peer *client, const uint8_t *buf, ssize_t nre fprintf(stdout, "[client] tls_process: reading %zd bytes from client\n", nread); - int ret = tls_process_handshake(client); + int ret = 0; + if (tls->handshake_state == TLS_HS_REAUTH_EXPECTED) { + ret = tls_process_reauth(client); + } else { + ret = tls_process_handshake(client); + } if (ret <= 0) { return ret; } @@ -778,9 +876,25 @@ int tls_process_from_client(struct peer *client, const uint8_t *buf, ssize_t nre break; } continue; - } else if (count < 0) { + } +#if GNUTLS_VERSION_NUMBER >= 0x030604 + else if (count == GNUTLS_E_REAUTH_REQUEST) { + assert(false); + tls->handshake_state = TLS_HS_IN_PROGRESS; + ret = tls_process_reauth(client); + if (ret < 0) { /* Critical error */ + return ret; + } + if (ret == 0) { /* Non fatal, most likely GNUTLS_E_AGAIN */ + break; + } + continue; + } +#endif + else if (count < 0) { fprintf(stdout, "[client] gnutls_record_recv failed: %s (%zd)\n", gnutls_strerror_name(count), count); + assert(false); return -1; } else if (count == 0) { break; diff --git a/tests/pytests/proxy/tls-proxy.h b/tests/pytests/proxy/tls-proxy.h index 4ec13d34f..783b19cd8 100644 --- a/tests/pytests/proxy/tls-proxy.h +++ b/tests/pytests/proxy/tls-proxy.h @@ -13,6 +13,7 @@ struct args { bool rehandshake; bool close_connection; bool accept_only; + bool tls_13; uint64_t close_timeout; uint32_t max_conn_sequence; diff --git a/tests/pytests/proxy/tlsproxy.c b/tests/pytests/proxy/tlsproxy.c index 36f213b50..1513cf657 100644 --- a/tests/pytests/proxy/tlsproxy.c +++ b/tests/pytests/proxy/tlsproxy.c @@ -30,6 +30,8 @@ void help(char *argv[], struct args *a) " sent to the client (default: no).\n" " -a, --acceptonly Accept incoming connections, but don't\n" " connect to upstream (default: no).\n" + " -v, --tls13 Force use of TLSv1.3. If not turned on,\n" + " TLSv1.2 will be used (default: no).\n" , a->local_addr, a->local_port, a->upstream, a->upstream_port, @@ -47,6 +49,7 @@ void init_args(struct args *a) a->key_file = default_key_path; a->rehandshake = false; a->accept_only = false; + a->tls_13 = false; a->close_connection = false; a->close_timeout = 1000; a->max_conn_sequence = 0; /* disabled */ @@ -67,11 +70,14 @@ int main(int argc, char **argv) {"fail", required_argument, 0, 'f'}, {"rehandshake", no_argument, 0, 'r'}, {"acceptonly", no_argument, 0, 'a'}, +#if GNUTLS_VERSION_NUMBER >= 0x030604 + {"tls13", no_argument, 0, 'v'}, +#endif {0, 0, 0, 0} }; struct args args; init_args(&args); - while ((c = getopt_long(argc, argv, "l:p:u:d:t:k:c:f:ra", opts, &li)) != -1) { + while ((c = getopt_long(argc, argv, "l:p:u:d:t:k:c:f:rav", opts, &li)) != -1) { switch (c) { case 'l': @@ -130,6 +136,11 @@ int main(int argc, char **argv) case 'a': args.accept_only = true; break; + case 'v': +#if GNUTLS_VERSION_NUMBER >= 0x030604 + args.tls_13 = true; +#endif + break; default: init_args(&args); help(argv, &args); @@ -157,16 +168,26 @@ int main(int argc, char **argv) } fprintf(stdout, "Listen on %s#%u\n" "Upstream is expected on %s#%u\n" + "Certificate file %s\n" + "Key file %s\n" "Rehandshake %s\n" "Close %s\n" "Refuse incoming connections every %ith%s\n" - "Only accept, don't forward %s\n", + "Only accept, don't forward %s\n" + "Force TLSv1.3 %s\n" + , args.local_addr, args.local_port, args.upstream, args.upstream_port, + args.cert_file, args.key_file, args.rehandshake ? "yes" : "no", args.close_connection ? "yes" : "no", args.max_conn_sequence, args.max_conn_sequence ? "" : " (disabled)", - args.accept_only ? "yes" : "no" + args.accept_only ? "yes" : "no", +#if GNUTLS_VERSION_NUMBER >= 0x030604 + args.tls_13 ? "yes" : "no" +#else + "Not supported" +#endif ); res = tls_proxy_run(proxy); tls_proxy_free(proxy);