diff options
author | Hubert Kario <hkario@redhat.com> | 2016-05-06 11:12:29 +0200 |
---|---|---|
committer | Hubert Kario <hkario@redhat.com> | 2016-05-06 11:12:29 +0200 |
commit | c4dcaf7c494108e897616b947b05c6f511cf8688 (patch) | |
tree | acb3bc5dd7f13ff4bd3512a340e2dcaa78bae4af | |
parent | c8a36989000e2f7b6ff4e5f1cd85171ea8cc6f7e (diff) | |
download | gnutls-c4dcaf7c494108e897616b947b05c6f511cf8688.tar.gz |
gnutls-serv: sending alerts on mismatched SNI namestomato42/gnutls-sni-alerts
Extend serv utility to be able to send alerts when the name advertised
by client does not match the name expected by server.
-rw-r--r-- | src/serv-args.def | 13 | ||||
-rw-r--r-- | src/serv.c | 89 |
2 files changed, 102 insertions, 0 deletions
diff --git a/src/serv-args.def b/src/serv-args.def index e0dd2bb4a5..07c3bbf388 100644 --- a/src/serv-args.def +++ b/src/serv-args.def @@ -9,6 +9,19 @@ detail = "Server program that listens to incoming TLS connections."; #include args-std.def flag = { + name = sni-hostname; + descrip = "Server's hostname for server name extension"; + arg-type = string; + doc = "Server name of type host_name that the server will recognise as its own. If the server receives client hello with different name, it will send a warning-level unrecognized_name alert."; +}; + +flag = { + name = sni-hostname-fatal; + descrip = "Send fatal alert on sni-hostname mismatch"; + doc = ""; +}; + +flag = { name = noticket; descrip = "Don't accept session tickets"; doc = ""; diff --git a/src/serv.c b/src/serv.c index b34254d38e..308612a33e 100644 --- a/src/serv.c +++ b/src/serv.c @@ -81,6 +81,8 @@ const char *dh_params_file = NULL; const char *x509_crlfile = NULL; const char *priorities = NULL; const char *status_response_ocsp = NULL; +const char *sni_hostname = NULL; +int sni_hostname_fatal = 0; gnutls_datum_t session_ticket_key; static void tcp_server(const char *name, int port); @@ -318,6 +320,83 @@ int ret; return 0; } +/* callback used to verify if the host name advertised in client hello matches + * the one configured in server + */ +int +post_client_hello(gnutls_session_t session) +{ + int ret; + /* DNS names (only type supported) may be at most 256 byte long */ + char *name; + size_t len = 256; + unsigned int type; + int i; + + name = malloc(len); + if (name == NULL) + return GNUTLS_E_MEMORY_ERROR; + + for (i=0; ; ) { + ret = gnutls_server_name_get(session, name, &len, &type, i); + if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { + char *new_name; + new_name = realloc(name, len); + if (new_name == NULL) { + ret = GNUTLS_E_MEMORY_ERROR; + goto end; + } + name = new_name; + continue; /* retry call with same index */ + } + + /* check if it is the last entry in list */ + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + break; + i++; + if (ret != GNUTLS_E_SUCCESS) + goto end; + /* unknown types need to be ignored */ + if (type != GNUTLS_NAME_DNS) + continue; + + if (strlen(sni_hostname) != len) + continue; + /* API guarantees that the name of type DNS will be null terminated */ + if (!strncmp(name, sni_hostname, len)) { + ret = GNUTLS_E_SUCCESS; + goto end; + } + }; + /* when there is no extension, we can't send the extension specific alert */ + if (i == 0) { + fprintf(stderr, "Warning: client did not include SNI extension, using default host\n"); + ret = GNUTLS_E_SUCCESS; + goto end; + } + + if (sni_hostname_fatal == 1) { + /* abort the connection, propagate error up the stack */ + ret = GNUTLS_E_UNRECOGNIZED_NAME; + goto end; + } + + fprintf(stderr, "Warning: client provided unrecognized host name\n"); + /* since we just want to send an alert, not abort the connection, we + * need to send it ourselves + */ + do { + ret = gnutls_alert_send(session, + GNUTLS_AL_WARNING, + GNUTLS_A_UNRECOGNIZED_NAME); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + /* continue handshake, fall through */ +end: + free(name); + return ret; +} + gnutls_session_t initialize_session(int dtls) { gnutls_session_t session; @@ -349,6 +428,10 @@ gnutls_session_t initialize_session(int dtls) &session_ticket_key); #endif + if (sni_hostname != NULL) + gnutls_handshake_set_post_client_hello_function(session, + &post_client_hello); + if (gnutls_priority_set_direct(session, priorities, &err) < 0) { fprintf(stderr, "Syntax error at: %s\n", err); exit(1); @@ -1642,6 +1725,12 @@ static void cmd_parser(int argc, char **argv) if (HAVE_OPT(OCSP_RESPONSE)) status_response_ocsp = OPT_ARG(OCSP_RESPONSE); + if (HAVE_OPT(SNI_HOSTNAME)) + sni_hostname = OPT_ARG(SNI_HOSTNAME); + + if (HAVE_OPT(SNI_HOSTNAME_FATAL)) + sni_hostname_fatal = 1; + } /* session resuming support */ |