Check duplicate extensions before processing.

ClientHello and ServerHello are not allowed to include duplicate extensions.
Add a new helper function to check this and call as appropriate. Remove ad-hoc
per-extension duplicate checks which are no unnecessary.

Add runner.go tests to verify such message correctly rejected.

Change-Id: I7babd5b642dfec941459512869e2dd6de26a831c
Reviewed-on: https://boringssl-review.googlesource.com/1100
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 3015ee9..86914dc 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -107,6 +107,7 @@
  * Hudson (tjh@cryptsoft.com). */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <assert.h>
 
 #include <openssl/bytestring.h>
@@ -210,12 +211,94 @@
 	s->version = s->method->version;
 	}
 
+static int compare_uint16_t(const void *p1, const void *p2)
+	{
+	uint16_t u1 = *((const uint16_t*)p1);
+	uint16_t u2 = *((const uint16_t*)p2);
+	if (u1 < u2)
+		{
+		return -1;
+		}
+	else if (u1 > u2)
+		{
+		return 1;
+		}
+	else
+		{
+		return 0;
+		}
+	}
+
+/* Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be more
+ * than one extension of the same type in a ClientHello or ServerHello. This
+ * function does an initial scan over the extensions block to filter those
+ * out. */
+static int tls1_check_duplicate_extensions(const CBS *cbs)
+	{
+	CBS extensions = *cbs;
+	size_t num_extensions = 0, i = 0;
+	uint16_t *extension_types = NULL;
+	int ret = 0;
+
+	/* First pass: count the extensions. */
+	while (CBS_len(&extensions) > 0)
+		{
+		uint16_t type;
+		CBS extension;
+
+		if (!CBS_get_u16(&extensions, &type) ||
+			!CBS_get_u16_length_prefixed(&extensions, &extension))
+			{
+			goto done;
+			}
+
+		num_extensions++;
+		}
+
+	extension_types = (uint16_t*)OPENSSL_malloc(sizeof(uint16_t) * num_extensions);
+	if (extension_types == NULL)
+		{
+		OPENSSL_PUT_ERROR(SSL, tls1_check_duplicate_extensions, ERR_R_MALLOC_FAILURE);
+		goto done;
+		}
+
+	/* Second pass: gather the extension types. */
+	extensions = *cbs;
+	for (i = 0; i < num_extensions; i++)
+		{
+		CBS extension;
+
+		if (!CBS_get_u16(&extensions, &extension_types[i]) ||
+			!CBS_get_u16_length_prefixed(&extensions, &extension))
+			{
+			/* This should not happen. */
+			goto done;
+			}
+		}
+	assert(CBS_len(&extensions) == 0);
+
+	/* Sort the extensions and make sure there are no duplicates. */
+	qsort(extension_types, num_extensions, sizeof(uint16_t), compare_uint16_t);
+	for (i = 1; i < num_extensions; i++)
+		{
+		if (extension_types[i-1] == extension_types[i])
+			{
+			goto done;
+			}
+		}
+
+	ret = 1;
+done:
+	if (extension_types)
+		OPENSSL_free(extension_types);
+	return ret;
+	}
+
 char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx)
 	{
 	size_t len = ctx->client_hello_len;
 	const unsigned char *p = ctx->client_hello;
-	uint16_t *extension_types;
-	unsigned num_extensions;
+	CBS extensions;
 
 	/* Skip client version. */
 	if (len < 2)
@@ -302,48 +385,15 @@
 		return 0;
 
 	/* Verify that the extensions have valid lengths and that there are
-	 * no duplicates. Each extension takes, at least, four bytes, so
-	 * we can allocate a buffer of extensions_len/4 elements and be sure
-	 * that we have enough space for all the extension types. */
-	extension_types =
-		OPENSSL_malloc(sizeof(uint16_t) * ctx->extensions_len/4);
-	if (extension_types == NULL)
+	 * no duplicates.
+	 *
+	 * TODO(fork): Port the rest of this processing to CBS.
+	 */
+	CBS_init(&extensions, ctx->extensions, ctx->extensions_len);
+	if (!tls1_check_duplicate_extensions(&extensions))
 		return 0;
-	num_extensions = 0;
 
-	while (len != 0)
-		{
-		uint16_t extension_type, extension_len;
-		unsigned i;
-
-		if (len < 4)
-			goto err;
-		n2s(p, extension_type);
-		n2s(p, extension_len);
-		len -= 4;
-
-		if (len < extension_len)
-			goto err;
-		p += extension_len; len -= extension_len;
-
-		for (i = 0; i < num_extensions; i++)
-			{
-			if (extension_types[i] == extension_type)
-				{
-				/* Duplicate extension type. */
-				goto err;
-				}
-			}
-		extension_types[num_extensions] = extension_type;
-		num_extensions++;
-		}
-
-	OPENSSL_free(extension_types);
 	return 1;
-
-err:
-	OPENSSL_free(extension_types);
-	return 0;
 	}
 
 char
