Tidy up EC parameter check code: instead of accessing internal structures
add utility functions to t1_lib.c to check if EC certificates and parameters
are consistent with peer.
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index f680d35..1ff5e9d 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -152,11 +152,6 @@
 #include <openssl/objects.h>
 #include "ssl_locl.h"
 #include "kssl_lcl.h"
-#ifndef OPENSSL_NO_TLSEXT
-#ifndef OPENSSL_NO_EC
-#include "../crypto/ec/ec_lcl.h"
-#endif /* OPENSSL_NO_EC */
-#endif /* OPENSSL_NO_TLSEXT */
 #include <openssl/md5.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
@@ -3844,11 +3839,6 @@
 	SSL_CIPHER *c,*ret=NULL;
 	STACK_OF(SSL_CIPHER) *prio, *allow;
 	int i,ii,ok;
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_EC)
-	unsigned int j;
-	int ec_ok, ec_nid;
-	unsigned char ec_search1 = 0, ec_search2 = 0;
-#endif
 	CERT *cert;
 	unsigned long alg_k,alg_a,mask_k,mask_a,emask_k,emask_a;
 
@@ -3949,155 +3939,14 @@
 
 #ifndef OPENSSL_NO_TLSEXT
 #ifndef OPENSSL_NO_EC
-		if (
-			/* if we are considering an ECC cipher suite that uses our certificate */
-			(alg_a & SSL_aECDSA || alg_a & SSL_aECDH)
-			/* and we have an ECC certificate */
-			&& (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL)
-			/* and the client specified a Supported Point Formats extension */
-			&& ((s->session->tlsext_ecpointformatlist_length > 0) && (s->session->tlsext_ecpointformatlist != NULL))
-			/* and our certificate's point is compressed */
-			&& (
-				(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data != NULL)
-				&& (
-					(*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED)
-					|| (*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED + 1)
-					)
-				)
-		)
-			{
-			ec_ok = 0;
-			/* if our certificate's curve is over a field type that the client does not support
-			 * then do not allow this cipher suite to be negotiated */
-			if (
-				(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL)
-				&& (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field)
-			)
-				{
-				for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++)
-					{
-					if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime)
-						{
-						ec_ok = 1;
-						break;
-						}
-					}
-				}
-			else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field)
-				{
-				for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++)
-					{
-					if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2)
-						{
-						ec_ok = 1;
-						break;
-						}
-					}
-				}
-			ok = ok && ec_ok;
-			}
-		if (
-			/* if we are considering an ECC cipher suite that uses our certificate */
-			(alg_a & SSL_aECDSA || alg_a & SSL_aECDH)
-			/* and we have an ECC certificate */
-			&& (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL)
-			/* and the client specified an EllipticCurves extension */
-			&& ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
-		)
-			{
-			ec_ok = 0;
-			if (
-				(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL)
-				&& (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL)
-			)
-				{
-				ec_nid = EC_GROUP_get_curve_name(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group);
-				if ((ec_nid == 0)
-					&& (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL)
-				)
-					{
-					if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field)
-						{
-						ec_search1 = 0xFF;
-						ec_search2 = 0x01;
-						}
-					else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field)
-						{
-						ec_search1 = 0xFF;
-						ec_search2 = 0x02;
-						}
-					}
-				else
-					{
-					ec_search1 = 0x00;
-					ec_search2 = tls1_ec_nid2curve_id(ec_nid);
-					}
-				if ((ec_search1 != 0) || (ec_search2 != 0))
-					{
-					for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
-						{
-						if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
-							{
-							ec_ok = 1;
-							break;
-							}
-						}
-					}
-				}
-			ok = ok && ec_ok;
-			}
-		if (
-			/* if we are considering an ECC cipher suite that uses an ephemeral EC key */
-			(alg_k & SSL_kEECDH)
-			/* and we have an ephemeral EC key */
-			&& (s->cert->ecdh_tmp != NULL)
-			/* and the client specified an EllipticCurves extension */
-			&& ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
-		)
-			{
-			ec_ok = 0;
-			if (s->cert->ecdh_tmp->group != NULL)
-				{
-				ec_nid = EC_GROUP_get_curve_name(s->cert->ecdh_tmp->group);
-				if ((ec_nid == 0)
-					&& (s->cert->ecdh_tmp->group->meth != NULL)
-				)
-					{
-					if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_prime_field)
-						{
-						ec_search1 = 0xFF;
-						ec_search2 = 0x01;
-						}
-					else if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_characteristic_two_field)
-						{
-						ec_search1 = 0xFF;
-						ec_search2 = 0x02;
-						}
-					}
-				else
-					{
-					ec_search1 = 0x00;
-					ec_search2 = tls1_ec_nid2curve_id(ec_nid);
-					}
-				if ((ec_search1 != 0) || (ec_search2 != 0))
-					{
-					for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
-						{
-						if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
-							{
-							ec_ok = 1;
-							break;
-							}
-						}
-					}
-				}
-			ok = ok && ec_ok;
-			}
+		/* if we are considering an ECC cipher suite that uses our
+		 * certificate check it */
+		if (alg_a & (SSL_aECDSA|SSL_aECDH))
+			ok = ok && tls1_check_ec_server_key(s);
+		/* if we are considering an ECC cipher suite that uses
+		 * an ephemeral EC key check it */
+		if (alg_k & SSL_kEECDH)
+			ok = ok && tls1_check_ec_tmp_key(s);
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 91169da..1b64651 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1107,6 +1107,8 @@
 			int *curves, size_t ncurves);
 int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
 				const char *str);
