Equal preference cipher groups.

This change implements equal-preference groups of cipher suites. This
allows, for example, a server to prefer one of AES-GCM or ChaCha20
ciphers, but to allow the client to pick which one. When coupled with
clients that will boost AES-GCM in their preferences when AES-NI is
present, this allows us to use AES-GCM when the hardware exists and
ChaCha20 otherwise.
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index dce8021..8cc710c 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3737,15 +3737,40 @@
 	return(2);
 	}
 
+struct ssl_cipher_preference_list_st* ssl_get_cipher_preferences(SSL *s)
+	{
+	if (s->cipher_list != NULL)
+		return(s->cipher_list);
+
+	if (s->version >= TLS1_1_VERSION)
+		{
+		if (s->ctx != NULL && s->ctx->cipher_list_tls11 != NULL)
+			return s->ctx->cipher_list_tls11;
+		}
+
+	if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL))
+		return(s->ctx->cipher_list);
+
+	return NULL;
+	}
+
 SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
-	     STACK_OF(SSL_CIPHER) *srvr)
+	     struct ssl_cipher_preference_list_st *server_pref)
 	{
 	SSL_CIPHER *c,*ret=NULL;
-	STACK_OF(SSL_CIPHER) *prio, *allow;
+	STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow;
 	int i,ok;
 	size_t cipher_index;
 	CERT *cert;
 	unsigned long alg_k,alg_a,mask_k,mask_a,emask_k,emask_a;
+	/* in_group_flags will either be NULL, or will point to an array of
+	 * bytes which indicate equal-preference groups in the |prio| stack.
+	 * See the comment about |in_group_flags| in the
+	 * |ssl_cipher_preference_list_st| struct. */
+	const unsigned char *in_group_flags;
+	/* group_min contains the minimal index so far found in a group, or -1
+	 * if no such value exists yet. */
+	int group_min = -1;
 
 	/* Let's see which ciphers we can support */
 	cert=s->cert;
@@ -3778,11 +3803,13 @@
 	if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s))
 		{
 		prio = srvr;
+		in_group_flags = server_pref->in_group_flags;
 		allow = clnt;
 		}
 	else
 		{
 		prio = clnt;
+		in_group_flags = NULL;
 		allow = srvr;
 		}
 
@@ -3792,10 +3819,12 @@
 		{
 		c=sk_SSL_CIPHER_value(prio,i);
 
+		ok = 1;
+
 		/* Skip TLS v1.2 only ciphersuites if not supported */
-		if ((c->algorithm_ssl & SSL_TLSV1_2) && 
+		if ((c->algorithm_ssl & SSL_TLSV1_2) &&
 			!SSL_USE_TLS1_2_CIPHERS(s))
-			continue;
+			ok = 0;
 
 		ssl_set_cert_masks(cert,c);
 		mask_k = cert->mask_k;
@@ -3813,12 +3842,12 @@
 #ifndef OPENSSL_NO_PSK
 		/* with PSK there must be server callback set */
 		if ((alg_a & SSL_aPSK) && s->psk_server_callback == NULL)
-			continue;
+			ok = 0;
 #endif /* OPENSSL_NO_PSK */
 
 		if (SSL_C_IS_EXPORT(c))
 			{
-			ok = (alg_k & emask_k) && (alg_a & emask_a);
+			ok = ok && (alg_k & emask_k) && (alg_a & emask_a);
 #ifdef CIPHER_DEBUG
 			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s (export)\n",ok,alg_k,alg_a,emask_k,emask_a,
 			       (void *)c,c->name);
@@ -3826,7 +3855,7 @@
 			}
 		else
 			{
-			ok = (alg_k & mask_k) && (alg_a & mask_a);
+			ok = ok && (alg_k & mask_k) && (alg_a & mask_a);
 #ifdef CIPHER_DEBUG
 			printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n",ok,alg_k,alg_a,mask_k,mask_a,(void *)c,
 			       c->name);
@@ -3842,17 +3871,32 @@
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
-		if (!ok) continue;
-		if (sk_SSL_CIPHER_find(allow, &cipher_index, c))
+		if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c))
 			{
-#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT)
-			if ((alg_k & SSL_kEECDH) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari)
+			if (in_group_flags != NULL && in_group_flags[i] == 1)
 				{
-				if (!ret) ret=sk_SSL_CIPHER_value(allow, cipher_index);
-				continue;
+				/* This element of |prio| is in a group. Update
+				 * the minimum index found so far and continue
+				 * looking. */
+				if (group_min == -1 || group_min > cipher_index)
+					group_min = cipher_index;
 				}
-#endif
-			ret=sk_SSL_CIPHER_value(allow, cipher_index);
+			else
+				{
+				if (group_min != -1 && group_min < cipher_index)
+					cipher_index = group_min;
+				ret=sk_SSL_CIPHER_value(allow,cipher_index);
+				break;
+				}
+			}
+
+		if (in_group_flags != NULL &&
+		    in_group_flags[i] == 0 &&
+		    group_min != -1)
+			{
+			/* We are about to leave a group, but we found a match
+			 * in it, so that's our answer. */
+			ret=sk_SSL_CIPHER_value(allow,group_min);
 			break;
 			}
 		}