Revision of custom extension code.

Move custom extension structures from SSL_CTX to CERT structure.

This change means the form can be revised in future without binary
compatibility issues. Also since CERT is part of SSL structures
so per-SSL custom extensions could be supported in future as well as
per SSL_CTX.
Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Emilia Käsper <emilia@openssl.org>
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 0865485..903f128 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -368,7 +368,7 @@
 		if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
 			ssl2_compat = 0;
 #endif
-		if (s->ctx->custom_cli_ext_records_count != 0)
+		if (s->cert->custom_cli_ext_records_count != 0)
 			ssl2_compat = 0;
 		}
 #endif
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 376dd69..dc18255 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -425,20 +425,6 @@
 					   const unsigned char **out,
 					   unsigned short *outlen, int *al, void *arg);
 
-typedef struct {
-	unsigned short ext_type;
-	custom_cli_ext_first_cb_fn fn1; 
-	custom_cli_ext_second_cb_fn fn2; 
-	void *arg;
-} custom_cli_ext_record;
-
-typedef struct {
-	unsigned short ext_type;
-	custom_srv_ext_first_cb_fn fn1; 
-	custom_srv_ext_second_cb_fn fn2; 
-	void *arg;
-} custom_srv_ext_record;
-
 #endif
 
 #ifndef OPENSSL_NO_SSL_INTERN
@@ -1160,11 +1146,6 @@
 	size_t tlsext_ellipticcurvelist_length;
 	unsigned char *tlsext_ellipticcurvelist;
 # endif /* OPENSSL_NO_EC */
-	/* Arrays containing the callbacks for custom TLS Extensions. */
-	custom_cli_ext_record *custom_cli_ext_records;
-	size_t custom_cli_ext_records_count;
-	custom_srv_ext_record *custom_srv_ext_records;
-	size_t custom_srv_ext_records_count;
 	};
 
 #endif
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 4e75a96..4504958 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -423,6 +423,27 @@
 	ret->sec_level = cert->sec_level;
 	ret->sec_ex = cert->sec_ex;
 
+#ifndef OPENSSL_NO_TLSEXT
+	if (cert->custom_cli_ext_records_count)
+		{
+		ret->custom_cli_ext_records = BUF_memdup(cert->custom_cli_ext_records, sizeof(custom_cli_ext_record) * cert->custom_cli_ext_records_count);
+		if (ret->custom_cli_ext_records == NULL)
+			goto err;
+		ret->custom_cli_ext_records_count =
+					cert->custom_cli_ext_records_count;
+		}
+
+	if (cert->custom_srv_ext_records_count)
+		{
+		ret->custom_srv_ext_records = BUF_memdup(cert->custom_srv_ext_records, sizeof(custom_srv_ext_record) * cert->custom_srv_ext_records_count);
+		if (ret->custom_srv_ext_records == NULL)
+			goto err;
+		ret->custom_srv_ext_records_count =
+					cert->custom_srv_ext_records_count;
+		}
+
+#endif
+
 	return(ret);
 	
 #if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
@@ -441,6 +462,13 @@
 		EC_KEY_free(ret->ecdh_tmp);
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+	if (ret->custom_cli_ext_records)
+		OPENSSL_free(ret->custom_cli_ext_records);
+	if (ret->custom_srv_ext_records)
+		OPENSSL_free(ret->custom_srv_ext_records);
+#endif
+
 	ssl_cert_clear_certs(ret);
 
 	return NULL;
@@ -531,6 +559,12 @@
 		X509_STORE_free(c->chain_store);
 	if (c->ciphers_raw)
 		OPENSSL_free(c->ciphers_raw);
+#ifndef OPENSSL_NO_TLSEXT
+	if (c->custom_cli_ext_records)
+		OPENSSL_free(c->custom_cli_ext_records);
+	if (c->custom_srv_ext_records)
+		OPENSSL_free(c->custom_srv_ext_records);
+#endif
 	OPENSSL_free(c);
 	}
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 9f4040d..98f4018 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1751,7 +1751,7 @@
 	}
 # endif
 
