Implement the Supported Point Formats Extension for ECC ciphersuites

Submitted by: Douglas Stebila
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 237dfb6..a8f2b8f 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -632,6 +632,11 @@
 #endif
 		*(p++)=0; /* Add the NULL method */
 #ifndef OPENSSL_NO_TLSEXT
+		if (ssl_prepare_clienthello_tlsext(s) <= 0)
+			{
+			SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+			goto err;
+			}
 		if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
 			{
 			SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
@@ -829,12 +834,12 @@
 		if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
 			{
 			/* 'al' set by ssl_parse_serverhello_tlsext */
-			SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLS_EXT);
+			SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
 			goto f_err; 
 			}
-		if (ssl_check_tlsext(s,0) <= 0)
+		if (ssl_check_serverhello_tlsext(s) <= 0)
 			{
-			SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLS_EXT);
+			SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLSEXT);
 				goto err;
 			}
 		}
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index aecf6d6..0537a16 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1754,6 +1754,30 @@
 			}
 		s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
  		break;
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST:
+		if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(larg)) == NULL)
+			{
+			SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE);
+			return 0;
+			}
+		{
+		int i;
+		unsigned char *sparg = (unsigned char *) parg;
+		for (i = 0; i < larg; i++, sparg++)
+			{
+			if (TLSEXT_ECPOINTFORMAT_last < *sparg)
+				{
+				SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT);
+				return(0);
+				}
+			}
+		}
+		s->tlsext_ecpointformatlist_length = larg;
+		memcpy(s->tlsext_ecpointformatlist, parg, larg);
+		s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
+ 		break;
+#endif /* OPENSSL_NO_EC */
 #endif /* !OPENSSL_NO_TLSEXT */
 	default:
 		break;
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 8859540..43ff0d8 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -941,12 +941,12 @@
 		if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
 			{
 			/* 'al' set by ssl_parse_clienthello_tlsext */
-			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLS_EXT);
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
 			goto f_err;
 			}
 		}
-		if (ssl_check_tlsext(s,1) <= 0) {
-			SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLS_EXT);
+		if (ssl_check_clienthello_tlsext(s) <= 0) {
+			SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
 			goto err;
 		}
 #endif
@@ -1126,6 +1126,11 @@
 			*(p++)=s->s3->tmp.new_compression->id;
 #endif
 #ifndef OPENSSL_NO_TLSEXT
+		if (ssl_prepare_serverhello_tlsext(s) <= 0)
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
+			return -1;
+			}
 		if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
 			{
 			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 33792ea..4d26c70 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -507,6 +507,10 @@
 	struct ssl_session_st *prev,*next;
 #ifndef OPENSSL_NO_TLSEXT
 	char *tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+	int tlsext_ecpointformatlist_length;
+	char * tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
 #endif
 	} SSL_SESSION;
 
@@ -1057,6 +1061,10 @@
 	                          1 : prepare 2, allow last ack just after in server callback.
 	                          2 : don't call servername callback, no ack in server hello
 	                       */
+#ifndef OPENSSL_NO_EC
+	int tlsext_ecpointformatlist_length;
+	char * tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
 #define session_ctx initial_ctx
 #else
@@ -1279,6 +1287,7 @@
 #define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB	53
 #define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG	54
 #define SSL_CTRL_SET_TLSEXT_HOSTNAME		55
+#define SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST	56
 #endif
 
 #define SSL_session_reused(ssl) \
@@ -1829,7 +1838,10 @@
 #define SSL_F_SSL_VERIFY_CERT_CHAIN			 207
 #define SSL_F_SSL_WRITE					 208
 #define SSL_F_TLS1_CHANGE_CIPHER_STATE			 209
+#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT		 274
 #define SSL_F_TLS1_ENC					 210
+#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT		 275
+#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT		 276
 #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
 #define SSL_F_WRITE_PENDING				 212
 
