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