-int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
+static int cert_set_custom_cli_ext(CERT *cert, unsigned short ext_type,
 			       custom_cli_ext_first_cb_fn fn1, 
 			       custom_cli_ext_second_cb_fn fn2, void* arg)
 	{
@@ -1759,19 +1759,19 @@
 	custom_cli_ext_record* record;
 
 	/* Check for duplicates */
-	for (i=0; i < ctx->custom_cli_ext_records_count; i++)
-		if (ext_type == ctx->custom_cli_ext_records[i].ext_type)
+	for (i=0; i < cert->custom_cli_ext_records_count; i++)
+		if (ext_type == cert->custom_cli_ext_records[i].ext_type)
 			return 0;
 
-	ctx->custom_cli_ext_records = OPENSSL_realloc(ctx->custom_cli_ext_records,
-						      (ctx->custom_cli_ext_records_count + 1) * 
+	cert->custom_cli_ext_records = OPENSSL_realloc(cert->custom_cli_ext_records,
+						      (cert->custom_cli_ext_records_count + 1) * 
 						      sizeof(custom_cli_ext_record));
-	if (!ctx->custom_cli_ext_records) {
-		ctx->custom_cli_ext_records_count = 0;
+	if (!cert->custom_cli_ext_records) {
+		cert->custom_cli_ext_records_count = 0;
 		return 0;
 	}
-	ctx->custom_cli_ext_records_count++;
-	record = &ctx->custom_cli_ext_records[ctx->custom_cli_ext_records_count - 1];
+	cert->custom_cli_ext_records_count++;
+	record = &cert->custom_cli_ext_records[cert->custom_cli_ext_records_count - 1];
 	record->ext_type = ext_type;
 	record->fn1 = fn1;
 	record->fn2 = fn2;
@@ -1779,7 +1779,7 @@
 	return 1;
 	}
 
-int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
+static int cert_set_custom_srv_ext(CERT *cert, unsigned short ext_type,
 			       custom_srv_ext_first_cb_fn fn1, 
 			       custom_srv_ext_second_cb_fn fn2, void* arg)
 	{
@@ -1787,25 +1787,39 @@
 	custom_srv_ext_record* record;
 
 	/* Check for duplicates */	
-	for (i=0; i < ctx->custom_srv_ext_records_count; i++)
-		if (ext_type == ctx->custom_srv_ext_records[i].ext_type)
+	for (i=0; i < cert->custom_srv_ext_records_count; i++)
+		if (ext_type == cert->custom_srv_ext_records[i].ext_type)
 			return 0;
 
-	ctx->custom_srv_ext_records = OPENSSL_realloc(ctx->custom_srv_ext_records,
-						      (ctx->custom_srv_ext_records_count + 1) * 
+	cert->custom_srv_ext_records = OPENSSL_realloc(cert->custom_srv_ext_records,
+						      (cert->custom_srv_ext_records_count + 1) * 
 						      sizeof(custom_srv_ext_record));
-	if (!ctx->custom_srv_ext_records) {
-		ctx->custom_srv_ext_records_count = 0;
+	if (!cert->custom_srv_ext_records) {
+		cert->custom_srv_ext_records_count = 0;
 		return 0;
 	}
-	ctx->custom_srv_ext_records_count++;
-	record = &ctx->custom_srv_ext_records[ctx->custom_srv_ext_records_count - 1];
+	cert->custom_srv_ext_records_count++;
+	record = &cert->custom_srv_ext_records[cert->custom_srv_ext_records_count - 1];
 	record->ext_type = ext_type;
 	record->fn1 = fn1;
 	record->fn2 = fn2;
 	record->arg = arg;
 	return 1;
 	}
+ 
+int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_cli_ext_first_cb_fn fn1, 
+			       custom_cli_ext_second_cb_fn fn2, void *arg)
+	{
+	return cert_set_custom_cli_ext(ctx->cert, ext_type, fn1, fn2,arg);
+	}
+
+int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
+			       custom_srv_ext_first_cb_fn fn1, 
+			       custom_srv_ext_second_cb_fn fn2, void *arg)
+	{
+	return cert_set_custom_srv_ext(ctx->cert, ext_type, fn1, fn2,arg);
+	}
 
 /* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
  * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
@@ -2078,10 +2092,6 @@
 #ifndef OPENSSL_NO_SRP
 	SSL_CTX_SRP_CTX_init(ret);
 #endif
-	ret->custom_cli_ext_records = NULL;
-	ret->custom_cli_ext_records_count = 0;
-	ret->custom_srv_ext_records = NULL;
-	ret->custom_srv_ext_records_count = 0;
 #ifndef OPENSSL_NO_BUF_FREELISTS
 	ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
 	ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
@@ -2220,10 +2230,6 @@
 #ifndef OPENSSL_NO_SRP
 	SSL_CTX_SRP_CTX_free(a);
 #endif
-#ifndef OPENSSL_NO_TLSEXT
-	OPENSSL_free(a->custom_cli_ext_records);
-	OPENSSL_free(a->custom_srv_ext_records);
-#endif
 #ifndef OPENSSL_NO_ENGINE
 	if (a->client_cert_engine)
 		ENGINE_finish(a->client_cert_engine);
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 7b28886..4a12aec 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -532,6 +532,20 @@
 #define SSL_CERT_FLAGS_CHECK_TLS_STRICT \
 	(SSL_CERT_FLAG_SUITEB_128_LOS|SSL_CERT_FLAG_TLS_STRICT)
 
+typedef struct {
+	unsigned short ext_type;
+	custom_cli_ext_first_cb_fn fn1; 
+	custom_cli_ext_second_cb_fn fn2; 
+	void *arg;
+} custom_cli_ext_record;
+
+typedef struct {
+	unsigned short ext_type;
+	custom_srv_ext_first_cb_fn fn1; 
+	custom_srv_ext_second_cb_fn fn2; 
+	void *arg;
+} custom_srv_ext_record;
+
 typedef struct cert_st
 	{
 	/* Current active set */
@@ -628,6 +642,12 @@
 	unsigned char *ciphers_raw;
 	size_t ciphers_rawlen;
 
+	/* Arrays containing the callbacks for custom TLS Extensions. */
+	custom_cli_ext_record *custom_cli_ext_records;
+	size_t custom_cli_ext_records_count;
+	custom_srv_ext_record *custom_srv_ext_records;
+	size_t custom_srv_ext_records_count;
+
 	/* Security callback */
 	int (*sec_cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid, void *other, void *ex);
 	/* Security level */
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 3616c0a..ac00a2a 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1482,17 +1482,17 @@
                 }
 
 	/* Add custom TLS Extensions to ClientHello */
-	if (s->ctx->custom_cli_ext_records_count)
+	if (s->cert->custom_cli_ext_records_count)
 		{
 		size_t i;
 		custom_cli_ext_record* record;
 
-		for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+		for (i = 0; i < s->cert->custom_cli_ext_records_count; i++)
 			{
 			const unsigned char* out = NULL;
 			unsigned short outlen = 0;
 
-			record = &s->ctx->custom_cli_ext_records[i];
+			record = &s->cert->custom_cli_ext_records[i];
 			/* NULL callback sends empty extension */ 
 			/* -1 from callback omits extension */
 			if (record->fn1)
@@ -1747,13 +1747,13 @@
 		}
 #endif
 
-	for (i = 0; i < s->ctx->custom_srv_ext_records_count; i++)
+	for (i = 0; i < s->cert->custom_srv_ext_records_count; i++)
 		{
 		const unsigned char *out = NULL;
 		unsigned short outlen = 0;
 		int cb_retval = 0;
 
-		record = &s->ctx->custom_srv_ext_records[i];
+		record = &s->cert->custom_srv_ext_records[i];
 
 		/* NULL callback or -1 omits extension */
 		if (!record->fn2)
@@ -2503,13 +2503,13 @@
 		 * so call the callback and record the extension number so that
 		 * an appropriate ServerHello may be later returned.
 		 */
-		else if (!s->hit && s->ctx->custom_srv_ext_records_count)
+		else if (!s->hit && s->cert->custom_srv_ext_records_count)
 			{
 			custom_srv_ext_record *record;
 
-			for (i=0; i < s->ctx->custom_srv_ext_records_count; i++)
+			for (i=0; i < s->cert->custom_srv_ext_records_count; i++)
 				{
-				record = &s->ctx->custom_srv_ext_records[i];
+				record = &s->cert->custom_srv_ext_records[i];
 				if (type == record->ext_type)
 					{
 					if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
@@ -2848,14 +2848,14 @@
 		/* If this extension type was not otherwise handled, but 
 		 * matches a custom_cli_ext_record, then send it to the c
 		 * callback */
-		else if (s->ctx->custom_cli_ext_records_count)
+		else if (s->cert->custom_cli_ext_records_count)
 			{
 			size_t i;
 			custom_cli_ext_record* record;
 
-			for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+			for (i = 0; i < s->cert->custom_cli_ext_records_count; i++)
 				{
-				record = &s->ctx->custom_cli_ext_records[i];
+				record = &s->cert->custom_cli_ext_records[i];
 				if (record->ext_type == type)
 					{
 					if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg))