summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Kario <hkario@redhat.com>2016-05-06 11:12:29 +0200
committerHubert Kario <hkario@redhat.com>2016-05-06 11:12:29 +0200
commitc4dcaf7c494108e897616b947b05c6f511cf8688 (patch)
treeacb3bc5dd7f13ff4bd3512a340e2dcaa78bae4af
parentc8a36989000e2f7b6ff4e5f1cd85171ea8cc6f7e (diff)
downloadgnutls-tomato42/gnutls-sni-alerts.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.def13
-rw-r--r--src/serv.c89
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 */