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