Blame SOURCES/gnutls-3.3.29-serv-sni-hostname.patch

519d7d
diff --git a/src/serv-args.def b/src/serv-args.def
519d7d
index 44b67f1ab..027737772 100644
519d7d
--- a/src/serv-args.def
519d7d
+++ b/src/serv-args.def
519d7d
@@ -8,6 +8,19 @@ detail        = "Server program that listens to incoming TLS connections.";
519d7d
 
519d7d
 #include args-std.def
519d7d
 
519d7d
+flag = {
519d7d
+    name      = sni-hostname;
519d7d
+    descrip   = "Server's hostname for server name extension";
519d7d
+    arg-type  = string;
519d7d
+    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.";
519d7d
+};
519d7d
+
519d7d
+flag = {
519d7d
+    name      = sni-hostname-fatal;
519d7d
+    descrip   = "Send fatal alert on sni-hostname mismatch";
519d7d
+    doc      = "";
519d7d
+};
519d7d
+
519d7d
 flag = {
519d7d
     name      = noticket;
519d7d
     descrip   = "Don't accept session tickets";
519d7d
diff --git a/src/serv.c b/src/serv.c
519d7d
index a1f9adfa8..f5ff48786 100644
519d7d
--- a/src/serv.c
519d7d
+++ b/src/serv.c
519d7d
@@ -49,6 +49,8 @@
519d7d
 #include "sockets.h"
519d7d
 #include "udp-serv.h"
519d7d
 
519d7d
+#define _GNUTLS_E_UNRECOGNIZED_NAME -294
519d7d
+
519d7d
 /* konqueror cannot handle sending the page in multiple
519d7d
  * pieces.
519d7d
  */
519d7d
@@ -81,6 +83,8 @@ const char *dh_params_file = NULL;
519d7d
 const char *x509_crlfile = NULL;
519d7d
 const char *priorities = NULL;
519d7d
 const char *status_response_ocsp = NULL;
519d7d
+const char *sni_hostname = NULL;
519d7d
+int sni_hostname_fatal = 0;
519d7d
 
519d7d
 gnutls_datum_t session_ticket_key;
519d7d
 static void tcp_server(const char *name, int port);
519d7d
@@ -312,6 +316,83 @@ int ret;
519d7d
 	return 0;
519d7d
 }
519d7d
 
519d7d
+/* callback used to verify if the host name advertised in client hello matches
519d7d
+ * the one configured in server
519d7d
+ */
519d7d
+static int
519d7d
+post_client_hello(gnutls_session_t session)
519d7d
+{
519d7d
+	int ret;
519d7d
+	/* DNS names (only type supported) may be at most 256 byte long */
519d7d
+	char *name;
519d7d
+	size_t len = 256;
519d7d
+	unsigned int type;
519d7d
+	int i;
519d7d
+
519d7d
+	name = malloc(len);
519d7d
+	if (name == NULL)
519d7d
+		return GNUTLS_E_MEMORY_ERROR;
519d7d
+
519d7d
+	for (i=0; ; ) {
519d7d
+		ret = gnutls_server_name_get(session, name, &len, &type, i);
519d7d
+		if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
519d7d
+			char *new_name;
519d7d
+			new_name = realloc(name, len);
519d7d
+			if (new_name == NULL) {
519d7d
+				ret = GNUTLS_E_MEMORY_ERROR;
519d7d
+				goto end;
519d7d
+			}
519d7d
+			name = new_name;
519d7d
+			continue; /* retry call with same index */
519d7d
+		}
519d7d
+
519d7d
+		/* check if it is the last entry in list */
519d7d
+		if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
519d7d
+			break;
519d7d
+		i++;
519d7d
+		if (ret != GNUTLS_E_SUCCESS)
519d7d
+			goto end;
519d7d
+		/* unknown types need to be ignored */
519d7d
+		if (type != GNUTLS_NAME_DNS)
519d7d
+			continue;
519d7d
+
519d7d
+		if (strlen(sni_hostname) != len)
519d7d
+			continue;
519d7d
+		/* API guarantees that the name of type DNS will be null terminated */
519d7d
+		if (!strncmp(name, sni_hostname, len)) {
519d7d
+			ret = GNUTLS_E_SUCCESS;
519d7d
+			goto end;
519d7d
+		}
519d7d
+	};
519d7d
+	/* when there is no extension, we can't send the extension specific alert */
519d7d
+	if (i == 0) {
519d7d
+		fprintf(stderr, "Warning: client did not include SNI extension, using default host\n");
519d7d
+		ret = GNUTLS_E_SUCCESS;
519d7d
+		goto end;
519d7d
+	}
519d7d
+
519d7d
+	if (sni_hostname_fatal == 1) {
519d7d
+		/* abort the connection, propagate error up the stack */
519d7d
+		ret = _GNUTLS_E_UNRECOGNIZED_NAME;
519d7d
+		goto end;
519d7d
+	}
519d7d
+
519d7d
+	fprintf(stderr, "Warning: client provided unrecognized host name\n");
519d7d
+	/* since we just want to send an alert, not abort the connection, we
519d7d
+	 * need to send it ourselves
519d7d
+	 */
519d7d
+	do {
519d7d
+		ret = gnutls_alert_send(session,
519d7d
+					GNUTLS_AL_WARNING,
519d7d
+					GNUTLS_A_UNRECOGNIZED_NAME);
519d7d
+	} while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
519d7d
+
519d7d
+	/* continue handshake, fall through */
519d7d
+end:
519d7d
+	free(name);
519d7d
+	return ret;
519d7d
+}
519d7d
+
519d7d
 gnutls_session_t initialize_session(int dtls)
519d7d
 {
519d7d
 	gnutls_session_t session;
519d7d
@@ -343,6 +424,10 @@ gnutls_session_t initialize_session(int dtls)
519d7d
 						    &session_ticket_key);
519d7d
 #endif
519d7d
 
519d7d
+	if (sni_hostname != NULL)
519d7d
+		gnutls_handshake_set_post_client_hello_function(session,
519d7d
+								&post_client_hello);
519d7d
+
519d7d
 	if (gnutls_priority_set_direct(session, priorities, &err) < 0) {
519d7d
 		fprintf(stderr, "Syntax error at: %s\n", err);
519d7d
 		exit(1);
519d7d
@@ -1629,6 +1714,12 @@ static void cmd_parser(int argc, char **argv)
519d7d
 	if (HAVE_OPT(OCSP_RESPONSE))
519d7d
 		status_response_ocsp = OPT_ARG(OCSP_RESPONSE);
519d7d
 
519d7d
+	if (HAVE_OPT(SNI_HOSTNAME))
519d7d
+		sni_hostname = OPT_ARG(SNI_HOSTNAME);
519d7d
+
519d7d
+	if (HAVE_OPT(SNI_HOSTNAME_FATAL))
519d7d
+		sni_hostname_fatal = 1;
519d7d
+
519d7d
 }
519d7d
 
519d7d
 /* session resuming support */
519d7d
-- 
519d7d
2.14.3
519d7d