@@ -1825,13 +1875,32 @@
 		s->cert->pkeys[i].valid_flags = 0;
 		}
 
+	/* TODO(fork): we probably want OCSP stapling support, but this pulls in
+	 * a lot of code. */
+#if 0
+	/* Clear OCSP state. */
+	s->tlsext_status_type = -1;
+	if (s->tlsext_ocsp_ids)
+		{
+		sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
+		s->tlsext_ocsp_ids = NULL;
+		}
+	if (s->tlsext_ocsp_exts)
+		{
+		sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free);
+		s->tlsext_ocsp_exts = NULL;
+		}
+#endif
+
 	/* There may be no extensions. */
 	if (CBS_len(cbs) == 0)
 		{
 		goto ri_check;
 		}
 
-	if (!CBS_get_u16_length_prefixed(cbs, &extensions))
+	/* Decode the extensions block and check it is valid. */
+	if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+		!tls1_check_duplicate_extensions(&extensions))
 		{
 		*out_alert = SSL_AD_DECODE_ERROR;
 		return 0;
@@ -1904,9 +1973,6 @@
 					return 0;
 					}
 
-				if (s->servername_done)
-					continue;
-
 				/* Only host_name is supported. */
 				if (name_type != TLSEXT_NAMETYPE_host_name)
 					continue;
@@ -1999,12 +2065,6 @@
 
 			if (!s->hit)
 				{
-				if (s->session->tlsext_ellipticcurvelist)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					return 0;
-					}
-
 				if (!CBS_stow(&elliptic_curve_list,
 						&s->session->tlsext_ellipticcurvelist,
 						&s->session->tlsext_ellipticcurvelist_length))
@@ -2034,13 +2094,6 @@
 			{
 			CBS supported_signature_algorithms;
 
-			/* The extension should not appear twice. */
-			if (s->cert->peer_sigalgs)
-				{
-				*out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
-				return 0;
-				}
-
 			if (!CBS_get_u16_length_prefixed(&extension, &supported_signature_algorithms) ||
 				CBS_len(&extension) != 0)
 				{
@@ -2084,15 +2137,6 @@
 			CBS responder_id_list;
 			CBS request_extensions;
 
-			/* Already seen the extension. */
-			if (s->tlsext_status_type != -1 ||
-				s->tlsext_ocsp_ids != NULL ||
-				s->tlsext_ocsp_exts != NULL)
-				{
-				*out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
-				return 0;
-				}
-
 			if (!CBS_get_u8(&extension, &status_type))
 				{
 				*out_alert = SSL_AD_DECODE_ERROR;
@@ -2355,7 +2399,9 @@
 		goto ri_check;
 		}
 
-	if (!CBS_get_u16_length_prefixed(cbs, &extensions))
+	/* Decode the extensions block and check it is valid. */
+	if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+		!tls1_check_duplicate_extensions(&extensions))
 		{
 		*out_alert = SSL_AD_DECODE_ERROR;
 		return 0;