@@ -1880,7 +1892,7 @@
 #define SSL_R_CIPHER_CODE_WRONG_LENGTH			 137
 #define SSL_R_CIPHER_OR_HASH_UNAVAILABLE		 138
 #define SSL_R_CIPHER_TABLE_SRC_ERROR			 139
-#define SSL_R_CLIENTHELLO_TLS_EXT			 316
+#define SSL_R_CLIENTHELLO_TLSEXT			 226
 #define SSL_R_COMPRESSED_LENGTH_TOO_LONG		 140
 #define SSL_R_COMPRESSION_FAILURE			 141
 #define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE	 307
@@ -1965,7 +1977,7 @@
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED		 197
 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE		 297
 #define SSL_R_PACKET_LENGTH_TOO_LONG			 198
-#define SSL_R_PARSE_TLS_EXT				 317
+#define SSL_R_PARSE_TLSEXT				 227
 #define SSL_R_PATH_TOO_LONG				 270
 #define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE		 199
 #define SSL_R_PEER_ERROR				 200
@@ -1992,12 +2004,13 @@
 #define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO		 216
 #define SSL_R_REUSE_CERT_TYPE_NOT_ZERO			 217
 #define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO		 218
-#define SSL_R_SERVERHELLO_TLS_EXT			 318
+#define SSL_R_SERVERHELLO_TLSEXT			 275
 #define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED		 277
 #define SSL_R_SHORT_READ				 219
 #define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE	 220
 #define SSL_R_SSL23_DOING_SESSION_ID_REUSE		 221
 #define SSL_R_SSL2_CONNECTION_ID_TOO_LONG		 299
+#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT		 321
 #define SSL_R_SSL3_EXT_INVALID_SERVERNAME		 319
 #define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE		 320
 #define SSL_R_SSL3_SESSION_ID_TOO_LONG			 300
@@ -2039,6 +2052,7 @@
 #define SSL_R_TLSV1_UNRECOGNIZED_NAME			 1112
 #define SSL_R_TLSV1_UNSUPPORTED_EXTENSION		 1110
 #define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER	 232
+#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST		 157
 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG	 234
 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER		 235
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index a8193a5..4845499 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -106,6 +106,9 @@
 	ASN1_INTEGER verify_result;
 #ifndef OPENSSL_NO_TLSEXT
 	ASN1_OCTET_STRING tlsext_hostname;
+#ifndef OPENSSL_NO_EC
+	ASN1_OCTET_STRING tlsext_ecpointformatlist;
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
 	ASN1_OCTET_STRING psk_identity_hint;
@@ -116,7 +119,7 @@
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 	{
 #define LSIZE2 (sizeof(long)*2)
-	int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0;
+	int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0;
 	unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
 	unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
 	long l;
@@ -218,6 +221,20 @@
                 a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
                 a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
                 }                
+#ifndef OPENSSL_NO_EC
+	if (in->tlsext_ecpointformatlist)
+		{
+		a.tlsext_ecpointformatlist.length=1+in->tlsext_ecpointformatlist_length;
+		a.tlsext_ecpointformatlist.type=V_ASN1_OCTET_STRING;
+		if ((a.tlsext_ecpointformatlist.data = OPENSSL_malloc(1+in->tlsext_ecpointformatlist_length)) == NULL)
+			{
+			SSLerr(SSL_F_I2D_SSL_SESSION,ERR_R_MALLOC_FAILURE);
+			return(0);
+			}
+		*a.tlsext_ecpointformatlist.data = (unsigned char) in->tlsext_ecpointformatlist_length;
+		memcpy(a.tlsext_ecpointformatlist.data+1, in->tlsext_ecpointformatlist, in->tlsext_ecpointformatlist_length);
+		}
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
 	if (in->psk_identity_hint)
@@ -258,12 +275,16 @@
 #ifndef OPENSSL_NO_TLSEXT
 	if (in->tlsext_hostname)
         	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_EC
+	if (in->tlsext_ecpointformatlist)
+        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
 	if (in->psk_identity_hint)
-        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,6,v7);
+        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
 	if (in->psk_identity)
-        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,7,v8);
+        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
 #endif /* OPENSSL_NO_PSK */
 
 	M_ASN1_I2D_seq_total();
@@ -292,14 +313,23 @@
 #ifndef OPENSSL_NO_TLSEXT
 	if (in->tlsext_hostname)
         	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_EC
+	if (in->tlsext_ecpointformatlist)
+        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
 	if (in->psk_identity_hint)
-		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,6,v6);
+		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
 	if (in->psk_identity)
-		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,7,v7);
+		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
 #endif /* OPENSSL_NO_PSK */
 	M_ASN1_I2D_finish();
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef OPENSSL_NO_EC
+	OPENSSL_free(a.tlsext_ecpointformatlist.data);
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_NO_TLSEXT */
 	}
 
 SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
@@ -484,12 +514,38 @@
 	else
 		ret->tlsext_hostname=NULL;
 
+#ifndef OPENSSL_NO_EC
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+	if (os.data)
+		{
+		if ((ret->tlsext_ecpointformatlist = OPENSSL_malloc(os.length - 1)) == NULL)
+			{
+			SSLerr(SSL_F_D2I_SSL_SESSION,ERR_R_MALLOC_FAILURE);
+			}
+		else
+			{
+			ret->tlsext_ecpointformatlist_length = os.length - 1;
+			memcpy(ret->tlsext_ecpointformatlist, (unsigned char *) os.data + 1, os.length - 1);
+			}
+		OPENSSL_free(os.data);
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		{
+		ret->tlsext_ecpointformatlist=NULL;
+		ret->tlsext_ecpointformatlist_length=0;
+		}
+
+#endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
 #ifndef OPENSSL_NO_PSK
 	os.length=0;
 	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
 	if (os.data)
 		{
 		ret->psk_identity_hint = BUF_strndup(os.data, os.length);
@@ -502,7 +558,7 @@
 
 	os.length=0;
 	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,9);
 	if (os.data)
 		{
 		ret->psk_identity = BUF_strndup(os.data, os.length);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 67a1d4f..ebf1dd0 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -241,7 +241,10 @@
 {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN),	"SSL_VERIFY_CERT_CHAIN"},
 {ERR_FUNC(SSL_F_SSL_WRITE),	"SSL_write"},
 {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE),	"TLS1_CHANGE_CIPHER_STATE"},
+{ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT),	"TLS1_CHECK_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT),	"TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT),	"TLS1_PREPARE_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
 {0,NULL}
@@ -295,7 +298,7 @@
 {ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH),"cipher code wrong length"},
 {ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE),"cipher or hash unavailable"},
 {ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR),"cipher table src error"},
-{ERR_REASON(SSL_R_CLIENTHELLO_TLS_EXT)   ,"clienthello tls ext"},
+{ERR_REASON(SSL_R_CLIENTHELLO_TLSEXT)    ,"clienthello tlsext"},
 {ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG),"compressed length too long"},
 {ERR_REASON(SSL_R_COMPRESSION_FAILURE)   ,"compression failure"},
 {ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),"compression id not within private range"},
@@ -380,7 +383,7 @@
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
-{ERR_REASON(SSL_R_PARSE_TLS_EXT)         ,"parse tls ext"},
+{ERR_REASON(SSL_R_PARSE_TLSEXT)          ,"parse tlsext"},
 {ERR_REASON(SSL_R_PATH_TOO_LONG)         ,"path too long"},
 {ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"},
 {ERR_REASON(SSL_R_PEER_ERROR)            ,"peer error"},
@@ -407,12 +410,13 @@
 {ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
 {ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
 {ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
-{ERR_REASON(SSL_R_SERVERHELLO_TLS_EXT)   ,"serverhello tls ext"},
+{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT)    ,"serverhello tlsext"},
 {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
 {ERR_REASON(SSL_R_SHORT_READ)            ,"short read"},
 {ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"},
 {ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE),"ssl23 doing session id reuse"},
 {ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG),"ssl2 connection id too long"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT),"ssl3 ext invalid ecpointformat"},
 {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME),"ssl3 ext invalid servername"},
 {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),"ssl3 ext invalid servername type"},
 {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG),"ssl3 session id too long"},
@@ -454,6 +458,7 @@
 {ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME),"tlsv1 unrecognized name"},
 {ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION),"tlsv1 unsupported extension"},
 {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
+{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
 {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
 {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
 {ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 2beffcb..f0527f4 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -975,6 +975,9 @@
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
-int ssl_check_tlsext(SSL *s, int is_server);
+int ssl_prepare_clienthello_tlsext(SSL *s);
+int ssl_prepare_serverhello_tlsext(SSL *s);
+int ssl_check_clienthello_tlsext(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
 #endif
 #endif
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index a4a3a4b..9372a4e 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -203,6 +203,10 @@
 	ss->compress_meth=0;
 #ifndef OPENSSL_NO_TLSEXT
 	ss->tlsext_hostname = NULL; 
+#ifndef OPENSSL_NO_EC
+	ss->tlsext_ecpointformatlist_length = 0;
+	ss->tlsext_ecpointformatlist = NULL;
+#endif
 #endif
 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
 #ifndef OPENSSL_NO_PSK
@@ -352,6 +356,19 @@
 				return 0;
 				}
 			}
+#ifndef OPENSSL_NO_EC
+		if (s->tlsext_ecpointformatlist)
+			{
+			if ((ss->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
+				{
+				SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE);
+				SSL_SESSION_free(ss);
+				return 0;
+				}
+			ss->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
+			memcpy(ss->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+			}
+#endif
 #endif
 		}
 	else
@@ -644,6 +661,10 @@
 	if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
 #ifndef OPENSSL_NO_TLSEXT
 	if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
+#ifndef OPENSSL_NO_EC
+	ss->tlsext_ecpointformatlist_length = 0;
+	if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
+#endif /* OPENSSL_NO_EC */
 #endif
 #ifndef OPENSSL_NO_PSK
 	if (ss->psk_identity_hint != NULL)
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index d591daa..7f42cee 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -181,6 +181,22 @@
 		memcpy(ret, s->tlsext_hostname, size_str);
 		ret+=size_str;
 		}
+#ifndef OPENSSL_NO_EC
+	if (s->tlsext_ecpointformatlist != NULL)
+		{
+		/* Add TLS extension ECPointFormats to the ClientHello message */
+		long lenmax; 
+
+		if ((lenmax = limit - p - 5) < 0) return NULL; 
+		if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+		
+		s2n(TLSEXT_TYPE_ec_point_formats,ret);
+		s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+		*(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+		memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+		ret+=s->tlsext_ecpointformatlist_length;
+		}
+#endif /* OPENSSL_NO_EC */
 
 	if ((extdatalen = ret-p-2)== 0) 
 		return p;
@@ -204,6 +220,22 @@
 		s2n(TLSEXT_TYPE_server_name,ret);
 		s2n(0,ret);
 		}
+#ifndef OPENSSL_NO_EC
+	if (s->tlsext_ecpointformatlist != NULL)
+		{
+		/* Add TLS extension ECPointFormats to the ServerHello message */
+		long lenmax; 
+
+		if ((lenmax = limit - p - 5) < 0) return NULL; 
+		if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
+		
+		s2n(TLSEXT_TYPE_ec_point_formats,ret);
+		s2n(s->tlsext_ecpointformatlist_length + 1,ret);
+		*(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
+		memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+		ret+=s->tlsext_ecpointformatlist_length;
+		}
+#endif /* OPENSSL_NO_EC */
 	
 	if ((extdatalen = ret-p-2)== 0) 
 		return p;
@@ -314,8 +346,37 @@
 				}
 			}
 
+#ifndef OPENSSL_NO_EC
+		else if (type == TLSEXT_TYPE_ec_point_formats)
+			{
+			unsigned char *sdata = data;
+			int ecpointformatlist_length = *(sdata++);
+			int i;
+
+			if (ecpointformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = 0;
+			if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+			memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+			fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
+			sdata = s->session->tlsext_ecpointformatlist;
+			for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+				fprintf(stderr,"%i ",*(sdata++));
+			fprintf(stderr,"\n");
+#endif
+			}
 		data+=size;		
 		}
+#endif /* OPENSSL_NO_EC */
 
 	*p = data;
 	return 1;
@@ -329,6 +390,9 @@
 	unsigned char *data = *p;
 
 	int tlsext_servername = 0;
+#ifndef OPENSSL_NO_EC
+	int tlsext_ecpointformats = 0;
+#endif /* OPENSSL_NO_EC */
 
 	if (data >= (d+n-2))
 		return 1;
@@ -353,8 +417,38 @@
 			tlsext_servername = 1;   
 			}
 
+#ifndef OPENSSL_NO_EC
+		else if (type == TLSEXT_TYPE_ec_point_formats)
+			{
+			unsigned char *sdata = data;
+			int ecpointformatlist_length = *(sdata++);
+			int i;
+
+			if (ecpointformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = 0;
+			if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+				{
+				*al = TLS1_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+			memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
+#if 0
+			fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+			sdata = s->session->tlsext_ecpointformatlist;
+			for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+				fprintf(stderr,"%i ",*(sdata++));
+			fprintf(stderr,"\n");
+#endif
+			}
+
 		data+=size;		
 		}
+#endif /* OPENSSL_NO_EC */
 
 	if (data != d+n)
 		{
@@ -383,16 +477,168 @@
 			}
 		}
 
+#ifndef OPENSSL_NO_EC
+	if (!s->hit && tlsext_ecpointformats == 1)
+		{
+ 		if (s->tlsext_ecpointformatlist)
+			{
+			if (s->session->tlsext_ecpointformatlist == NULL)
+				{
+				s->session->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
+				if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
+					{
+					*al = TLS1_AD_INTERNAL_ERROR;
+					return 0;
+					}
+				memcpy(s->session->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
+				}
+			else 
+				{
+				*al = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+			}
+		}
+#endif /* OPENSSL_NO_EC */
+
 	*p = data;
 	return 1;
 }
 
-int ssl_check_tlsext(SSL *s, int is_server)
+int ssl_prepare_clienthello_tlsext(SSL *s)
+	{
+#ifndef OPENSSL_NO_EC
+	/* If we are client and using an elliptic curve cryptography cipher suite, send the point formats we 
+	 * support (namely, only uncompressed points).
+	 */
+	int using_ecc = 0;
+	int i;
+	int algs;
+	STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+	for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+		{
+		algs = (sk_SSL_CIPHER_value(cipher_stack, i))->algorithms;
+		if ((algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA)) 
+			{
+			using_ecc = 1;
+			break;
+			}
+
+		}
+	using_ecc = using_ecc && (s->version == TLS1_VERSION);
+	if (using_ecc)
+		{
+		if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(1)) == NULL)
+			{
+			SSLerr(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+			return -1;
+			}
+		s->tlsext_ecpointformatlist_length = 1;
+		*s->tlsext_ecpointformatlist = TLSEXT_ECPOINTFORMAT_uncompressed;
+		}
+#endif /* OPENSSL_NO_EC */
+	return 1;
+}
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+	{
+#ifndef OPENSSL_NO_EC
+	/* If we are server and using an ECC cipher suite, send the point formats we support (namely, only
+	 * uncompressed points) if the client sent us an ECPointsFormat extension.
+	 */
+	int i;
+	int algs = s->s3->tmp.new_cipher->algorithms;
+	int using_ecc = (algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA);
+	using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+
+	if (using_ecc)
+		{
+		if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(1)) == NULL)
+			{
+			SSLerr(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+			return -1;
+			}
+		s->tlsext_ecpointformatlist_length = 1;
+		*s->tlsext_ecpointformatlist = TLSEXT_ECPOINTFORMAT_uncompressed;
+		}
+#endif /* OPENSSL_NO_EC */
+	return 1;
+}
+
+int ssl_check_clienthello_tlsext(SSL *s)
 	{
 	int ret=SSL_TLSEXT_ERR_NOACK;
-
 	int al = SSL_AD_UNRECOGNIZED_NAME;
 
+#ifndef OPENSSL_NO_EC
+	/* If we are server and using an elliptic curve cyrptography cipher suite, then we don't
+	 * need to check EC point formats since all clients must support uncompressed and it's the
+	 * only thing we support; we just need to copy the data in.  We probably ought to check it
+	 * for validity, but we never use it.
+	 */
+#endif
+
+	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+	else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) 		
+		ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+	switch (ret) {
+		case SSL_TLSEXT_ERR_ALERT_FATAL:
+			ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+			return -1;
+
+		case SSL_TLSEXT_ERR_ALERT_WARNING:
+			ssl3_send_alert(s,SSL3_AL_WARNING,al);
+			return 1; 
+					
+		case SSL_TLSEXT_ERR_NOACK:
+			s->servername_done=0;
+			default:
+		return 1;
+	}
+}
+
+int ssl_check_serverhello_tlsext(SSL *s)
+	{
+	int ret=SSL_TLSEXT_ERR_NOACK;
+	int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+	/* If we are client and using an elliptic curve cryptography cipher suite, then server
+	 * must return a an EC point formats lists containing uncompressed.
+	 */
+	int algs = s->s3->tmp.new_cipher->algorithms;
+	if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && 
+	    ((algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA))) 
+		{
+		/* we are using an ECC cipher */
+		int i;
+		unsigned char *list;
+		int found_uncompressed = 0;
+		if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length <= 0))
+			{
+			SSLerr(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+			return -1;
+			}
+		list = s->session->tlsext_ecpointformatlist;
+		for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+			{
+			if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+				{
+				found_uncompressed = 1;
+				break;
+				}
+			}
+		if (!found_uncompressed)
+			{
+			SSLerr(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+			return -1;
+			}
+		}
+	ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
 	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
 		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
 	else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) 		
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 4a33278..d839e9b 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -190,10 +190,18 @@
 #define TLSEXT_TYPE_trusted_ca_keys		3
 #define TLSEXT_TYPE_truncated_hmac		4
 #define TLSEXT_TYPE_status_request		5
+#define TLSEXT_TYPE_elliptic_curves		10
+#define TLSEXT_TYPE_ec_point_formats		11
 
 /* NameType value from RFC 3546 */
 #define TLSEXT_NAMETYPE_host_name 0
 
+/* ECPointFormat values from draft-ietf-tls-ecc-12 */
+#define TLSEXT_ECPOINTFORMAT_first			0
+#define TLSEXT_ECPOINTFORMAT_uncompressed		0
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime	1
+#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2	2
+#define TLSEXT_ECPOINTFORMAT_last			2
 
 #ifndef OPENSSL_NO_TLSEXT
 
@@ -216,6 +224,10 @@
 #define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
 SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
 
+#ifndef OPENSSL_NO_EC
+#define SSL_set_tlsext_ecpointformat(s,length,list) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_ECPOINTFORMATLIST,length,(unsigned char *)list)
+#endif /* OPENSSL_NO_EC */
 #endif
 
 /* PSK ciphersuites from 4279 */