Blob Blame History Raw
diff -up openssl-1.0.1e/apps/s_server.c.ecdh-auto openssl-1.0.1e/apps/s_server.c
--- openssl-1.0.1e/apps/s_server.c.ecdh-auto	2014-09-17 15:52:01.659445244 +0200
+++ openssl-1.0.1e/apps/s_server.c	2014-09-17 16:24:44.378754502 +0200
@@ -1708,7 +1708,7 @@ bad:
 		{
 		EC_KEY *ecdh=NULL;
 
-		if (named_curve)
+		if (named_curve && strcmp(named_curve, "auto"))
 			{
 			int nid = OBJ_sn2nid(named_curve);
 
@@ -1731,6 +1731,8 @@ bad:
 			{
 			BIO_printf(bio_s_out,"Setting temp ECDH parameters\n");
 			}
+		else if (named_curve)
+			SSL_CTX_set_ecdh_auto(ctx, 1);
 		else
 			{
 			BIO_printf(bio_s_out,"Using default temp ECDH parameters\n");
diff -up openssl-1.0.1e/ssl/ssl_cert.c.ecdh-auto openssl-1.0.1e/ssl/ssl_cert.c
--- openssl-1.0.1e/ssl/ssl_cert.c.ecdh-auto	2013-02-11 16:26:04.000000000 +0100
+++ openssl-1.0.1e/ssl/ssl_cert.c	2014-09-17 16:20:24.355884360 +0200
@@ -270,6 +270,7 @@ CERT *ssl_cert_dup(CERT *cert)
 			}
 		}
 	ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
+	ret->ecdh_tmp_auto = cert->ecdh_tmp_auto;
 #endif
 
 	for (i = 0; i < SSL_PKEY_NUM; i++)
diff -up openssl-1.0.1e/ssl/ssl.h.ecdh-auto openssl-1.0.1e/ssl/ssl.h
--- openssl-1.0.1e/ssl/ssl.h.ecdh-auto	2014-09-17 16:20:24.354884336 +0200
+++ openssl-1.0.1e/ssl/ssl.h	2014-09-17 16:49:29.135273514 +0200
@@ -1563,6 +1563,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTRL_GET_EXTRA_CHAIN_CERTS		82
 #define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS	83
 
+#define SSL_CTRL_SET_ECDH_AUTO			94
 #define SSL_CTRL_GET_SERVER_TMP_KEY		109
 
 #define DTLSv1_get_timeout(ssl, arg) \
@@ -1606,6 +1607,11 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTX_clear_extra_chain_certs(ctx) \
 	SSL_CTX_ctrl(ctx,SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS,0,NULL)
 
+#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_ECDH_AUTO,onoff,NULL)
+#define SSL_set_ecdh_auto(s, onoff) \
+	SSL_ctrl(s,SSL_CTRL_SET_ECDH_AUTO,onoff,NULL)
+
 #define SSL_get_server_tmp_key(s, pk) \
 	SSL_ctrl(s,SSL_CTRL_GET_SERVER_TMP_KEY,0,pk)
 
diff -up openssl-1.0.1e/ssl/ssl_lib.c.ecdh-auto openssl-1.0.1e/ssl/ssl_lib.c
--- openssl-1.0.1e/ssl/ssl_lib.c.ecdh-auto	2014-09-17 15:52:01.616444274 +0200
+++ openssl-1.0.1e/ssl/ssl_lib.c	2014-09-17 16:20:24.356884383 +0200
@@ -2045,7 +2045,7 @@ void ssl_set_cert_masks(CERT *c, const S
 #endif
 
 #ifndef OPENSSL_NO_ECDH
-	have_ecdh_tmp=(c->ecdh_tmp != NULL || c->ecdh_tmp_cb != NULL);
+	have_ecdh_tmp=(c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
 #endif
 	cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
 	rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
diff -up openssl-1.0.1e/ssl/ssl_locl.h.ecdh-auto openssl-1.0.1e/ssl/ssl_locl.h
--- openssl-1.0.1e/ssl/ssl_locl.h.ecdh-auto	2014-09-17 15:52:01.632444635 +0200
+++ openssl-1.0.1e/ssl/ssl_locl.h	2014-09-17 17:26:29.764405189 +0200
@@ -511,6 +511,8 @@ typedef struct cert_st
 	EC_KEY *ecdh_tmp;
 	/* Callback for generating ephemeral ECDH keys */
 	EC_KEY *(*ecdh_tmp_cb)(SSL *ssl,int is_export,int keysize);
+	/* Select ECDH parameters automatically */
+	int ecdh_tmp_auto;
 #endif
 
 	CERT_PKEY pkeys[SSL_PKEY_NUM];
@@ -1091,6 +1093,7 @@ SSL_COMP *ssl3_comp_find(STACK_OF(SSL_CO
 #ifndef OPENSSL_NO_EC
 int tls1_ec_curve_id2nid(int curve_id);
 int tls1_ec_nid2curve_id(int nid);
+int tls1_shared_curve(SSL *s, int nmatch);
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
diff -up openssl-1.0.1e/ssl/s3_lib.c.ecdh-auto openssl-1.0.1e/ssl/s3_lib.c
--- openssl-1.0.1e/ssl/s3_lib.c.ecdh-auto	2014-09-17 16:20:24.352884288 +0200
+++ openssl-1.0.1e/ssl/s3_lib.c	2014-09-17 17:37:26.274226185 +0200
@@ -3350,6 +3350,12 @@ long ssl3_ctrl(SSL *s, int cmd, long lar
 #endif
 
 #endif /* !OPENSSL_NO_TLSEXT */
+
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_SET_ECDH_AUTO:
+		s->cert->ecdh_tmp_auto = larg;
+		return 1;
+#endif
 	case SSL_CTRL_GET_SERVER_TMP_KEY:
 		if (s->server || !s->session || !s->session->sess_cert)
 			return 0;
@@ -3651,6 +3657,12 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd
 		ctx->srp_ctx.strength=larg;
 		break;
 #endif
+
+#ifndef OPENSSL_NO_EC
+	case SSL_CTRL_SET_ECDH_AUTO:
+		ctx->cert->ecdh_tmp_auto = larg;
+		return 1;
+#endif
 #endif /* !OPENSSL_NO_TLSEXT */
 
 	/* A Thawte special :-) */
@@ -4003,6 +4015,14 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, S
 		if (
 			/* if we are considering an ECC cipher suite that uses an ephemeral EC key */
 			(alg_k & SSL_kEECDH)
+			&& (s->cert->ecdh_tmp_auto)
+		)
+			{
+			ok = ok && tls1_shared_curve(s, 0);
+			}
+		else 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 */
diff -up openssl-1.0.1e/ssl/s3_srvr.c.ecdh-auto openssl-1.0.1e/ssl/s3_srvr.c
--- openssl-1.0.1e/ssl/s3_srvr.c.ecdh-auto	2014-09-17 15:52:01.644444906 +0200
+++ openssl-1.0.1e/ssl/s3_srvr.c	2014-09-17 16:20:24.353884312 +0200
@@ -1693,7 +1693,14 @@ int ssl3_send_server_key_exchange(SSL *s
 			const EC_GROUP *group;
 
 			ecdhp=cert->ecdh_tmp;
-			if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+			if (s->cert->ecdh_tmp_auto)
+				{
+				/* Get NID of first shared curve */
+				int nid = tls1_shared_curve(s, 0);
+				if (nid != NID_undef)
+					ecdhp = EC_KEY_new_by_curve_name(nid);
+				}
+			else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb)
 				{
 				ecdhp=s->cert->ecdh_tmp_cb(s,
 				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
@@ -1718,7 +1725,9 @@ int ssl3_send_server_key_exchange(SSL *s
 				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
 				goto err;
 				}
-			if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
+			if (s->cert->ecdh_tmp_auto)
+				ecdh = ecdhp;
+			else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
 				{
 				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
 				goto err;
diff -up openssl-1.0.1e/ssl/t1_lib.c.ecdh-auto openssl-1.0.1e/ssl/t1_lib.c
--- openssl-1.0.1e/ssl/t1_lib.c.ecdh-auto	2014-09-17 16:20:24.358884427 +0200
+++ openssl-1.0.1e/ssl/t1_lib.c	2014-09-17 17:32:04.054951942 +0200
@@ -202,6 +202,13 @@ static int nid_list[] =
 		NID_secp521r1  /* secp521r1 (25) */	
 	};
 
+static const unsigned char eccurves_default[] =
+	{
+		0,23, /* secp256r1 (23) */ 
+		0,24, /* secp384r1 (24) */
+		0,25, /* secp521r1 (25) */	
+	};
+
 static int pref_list[] =
 	{
 		NID_secp521r1, /* secp521r1 (25) */	
@@ -277,6 +284,69 @@ int tls1_ec_nid2curve_id(int nid)
 		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 (!*pcurves)
+		{
+		*pcurves = eccurves_default;
+		*pcurveslen = sizeof(eccurves_default);
+		}
+	}
+/* Return nth shared curve. If nmatch == -1 return number of
+ * matches.
+ */
+
+int tls1_shared_curve(SSL *s, int nmatch)
+	{
+	const unsigned char *pref, *supp;
+	size_t preflen, supplen, i, j;
+	int k;
+	/* Can't do anything on client side */
+	if (s->server == 0)
+		return -1;
+	tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+				&supp, &supplen);
+	tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
+				&pref, &preflen);
+	preflen /= 2;
+	supplen /= 2;
+	k = 0;
+	for (i = 0; i < preflen; i++, pref+=2)
+		{
+		const unsigned char *tsupp = supp;
+		for (j = 0; j < supplen; j++, tsupp+=2)
+			{
+			if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
+				{
+				if (nmatch == k)
+					{
+					int id = (pref[0] << 8) | pref[1];
+					return tls1_ec_curve_id2nid(id);
+					}
+				k++;
+				}
+			}
+		}
+	if (nmatch == -1)
+		return k;
+	return 0;
+	}
+
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT