Add support for automatic ECDH temporary key parameter selection. When
authorDr. Stephen Henson <steve@openssl.org>
Fri, 6 Apr 2012 20:15:50 +0000 (20:15 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 6 Apr 2012 20:15:50 +0000 (20:15 +0000)
enabled instead of requiring an application to hard code a (possibly
inappropriate) parameter set and delve into EC internals we just
automatically use the preferred curve.
(backport from HEAD)

CHANGES
apps/s_cb.c
apps/s_server.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_cert.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index 6765cdeb9597faf213c77a9c5b3f6da7421403ae..e4c168c53187b25ff56556ae717107746ead44ec 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,13 @@
 
  Changes between 1.0.1 and 1.0.2 [xx XXX xxxx]
 
+  *) Support for automatic EC temporary key parameter selection. If enabled
+     the most preferred EC parameters are automatically used instead of
+     hardcoded fixed parameters. Now a server just has to call:
+     SSL_CTX_set_ecdh_auto(ctx, 1) and the server will automatically
+     support ECDH and use the most appropriate parameters.
+     [Steve Henson]
+
   *) Enhance and tidy EC curve and point format TLS extension code. Use
      static structures instead of allocation if default values are used.
      New ctrls to set curves we wish to support and to retrieve shared curves.
index 141c222895206400b9880e6d1d75513094e59685..4395f194aa838d587c4048140f83e362ed2a20e7 100644 (file)
@@ -355,6 +355,8 @@ int ssl_print_curves(BIO *out, SSL *s)
                        cname = OBJ_nid2sn(nid);
                BIO_printf(out, "%s", cname);
                }
+       if (ncurves == 0)
+               BIO_puts(out, "NONE");
        BIO_puts(out, "\n");
        return 1;
        }
index a6b872e85599a91c527e9b9721a3aae53e065e2e..56e15fae38c07e858f73dc159b94ca268b7357d2 100644 (file)
@@ -1693,10 +1693,11 @@ bad:
                {
                EC_KEY *ecdh=NULL;
 
-               if (named_curve)
+               if (named_curve && strcmp(named_curve, "auto"))
                        {
-                       int nid = OBJ_sn2nid(named_curve);
-
+                       int nid = EC_curve_nist2nid(named_curve);
+                       if (nid == NID_undef)
+                               nid = OBJ_sn2nid(named_curve);
                        if (nid == 0)
                                {
                                BIO_printf(bio_err, "unknown curve name (%s)\n", 
@@ -1716,6 +1717,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");
index ab94ec8f1a9da8fde545af77b9f0afd041fffd61..c8cb8def0bbcd385b1e6f3828c43349a350bc35c 100644 (file)
@@ -3398,7 +3398,10 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
 
        case SSL_CTRL_GET_SHARED_CURVE:
                return tls1_shared_curve(s, larg);
+
+       case SSL_CTRL_SET_ECDH_AUTO:
+               s->cert->ecdh_tmp_auto = larg;
+               break;
 
        default:
                break;
@@ -3673,6 +3676,9 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                return tls1_set_curves_list(&ctx->tlsext_ellipticcurvelist,
                                        &ctx->tlsext_ellipticcurvelist_length,
                                                                parg);
+       case SSL_CTRL_SET_ECDH_AUTO:
+               ctx->cert->ecdh_tmp_auto = larg;
+               break;
 #endif /* !OPENSSL_NO_TLSEXT */
 
        /* A Thawte special :-) */
index cdbd281b8f45d3901055329c658102ba9433e7f1..5b66bb1ee859be5fa0e343911a423e2a912d0356 100644 (file)
@@ -1673,7 +1673,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),
@@ -1698,7 +1705,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;
index 60b61043f676648df84b20b23883fa5b2cfc82a7..8bee02f4782b09bcb33243818f74ad993600fee9 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1619,6 +1619,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTRL_SET_CURVES                    91
 #define SSL_CTRL_SET_CURVES_LIST               92
 #define SSL_CTRL_GET_SHARED_CURVE              93
+#define SSL_CTRL_SET_ECDH_AUTO                 94
 
 #define DTLSv1_get_timeout(ssl, arg) \
        SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
@@ -1690,6 +1691,10 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
        SSL_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s)
 #define SSL_get_shared_curve(s, n) \
        SSL_ctrl(s,SSL_CTRL_GET_SHARED_CURVE,n,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)
 
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_ssl(void);
index 6a1c484fc3c5def0f053311b417edb8e67077e16..a2682daaedd951321a57ccc8e0e1bf8b387ca6dc 100644 (file)
@@ -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++)
index dd7012b00f1ed278f3aff18225d6246b986e962d..5337ad5ac00a564dac57b6b91d864b237a518188 100644 (file)
@@ -2069,7 +2069,7 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
 #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);
index dc5b1cffc252e6cf49df14b5587e3f549bdf4de9..8015d4a513daf3d428d8a1e29d1d5e224c87bf06 100644 (file)
@@ -504,6 +504,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];
index b9b099d3c0d1678aa39cbd3678815abebac18c28..786c00667f8ec1375bd4ac9caac00bb478b13ed1 100644 (file)
@@ -332,33 +332,24 @@ static void tls1_get_curvelist(SSL *s, int sess,
                }
        }
 
