Initial revision of ECC extension handling.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 28 Mar 2012 15:05:04 +0000 (15:05 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 28 Mar 2012 15:05:04 +0000 (15:05 +0000)
Tidy some code up.

Don't allocate a structure to handle ECC extensions when it is used for
default values.

Make supported curves configurable.

Add ctrls to retrieve shared curves: not fully integrated with rest of
ECC code yet.

CHANGES
apps/s_cb.c
apps/s_client.c
apps/s_server.c
ssl/s3_lib.c
ssl/ssl.h
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssl_sess.c
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index dc7636e4d4277cda6abc1e8acd73abe06a30eff4..12b985a2d06ef2802dd9b667cfb02d6e411683e3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,13 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) 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.
+     Print out shared curves in s_server. New options to s_server and s_client
+     to set list of supported curves.
+     [Steve Henson]
+
   *) New ctrls to retrieve supported signature algorithms and 
      supported curve values as an array of NIDs. Extend openssl utility
      to print out received values.
index eab0a0803863f0248f653684f8f35d1c421385f3..141c222895206400b9880e6d1d75513094e59685 100644 (file)
@@ -316,18 +316,17 @@ int ssl_print_sigalgs(BIO *out, SSL *s)
 
 int ssl_print_curves(BIO *out, SSL *s)
        {
-       int i, ncurves, *curves;
-       ncurves = SSL_get1_curvelist(s, NULL);
+       int i, ncurves, *curves, nid;
+       const char *cname;
+       ncurves = SSL_get1_curves(s, NULL);
        if (ncurves <= 0)
                return 1;
        curves = OPENSSL_malloc(ncurves * sizeof(int));
-       SSL_get1_curvelist(s, curves);
+       SSL_get1_curves(s, curves);
 
        BIO_puts(out, "Supported Elliptic Curves: ");
        for (i = 0; i < ncurves; i++)
                {
-               int nid;
-               const char *cname;
                if (i)
                        BIO_puts(out, ":");
                nid = curves[i];
@@ -343,8 +342,20 @@ int ssl_print_curves(BIO *out, SSL *s)
                        BIO_printf(out, "%s", cname);
                        }
                }
-       BIO_puts(out, "\n");
+       BIO_puts(out, "\nShared Elliptic curves: ");
        OPENSSL_free(curves);
+       ncurves = SSL_get_shared_curve(s, -1);
+       for (i = 0; i < ncurves; i++)
+               {
+               if (i)
+                       BIO_puts(out, ":");
+               nid = SSL_get_shared_curve(s, i);
+               cname = EC_curve_nid2nist(nid);
+               if (!cname)
+                       cname = OBJ_nid2sn(nid);
+               BIO_printf(out, "%s", cname);
+               }
+       BIO_puts(out, "\n");
        return 1;
        }
 
index 6870368ff1f2c90475963b18c5e0666850f81aaa..55facead51b26980fc318839ae8a6bba3b8cce79 100644 (file)
@@ -601,6 +601,7 @@ int MAIN(int argc, char **argv)
 #endif
 #ifndef OPENSSL_NO_TLSEXT
        char *servername = NULL; 
+       char *curves=NULL;
         tlsextctx tlsextcbp = 
         {NULL,0};
 # ifndef OPENSSL_NO_NEXTPROTONEG
@@ -937,6 +938,11 @@ int MAIN(int argc, char **argv)
                        servername= *(++argv);
                        /* meth=TLSv1_client_method(); */
                        }
+               else if (strcmp(*argv,"-curves") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       curves= *(++argv);
+                       }
 #endif
 #ifndef OPENSSL_NO_JPAKE
                else if (strcmp(*argv,"-jpake") == 0)
@@ -1176,6 +1182,12 @@ bad:
                }
 
 #ifndef OPENSSL_NO_TLSEXT
+       if (curves != NULL)
+               if(!SSL_CTX_set1_curves_list(ctx,curves)) {
+               BIO_printf(bio_err,"error setting curve list\n");
+               ERR_print_errors(bio_err);
+               goto end;
+       }
        if (servername != NULL)
                {
                tlsextcbp.biodebug = bio_err;
index 608f3208dcc09dc60850c562d05d67e9a21c3663..5f1bcffb91c098f412f479b57a63f34baa6b3eb9 100644 (file)
@@ -273,6 +273,7 @@ static int s_server_session_id_context = 1; /* anything will do */
 static const char *s_cert_file=TEST_CERT,*s_key_file=NULL;
 #ifndef OPENSSL_NO_TLSEXT
 static const char *s_cert_file2=TEST_CERT2,*s_key_file2=NULL;
+static char *curves=NULL;
 #endif
 static char *s_dcert_file=NULL,*s_dkey_file=NULL;
 #ifdef FIONBIO
@@ -437,6 +438,7 @@ static void s_server_init(void)
        s_cert_file=TEST_CERT;
        s_key_file=NULL;
 #ifndef OPENSSL_NO_TLSEXT
+       curves=NULL;
        s_cert_file2=TEST_CERT2;
        s_key_file2=NULL;
        ctx2=NULL;
@@ -1174,6 +1176,11 @@ int MAIN(int argc, char *argv[])
                                goto bad;
                                }
                        }
+               else if (strcmp(*argv,"-curves") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       curves= *(++argv);
+                       }
 #endif
                else if (strcmp(*argv,"-msg") == 0)
                        { s_msg=1; }
@@ -1849,6 +1856,23 @@ bad:
                        }
 #endif
                }
+#ifndef OPENSSL_NO_TLSEXT
+       if (curves)
+               {
+               if(!SSL_CTX_set1_curves_list(ctx,curves))
+                       {
+                       BIO_printf(bio_err,"error setting curves list\n");
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               if(ctx2 && !SSL_CTX_set1_curves_list(ctx2,curves))
+                       {
+                       BIO_printf(bio_err,"error setting curves list\n");
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               }
+#endif
        SSL_CTX_set_verify(ctx,s_server_verify,verify_callback);
        SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
                sizeof s_server_session_id_context);
index 248bb94df843f63748113c82571c362e9b5a199a..f680d35233d7f8382c1da5cc800533fbc7dc6b36 100644 (file)
@@ -3365,7 +3365,7 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                else
                        return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg);
 
-       case SSL_CTRL_GET_CURVELIST:
+       case SSL_CTRL_GET_CURVES:
                {
                unsigned char *clist;
                size_t clistlen;
@@ -3391,6 +3391,20 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                return (int)clistlen;
                }
 
+       case SSL_CTRL_SET_CURVES:
+               return tls1_set_curves(&s->tlsext_ellipticcurvelist,
+                                       &s->tlsext_ellipticcurvelist_length,
+                                                               parg, larg);
+
+       case SSL_CTRL_SET_CURVES_LIST:
+               return tls1_set_curves_list(&s->tlsext_ellipticcurvelist,
+                                       &s->tlsext_ellipticcurvelist_length,
+                                                               parg);
+
+       case SSL_CTRL_GET_SHARED_CURVE:
+               return tls1_shared_curve(s, larg);
+
        default:
                break;
                }
@@ -3659,6 +3673,16 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                ctx->srp_ctx.strength=larg;
                break;
 #endif
+
+       case SSL_CTRL_SET_CURVES:
+               return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
+                                       &ctx->tlsext_ellipticcurvelist_length,
+                                                               parg, larg);
+
+       case SSL_CTRL_SET_CURVES_LIST:
+               return tls1_set_curves_list(&ctx->tlsext_ellipticcurvelist,
+                                       &ctx->tlsext_ellipticcurvelist_length,
+                                                               parg);
 #endif /* !OPENSSL_NO_TLSEXT */
 
        /* A Thawte special :-) */
index 3e255fcfeed1e347cd44a68569679cb45b806f23..6f5c305f72dfa79e9038437d0027438964e730f1 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -982,6 +982,13 @@ struct ssl_ctx_st
        /* Callback for disabling session caching and ticket support
         * on a session basis, depending on the chosen cipher. */
        int (*not_resumable_session_cb)(SSL *ssl, int is_forward_secure);
+#ifndef OPENSSL_NO_EC
+       /* EC extension values inherited by SSL structure */
+       size_t tlsext_ecpointformatlist_length;
+       unsigned char *tlsext_ecpointformatlist;
+       size_t tlsext_ellipticcurvelist_length;
+       unsigned char *tlsext_ellipticcurvelist;
+#endif /* OPENSSL_NO_EC */
        };
 
 #endif
@@ -1618,7 +1625,10 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTRL_CHAIN                         88
 #define SSL_CTRL_CHAIN_CERT                    89
 
-#define SSL_CTRL_GET_CURVELIST                 90
+#define SSL_CTRL_GET_CURVES                    90
+#define SSL_CTRL_SET_CURVES                    91
+#define SSL_CTRL_SET_CURVES_LIST               92
+#define SSL_CTRL_GET_SHARED_CURVE              93
 
 #define DTLSv1_get_timeout(ssl, arg) \
        SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
@@ -1678,9 +1688,18 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
        SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509)
 #define SSL_add1_chain_cert(ctx,x509) \
        SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509)
-#define SSL_get1_curvelist(ctx, s) \
-       SSL_ctrl(ctx,SSL_CTRL_GET_CURVELIST,0,(char *)s)
-
+#define SSL_get1_curves(ctx, s) \
+       SSL_ctrl(ctx,SSL_CTRL_GET_CURVES,0,(char *)s)
+#define SSL_CTX_set1_curves(ctx, clist, clistlen) \
+       SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist)
+#define SSL_CTX_set1_curves_list(ctx, s) \
+       SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CURVES_LIST,0,(char *)s)
+#define SSL_set1_curves(ctx, clist, clistlen) \
+       SSL_ctrl(ctx,SSL_CTRL_SET_CURVES,clistlen,(char *)clist)
+#define SSL_set1_curves_list(ctx, s) \
+       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)
 
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_ssl(void);
index 6256df8c95c01559c3fa6422a6b54e004ea030d6..af25d3e4d3148140800fe9e9fbd482c7477ebbec 100644 (file)
@@ -358,6 +358,28 @@ SSL *SSL_new(SSL_CTX *ctx)
        s->tlsext_ocsp_resplen = -1;
        CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
        s->initial_ctx=ctx;
+#ifndef OPENSSL_NO_EC
+       if (ctx->tlsext_ecpointformatlist)
+               {
+               s->tlsext_ecpointformatlist =
+                       BUF_memdup(ctx->tlsext_ecpointformatlist,
+                                       ctx->tlsext_ecpointformatlist_length);
+               if (!s->tlsext_ecpointformatlist)
+                       goto err;
+               s->tlsext_ecpointformatlist_length =
+                                       ctx->tlsext_ecpointformatlist_length;
+               }
+       if (ctx->tlsext_ellipticcurvelist)
+               {
+               s->tlsext_ellipticcurvelist =
+                       BUF_memdup(ctx->tlsext_ellipticcurvelist,
+                                       ctx->tlsext_ellipticcurvelist_length);
+               if (!s->tlsext_ellipticcurvelist)
+                       goto err;
+               s->tlsext_ellipticcurvelist_length = 
+                                       ctx->tlsext_ellipticcurvelist_length;
+               }
+#endif
 # ifndef OPENSSL_NO_NEXTPROTONEG
        s->next_proto_negotiated = NULL;
 # endif
@@ -1975,6 +1997,14 @@ void SSL_CTX_free(SSL_CTX *a)
                ssl_buf_freelist_free(a->wbuf_freelist);
        if (a->rbuf_freelist)
                ssl_buf_freelist_free(a->rbuf_freelist);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+# ifndef OPENSSL_NO_EC
+       if (a->tlsext_ecpointformatlist)
+               OPENSSL_free(a->tlsext_ecpointformatlist);
+       if (a->tlsext_ellipticcurvelist)
+               OPENSSL_free(a->tlsext_ellipticcurvelist);
+# endif /* OPENSSL_NO_EC */
 #endif
 
        OPENSSL_free(a);
index 44d9d9ad55e735cd2c12accba9a043543e52feba..91169da52371b9216d230044a3b0d739b5eb4d67 100644 (file)
@@ -1102,9 +1102,18 @@ SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 #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);
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+                       int *curves, size_t ncurves);
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
+                               const char *str);
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
+int tls1_shared_list(SSL *s,
+                       const unsigned char *l1, size_t l1len,
+                       const unsigned char *l2, size_t l2len,
+                       int nmatch);
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
 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);
index 05e4fb9fda27470fe85ff92f0458c668c979eb97..9e8f2e4eced2a7911e3fd046e9b52b4c4f12e097 100644 (file)
@@ -393,32 +393,6 @@ int ssl_get_new_session(SSL *s, int session)
                                return 0;
                                }
                        }
-#ifndef OPENSSL_NO_EC
-               if (s->tlsext_ecpointformatlist)
-                       {
-                       if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->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);
-                       }
-               if (s->tlsext_ellipticcurvelist)
-                       {
-                       if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
-                       if ((ss->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
-                               {
-                               SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE);
-                               SSL_SESSION_free(ss);
-                               return 0;
-                               }
-                       ss->tlsext_ellipticcurvelist_length = s->tlsext_ellipticcurvelist_length;
-                       memcpy(ss->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
-                       }
-#endif
 #endif
                }
        else
index da941ad73e83828c7819a2e99d8704ece7a976e6..7a8dc31203ea47b2864b722611eea4fb59154a8c 100644 (file)
@@ -202,33 +202,41 @@ static int nid_list[] =
                NID_secp521r1  /* secp521r1 (25) */     
        };
 
-static int pref_list[] =
+
+static const unsigned char ecformats_default[] = 
        {
-               NID_sect571r1, /* sect571r1 (14) */ 
-               NID_sect571k1, /* sect571k1 (13) */ 
-               NID_secp521r1, /* secp521r1 (25) */     
-               NID_sect409k1, /* sect409k1 (11) */ 
-               NID_sect409r1, /* sect409r1 (12) */
-               NID_secp384r1, /* secp384r1 (24) */
-               NID_sect283k1, /* sect283k1 (9) */
-               NID_sect283r1, /* sect283r1 (10) */ 
-               NID_secp256k1, /* secp256k1 (22) */ 
-               NID_X9_62_prime256v1, /* secp256r1 (23) */ 
-               NID_sect239k1, /* sect239k1 (8) */ 
-               NID_sect233k1, /* sect233k1 (6) */
-               NID_sect233r1, /* sect233r1 (7) */ 
-               NID_secp224k1, /* secp224k1 (20) */ 
-               NID_secp224r1, /* secp224r1 (21) */
-               NID_sect193r1, /* sect193r1 (4) */ 
-               NID_sect193r2, /* sect193r2 (5) */ 
-               NID_secp192k1, /* secp192k1 (18) */
-               NID_X9_62_prime192v1, /* secp192r1 (19) */ 
-               NID_sect163k1, /* sect163k1 (1) */
-               NID_sect163r1, /* sect163r1 (2) */
-               NID_sect163r2, /* sect163r2 (3) */
-               NID_secp160k1, /* secp160k1 (15) */
-               NID_secp160r1, /* secp160r1 (16) */ 
-               NID_secp160r2, /* secp160r2 (17) */ 
+       TLSEXT_ECPOINTFORMAT_uncompressed,
+       TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime,
+       TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2
+       };
+
+static const unsigned char eccurves_default[] =
+       {
+               0,14, /* sect571r1 (14) */ 
+               0,13, /* sect571k1 (13) */ 
+               0,25, /* secp521r1 (25) */      
+               0,11, /* sect409k1 (11) */ 
+               0,12, /* sect409r1 (12) */
+               0,24, /* secp384r1 (24) */
+               0,9,  /* sect283k1 (9) */
+               0,10, /* sect283r1 (10) */ 
+               0,22, /* secp256k1 (22) */ 
+               0,23, /* secp256r1 (23) */ 
+               0,8,  /* sect239k1 (8) */ 
+               0,6,  /* sect233k1 (6) */
+               0,7,  /* sect233r1 (7) */ 
+               0,20, /* secp224k1 (20) */ 
+               0,21, /* secp224r1 (21) */
+               0,4,  /* sect193r1 (4) */ 
+               0,5,  /* sect193r2 (5) */ 
+               0,18, /* secp192k1 (18) */
+               0,19, /* secp192r1 (19) */ 
+               0,1,  /* sect163k1 (1) */
+               0,2,  /* sect163r1 (2) */
+               0,3,  /* sect163r2 (3) */
+               0,15, /* secp160k1 (15) */
+               0,16, /* secp160r1 (16) */ 
+               0,17, /* secp160r2 (17) */ 
        };
 
 int tls1_ec_curve_id2nid(int curve_id)
@@ -299,6 +307,166 @@ int tls1_ec_nid2curve_id(int nid)
                return 0;
                }
        }
+
+/* Return any common values from two lists. One list is used as a 
+ * preference list where we return the most preferred match.
+ */
+int tls1_shared_list(SSL *s,
+                       const unsigned char *l1, size_t l1len,
+                       const unsigned char *l2, size_t l2len,
+                       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;
+               }
+       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)
+                                       return (pref[0] << 8) | pref[1];
+                               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;
+       /* Use our preferred curve list, if not set use default */
+       if (s->tlsext_ellipticcurvelist)
+               {
+               l1 = s->tlsext_ellipticcurvelist;
+               l1len = s->tlsext_ellipticcurvelist_length;
+               }
+       else
+               {
+               l1 = eccurves_default;
+               l1len = sizeof(eccurves_default);
+               }
+       /* Use peer preferred curve list, if not set use default */
+       if(s->session->tlsext_ellipticcurvelist)
+               {
+               l2 = s->session->tlsext_ellipticcurvelist;
+               l2len =s->session->tlsext_ellipticcurvelist_length;
+               }
+       else
+               {
+               l2 = eccurves_default;
+               l2len = sizeof(eccurves_default);
+               }
+       id = tls1_shared_list(s, l1, l1len, l2, l2len, nmatch);
+       if (nmatch == -1)
+               return id;
+       return tls1_ec_curve_id2nid(id);
+       }
+
+int tls1_set_curves(unsigned char **pext, size_t *pextlen,
+                       int *curves, size_t ncurves)
+       {
+       unsigned char *clist, *p;
+       size_t i;
+       /* Bitmap of curves included to detect duplicates: only works
+        * while curve ids < 32 
+        */
+       unsigned long dup_list = 0;
+       clist = OPENSSL_malloc(ncurves * 2);
+       if (!clist)
+               return 0;
+       for (i = 0, p = clist; i < ncurves; i++)
+               {
+               unsigned long idmask;
+               int id;
+               id = tls1_ec_nid2curve_id(curves[i]);
+               idmask = 1L << id;
+               if (!id || (dup_list & idmask))
+                       {
+                       OPENSSL_free(clist);
+                       return 0;
+                       }
+               dup_list |= idmask;
+               s2n(id, p);
+               }
+       if (*pext)
+               OPENSSL_free(*pext);
+       *pext = clist;
+       *pextlen = ncurves * 2;
+       return 1;
+       }
+
+#define MAX_CURVELIST  25
+
+typedef struct
+       {
+       size_t nidcnt;
+       int nid_arr[MAX_CURVELIST];
+       } nid_cb_st;
+
+static int nid_cb(const char *elem, int len, void *arg)
+       {
+       nid_cb_st *narg = arg;
+       size_t i;
+       int nid;
+       char etmp[20];
+       if (narg->nidcnt == MAX_CURVELIST)
+               return 0;
+       if (len > (int)(sizeof(etmp) - 1))
+               return 0;
+       memcpy(etmp, elem, len);
+       etmp[len] = 0;
+       nid = EC_curve_nist2nid(etmp);
+       if (nid == NID_undef)
+               nid = OBJ_sn2nid(etmp);
+       if (nid == NID_undef)
+               nid = OBJ_ln2nid(etmp);
+       if (nid == NID_undef)
+               return 0;
+       for (i = 0; i < narg->nidcnt; i++)
+               if (narg->nid_arr[i] == nid)
+                       return 0;
+       narg->nid_arr[narg->nidcnt++] = nid;
+       return 1;
+       }
+/* Set curves based on a colon separate list */
+int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, 
+                               const char *str)
+       {
+       nid_cb_st ncb;
+       ncb.nidcnt = 0;
+       if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb))
+               return 0;
+       return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt);
+       }
+
 #endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_TLSEXT
@@ -364,6 +532,30 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        {
        int extdatalen=0;
        unsigned char *ret = p;
+#ifndef OPENSSL_NO_EC
+       /* See if we support any ECC ciphersuites */
+       int using_ecc = 0;
+       if (s->version != DTLS1_VERSION && s->version >= TLS1_VERSION)
+               {
+               int i;
+               unsigned long alg_k, alg_a;
+               STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
+
+               for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
+                       {
+                       SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
+
+                       alg_k = c->algorithm_mkey;
+                       alg_a = c->algorithm_auth;
+                       if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)
+                               || (alg_a & SSL_aECDSA)))
+                               {
+                               using_ecc = 1;
+                               break;
+                               }
+                       }
+               }
+#endif
 
        /* don't add extensions for SSLv3 unless doing secure renegotiation */
        if (s->client_version == SSL3_VERSION
@@ -460,51 +652,68 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 #endif
 
 #ifndef OPENSSL_NO_EC
-       if (s->tlsext_ecpointformatlist != NULL &&
-           s->version != DTLS1_VERSION)
+       if (using_ecc)
                {
                /* Add TLS extension ECPointFormats to the ClientHello message */
                long lenmax; 
+               const unsigned char *plist;
+               size_t plistlen;
+               /* If we have a custom point format list use it otherwise
+                * use default */
+               plist = s->tlsext_ecpointformatlist;
+               if (plist)
+                       plistlen = s->tlsext_ecpointformatlist_length;
+               else
+                       {
+                       plist = ecformats_default;
+                       plistlen = sizeof(ecformats_default);
+                       }
 
                if ((lenmax = limit - ret - 5) < 0) return NULL; 
-               if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL;
-               if (s->tlsext_ecpointformatlist_length > 255)
+               if (plistlen > (size_t)lenmax) return NULL;
+               if (plistlen > 255)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        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;
-               }
-       if (s->tlsext_ellipticcurvelist != NULL &&
-           s->version != DTLS1_VERSION)
-               {
+               s2n(plistlen + 1,ret);
+               *(ret++) = (unsigned char)plistlen ;
+               memcpy(ret, plist, plistlen);
+               ret+=plistlen;
+
                /* Add TLS extension EllipticCurves to the ClientHello message */
-               long lenmax; 
+               plist = s->tlsext_ellipticcurvelist;
+               /* If we have a custom curve list use it otherwise
+                * use default */
+               if (plist)
+                       plistlen = s->tlsext_ellipticcurvelist_length;
+               else
+                       {
+                       plist = eccurves_default;
+                       plistlen = sizeof(eccurves_default);
+                       }
 
                if ((lenmax = limit - ret - 6) < 0) return NULL; 
-               if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
-               if (s->tlsext_ellipticcurvelist_length > 65532)
+               if (plistlen > (size_t)lenmax) return NULL;
+               if (plistlen > 65532)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        return NULL;
                        }
                
                s2n(TLSEXT_TYPE_elliptic_curves,ret);
-               s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+               s2n(plistlen + 2, ret);
 
                /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
                 * elliptic_curve_list, but the examples use two bytes.
                 * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
                 * resolves this to two bytes.
                 */
-               s2n(s->tlsext_ellipticcurvelist_length, ret);
-               memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
-               ret+=s->tlsext_ellipticcurvelist_length;
+               s2n(plistlen, ret);
+               memcpy(ret, plist, plistlen);
+               ret+=plistlen;
                }
 #endif /* OPENSSL_NO_EC */
 
@@ -1641,59 +1850,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
 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 
-        * and elliptic curves we support.
-        */
-       int using_ecc = 0;
-       int i;
-       unsigned char *j;
-       unsigned long alg_k, alg_a;
-       STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
-
-       for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
-               {
-               SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
-
-               alg_k = c->algorithm_mkey;
-               alg_a = c->algorithm_auth;
-               if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe) || (alg_a & SSL_aECDSA)))
-                       {
-                       using_ecc = 1;
-                       break;
-                       }
-               }
-       using_ecc = using_ecc && (s->version >= TLS1_VERSION);
-       if (using_ecc)
-               {
-               if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
-               if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL)
-                       {
-                       SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
-                       return -1;
-                       }
-               s->tlsext_ecpointformatlist_length = 3;
-               s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
-               s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
-               s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
-
-               /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
-               if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
-               s->tlsext_ellipticcurvelist_length = sizeof(pref_list)/sizeof(pref_list[0]) * 2;
-               if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
-                       {
-                       s->tlsext_ellipticcurvelist_length = 0;
-                       SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
-                       return -1;
-                       }
-               for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i <
-                               sizeof(pref_list)/sizeof(pref_list[0]); i++)
-                       {
-                       int id = tls1_ec_nid2curve_id(pref_list[i]);
-                       s2n(id,j);
-                       }
-               }
-#endif /* OPENSSL_NO_EC */
 
 #ifdef TLSEXT_TYPE_opaque_prf_input
        {