+int tls1_check_ec_server_key(SSL *s);
+int tls1_check_ec_tmp_key(SSL *s);
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 7a8dc31..ffc78c9 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -307,6 +307,30 @@
 		return 0;
 		}
 	}
+/* Get curves list, if "sess" is set return client curves otherwise
+ * preferred list
+ */
+static void tls1_get_curvelist(SSL *s, int sess,
+					const unsigned char **pcurves,
+					size_t *pcurveslen)
+	{
+	if (sess)
+		{
+		*pcurves = s->session->tlsext_ellipticcurvelist;
+		*pcurveslen = s->session->tlsext_ellipticcurvelist_length;
+		}
+	else
+		{
+		*pcurves = s->tlsext_ellipticcurvelist;
+		*pcurveslen = s->tlsext_ellipticcurvelist_length;
+		}
+	/* If not set use default: for now static structure */
+	if (!*pcurves)
+		{
+		*pcurves = eccurves_default;
+		*pcurveslen = sizeof(eccurves_default);
+		}
+	}
 
 /* Return any common values from two lists. One list is used as a 
  * preference list where we return the most preferred match.
@@ -362,28 +386,10 @@
 	/* Can't do anything on client side */
 	if (s->server == 0)
 		return -1;
-	/* Use our preferred curve list, if not set use default */
-	if (s->tlsext_ellipticcurvelist)
-		{
-		l1 = s->tlsext_ellipticcurvelist;
-		l1len = s->tlsext_ellipticcurvelist_length;
-		}
-	else
-		{
-		l1 = eccurves_default;
-		l1len = sizeof(eccurves_default);
-		}
-	/* Use peer preferred curve list, if not set use default */
-	if(s->session->tlsext_ellipticcurvelist)
-		{
-		l2 = s->session->tlsext_ellipticcurvelist;
-		l2len =s->session->tlsext_ellipticcurvelist_length;
-		}
-	else
-		{
-		l2 = eccurves_default;
-		l2len = sizeof(eccurves_default);
-		}
+	/* Get supported curves */
+	tls1_get_curvelist(s, 0, &l1, &l1len);
+	tls1_get_curvelist(s, 1, &l2, &l2len);
+
 	id = tls1_shared_list(s, l1, l1len, l2, l2len, nmatch);
 	if (nmatch == -1)
 		return id;
@@ -466,6 +472,130 @@
 		return 0;
 	return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
 	}
+/* For an EC key set TLS id and required compression based on parameters */
+static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id,
+				EC_KEY *ec)
+	{
+	int is_prime, id;
+	const EC_GROUP *grp;
+	const EC_POINT *pt;
+	const EC_METHOD *meth;
+	if (!ec)
+		return 0;
+	/* Determine if it is a prime field */
+	grp = EC_KEY_get0_group(ec);
+        pt = EC_KEY_get0_public_key(ec);
+	if (!grp || !pt)
+		return 0;
+        meth = EC_GROUP_method_of(grp);
+	if (!meth)
+		return 0;
+        if (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field)
+		is_prime = 1;
+	else
+		is_prime = 0;
+	/* Determine curve ID */
+	id = EC_GROUP_get_curve_name(grp);
+	id = tls1_ec_nid2curve_id(id);
+	/* If we have an ID set it, otherwise set arbitrary explicit curve */
+	if (id)
+		{
+		curve_id[0] = 0;
+		curve_id[1] = (unsigned char)id;
+		}
+	else
+		{
+		curve_id[0] = 0xff;
+		if (is_prime)
+			curve_id[1] = 0x01;
+		else
+			curve_id[1] = 0x02;
+		}
+	if (comp_id)
+		{
+		if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED)
+			{
+			if (is_prime)
+				*comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
+			else
+				*comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+			}
+		else
+			*comp_id = TLSEXT_ECPOINTFORMAT_uncompressed;
+		}
+	return 1;
+	}
+/* Check an EC key is compatible with extensions */
+static int tls1_check_ec_key(SSL *s,
+			unsigned char *curve_id, unsigned char *comp_id)
+	{
+	const unsigned char *p;
+	size_t plen, i;
+	/* If point formats extension present check it, otherwise everything
+	 * is supported (see RFC4492).
+	 */
+	if (comp_id && s->session->tlsext_ecpointformatlist)
+		{
+		p = s->session->tlsext_ecpointformatlist;
+		plen = s->session->tlsext_ecpointformatlist_length;
+		for (i = 0; i < plen; i++, p++)
+			{
+			if (*comp_id == *p)
+				break;
+			}
+		if (i == plen)
+			return 0;
+		}
+	/* If curve list present check it, otherwise everything is
+	 * supported.
+	 */
+	if (s->session->tlsext_ellipticcurvelist)
+		{
+		p = s->session->tlsext_ellipticcurvelist;
+		plen = s->session->tlsext_ellipticcurvelist_length;
+		for (i = 0; i < plen; i+=2, p+=2)
+			{
+			if (p[0] == curve_id[0] && p[1] == curve_id[1])
+				return 1;
+			}
+		return 0;
+		}
+	return 1;
+	}
+/* Check EC server key is compatible with client extensions */
+int tls1_check_ec_server_key(SSL *s)
+	{
+	int rv;
+	CERT_PKEY *cpk = s->cert->pkeys + SSL_PKEY_ECC;
+	EVP_PKEY *pkey;
+	unsigned char comp_id, curve_id[2];
+	if (!cpk->x509 || !cpk->privatekey)
+		return 0;
+	pkey = X509_get_pubkey(cpk->x509);
+	if (!pkey)
+		return 0;
+	rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec);
+	EVP_PKEY_free(pkey);
+	if (!rv)
+		return 0;
+	return tls1_check_ec_key(s, curve_id, &comp_id);
+	}
+/* Check EC temporary key is compatible with client extensions */
+int tls1_check_ec_tmp_key(SSL *s)
+	{
+	unsigned char curve_id[2];
+	EC_KEY *ec = s->cert->ecdh_tmp;
+	if (!ec)
+		{
+		if (s->cert->ecdh_tmp_cb)
+			return 1;
+		else
+			return 0;
+		}
+	if (!tls1_set_ec_id(curve_id, NULL, ec))
+		return 1;
+	return tls1_check_ec_key(s, curve_id, NULL);
+	}
 
 #endif /* OPENSSL_NO_EC */
 
@@ -685,15 +815,7 @@
 
 		/* Add TLS extension EllipticCurves to the ClientHello message */
 		plist = s->tlsext_ellipticcurvelist;
-		/* If we have a custom curve list use it otherwise
-		 * use default */
-		if (plist)
-			plistlen = s->tlsext_ellipticcurvelist_length;
-		else
-			{
-			plist = eccurves_default;
-			plistlen = sizeof(eccurves_default);
-			}
+		tls1_get_curvelist(s, 0, &plist, &plistlen);
 
 		if ((lenmax = limit - ret - 6) < 0) return NULL; 
 		if (plistlen > (size_t)lenmax) return NULL;