-/* Return any common values from two lists. One list is used as a 
- * preference list where we return the most preferred match.
+/* Return nth shared curve. If nmatch == -1 return number of
+ * matches.
  */
-int tls1_shared_list(SSL *s,
-                       const unsigned char *l1, size_t l1len,
-                       const unsigned char *l2, size_t l2len,
-                       int nmatch)
+
+int tls1_shared_curve(SSL *s, int nmatch)
        {
        const unsigned char *pref, *supp;
        size_t preflen, supplen, i, j;
        int k;
-       l1len /= 2;
-       l2len /= 2;
-       if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE)
-               {
-               pref = l1;
-               preflen = l1len;
-               supp = l2;
-               supplen = l2len;
-               }
-       else
-               {
-               supp = l1;
-               supplen = l1len;
-               pref = l2;
-               preflen = l2len;
-               }
+       /* 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)
                {
@@ -368,32 +359,17 @@ int tls1_shared_list(SSL *s,
                        if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
                                {
                                if (nmatch == k)
-                                       return (pref[0] << 8) | pref[1];
+                                       {
+                                       int id = (pref[0] << 8) | pref[1];
+                                       return tls1_ec_curve_id2nid(id);
+                                       }
                                k++;
                                }
                        }
                }
-       if (nmatch == -1 && k > 0)
-               return k;
-       return -1;
-       }
-
-int tls1_shared_curve(SSL *s, int nmatch)
-       {
-       const unsigned char *l1, *l2;
-       size_t l1len, l2len;
-       int id;
-       /* Can't do anything on client side */
-       if (s->server == 0)
-               return -1;
-       /* 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;
-       return tls1_ec_curve_id2nid(id);
+               return k;
+       return 0;
        }
 
 int tls1_set_curves(unsigned char **pext, size_t *pextlen,
@@ -531,6 +507,7 @@ static int tls1_check_ec_key(SSL *s,
        {
        const unsigned char *p;
        size_t plen, i;
+       int j;
        /* If point formats extension present check it, otherwise everything
         * is supported (see RFC4492).
         */
@@ -546,19 +523,17 @@ static int tls1_check_ec_key(SSL *s,
                if (i == plen)
                        return 0;
                }
-       /* If curve list present check it, otherwise everything is
-        * supported.
-        */
-       if (s->session->tlsext_ellipticcurvelist)
+       /* Check curve is consistent with client and server preferences */
+       for (j = 0; j <= 1; j++)
                {
-               p = s->session->tlsext_ellipticcurvelist;
-               plen = s->session->tlsext_ellipticcurvelist_length;
+               tls1_get_curvelist(s, j, &p, &plen);
                for (i = 0; i < plen; i+=2, p+=2)
                        {
                        if (p[0] == curve_id[0] && p[1] == curve_id[1])
-                               return 1;
+                               break;
                        }
-               return 0;
+               if (i == plen)
+                       return 0;
                }
        return 1;
        }
@@ -585,6 +560,13 @@ int tls1_check_ec_tmp_key(SSL *s)
        {
        unsigned char curve_id[2];
        EC_KEY *ec = s->cert->ecdh_tmp;
+       if (s->cert->ecdh_tmp_auto)
+               {
+               /* Need a shared curve */
+               if (tls1_shared_curve(s, 0))
+                       return 1;
+               else return 0;
+               }
        if (!ec)
                {
                if (s->cert->ecdh_tmp_cb)