Implement Supported Elliptic Curves Extension.
authorBodo Möller <bodo@openssl.org>
Thu, 30 Mar 2006 02:44:56 +0000 (02:44 +0000)
committerBodo Möller <bodo@openssl.org>
Thu, 30 Mar 2006 02:44:56 +0000 (02:44 +0000)
Submitted by: Douglas Stebila

CHANGES
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_asn1.c
ssl/ssl_locl.h
ssl/ssl_sess.c
ssl/t1_lib.c

diff --git a/CHANGES b/CHANGES
index b33ec3274312c101fe07542224a9576bb85f3c8c..462befa49f1ce105ff7841cbb3edb15c4f2168f4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 0.9.8a and 0.9.9  [xx XXX xxxx]
 
+  *) Implement the Supported Elliptic Curves Extension for
+     ECC ciphersuites from draft-ietf-tls-ecc-12.txt.
+     [Douglas Stebila]
+
   *) Don't free up OIDs in OBJ_cleanup() if they are in use by EVP_MD or
      EVP_CIPHER structures to avoid later problems in EVP_cleanup().
      [Steve Henson]
index a8f2b8f55750a8ed3702c36222e52c5ed24c00b2..1b9b586f96fc9dc2d8ff7ed44a1b9d08bdc0f4f9 100644 (file)
@@ -165,7 +165,6 @@ static const SSL_METHOD *ssl3_get_client_method(int ver);
 static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
 
 #ifndef OPENSSL_NO_ECDH
-static int curve_id2nid(int curve_id);
 int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs);
 #endif
 
@@ -1332,7 +1331,7 @@ int ssl3_get_key_exchange(SSL *s)
                param_len=3;
                if ((param_len > n) ||
                    (*p != NAMED_CURVE_TYPE) || 
-                   ((curve_nid = curve_id2nid(*(p + 2))) == 0)) 
+                   ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0)) 
                        {
                        al=SSL_AD_INTERNAL_ERROR;
                        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
@@ -2609,46 +2608,3 @@ f_err:
 err:
        return(0);
        }
-
-
-#ifndef OPENSSL_NO_ECDH
-/* This is the complement of nid2curve_id in s3_srvr.c. */
-static int curve_id2nid(int curve_id)
-{
-       /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001)
-        * (no changes in draft-ietf-tls-ecc-03.txt [June 2003]) */
-       static int nid_list[26] =
-       {
-               0,
-               NID_sect163k1, /* sect163k1 (1) */
-               NID_sect163r1, /* sect163r1 (2) */
-               NID_sect163r2, /* sect163r2 (3) */
-               NID_sect193r1, /* sect193r1 (4) */ 
-               NID_sect193r2, /* sect193r2 (5) */ 
-               NID_sect233k1, /* sect233k1 (6) */
-               NID_sect233r1, /* sect233r1 (7) */ 
-               NID_sect239k1, /* sect239k1 (8) */ 
-               NID_sect283k1, /* sect283k1 (9) */
-               NID_sect283r1, /* sect283r1 (10) */ 
-               NID_sect409k1, /* sect409k1 (11) */ 
-               NID_sect409r1, /* sect409r1 (12) */
-               NID_sect571k1, /* sect571k1 (13) */ 
-               NID_sect571r1, /* sect571r1 (14) */ 
-               NID_secp160k1, /* secp160k1 (15) */
-               NID_secp160r1, /* secp160r1 (16) */ 
-               NID_secp160r2, /* secp160r2 (17) */ 
-               NID_secp192k1, /* secp192k1 (18) */
-               NID_X9_62_prime192v1, /* secp192r1 (19) */ 
-               NID_secp224k1, /* secp224k1 (20) */ 
-               NID_secp224r1, /* secp224r1 (21) */
-               NID_secp256k1, /* secp256k1 (22) */ 
-               NID_X9_62_prime256v1, /* secp256r1 (23) */ 
-               NID_secp384r1, /* secp384r1 (24) */
-               NID_secp521r1  /* secp521r1 (25) */     
-       };
-       
-       if ((curve_id < 1) || (curve_id > 25)) return 0;
-
-       return nid_list[curve_id];
-}
-#endif
index a48869257951087ecd490b3079146103481d0f03..8e59a92905553d6500966d26d5db4878630aa2a3 100644 (file)
@@ -2046,7 +2046,9 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
        int i,j,ok;
 #ifndef OPENSSL_NO_TLSEXT
 #ifndef OPENSSL_NO_EC
-       int ec_ok;
+       int ec_ok, ec_nid;
+       unsigned char ec_search1, ec_search2;
+       unsigned char *ec_ptr;
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
        CERT *cert;
@@ -2188,6 +2190,103 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
                                }
                        ok = ok && ec_ok;
                        }
+               if (
+                       /* if we are considering an ECC cipher suite that uses our certificate */
+                       (alg & SSL_aECDSA)
+                       /* and we have an ECC certificate */
+                       && (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL)
+                       /* and the client specified an EllipticCurves extension */
+                       && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
+               )
+                       {
+                       ec_ok = 0;
+                       if (
+                               (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL)
+                               && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL)
+                       )
+                               {
+                               ec_nid = EC_GROUP_get_curve_name(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group);
+                               if ((ec_nid == 0)
+                                       && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL)
+                               )
+                                       {
+                                       if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x01;
+                                               }
+                                       else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x02;
+                                               }
+                                       }
+                               else
+                                       {
+                                       ec_search1 = 0x00;
+                                       ec_search2 = tls1_ec_nid2curve_id(ec_nid);
+                                       }
+                               if ((ec_search1 != 0) || (ec_search2 != 0))
+                                       {
+                                       for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
+                                               {
+                                               if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
+                                                       {
+                                                       ec_ok = 1;
+                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       ok = ok && ec_ok;
+                       }
+               if (
+                       /* if we are considering an ECC cipher suite that uses an ephemeral EC key */
+                       ((alg & SSL_kECDH) || (alg & SSL_kECDHE))
+                       /* and we have an ephemeral EC key */
+                       && (s->cert->ecdh_tmp != NULL)
+                       /* and the client specified an EllipticCurves extension */
+                       && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL))
+               )
+                       {
+                       ec_ok = 0;
+                       if (s->cert->ecdh_tmp->group != NULL)
+                               {
+                               ec_nid = EC_GROUP_get_curve_name(s->cert->ecdh_tmp->group);
+                               if ((ec_nid == 0)
+                                       && (s->cert->ecdh_tmp->group->meth != NULL)
+                               )
+                                       {
+                                       if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_prime_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x01;
+                                               }
+                                       else if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_characteristic_two_field)
+                                               {
+                                               ec_search1 = 0xFF;
+                                               ec_search2 = 0x02;
+                                               }
+                                       }
+                               else
+                                       {
+                                       ec_search1 = 0x00;
+                                       ec_search2 = tls1_ec_nid2curve_id(ec_nid);
+                                       }
+                               if ((ec_search1 != 0) || (ec_search2 != 0))
+                                       {
+                                       for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++)
+                                               {
+                                               if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2))
+                                                       {
+                                                       ec_ok = 1;
+                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       ok = ok && ec_ok;
+                       }
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
index 121cdfb6f232f39a7123ad63acc092a784b632ba..bfbf951f72cc8d6691e9ded771f60717129b7f3f 100644 (file)
 
 static const SSL_METHOD *ssl3_get_server_method(int ver);
 
-#ifndef OPENSSL_NO_ECDH
-static int nid2curve_id(int nid);
-#endif
-
 static const SSL_METHOD *ssl3_get_server_method(int ver)
        {
        if (ver == SSL3_VERSION)
@@ -1376,7 +1372,7 @@ int ssl3_send_server_key_exchange(SSL *s)
                         * supported named curves, curve_id is non-zero.
                         */
                        if ((curve_id = 
-                           nid2curve_id(EC_GROUP_get_curve_name(group)))
+                           tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
                            == 0)
                                {
                                SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
@@ -2696,67 +2692,3 @@ int ssl3_send_server_certificate(SSL *s)
        /* SSL3_ST_SW_CERT_B */
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
-
-
-#ifndef OPENSSL_NO_ECDH
-/* This is the complement of curve_id2nid in s3_clnt.c. */
-static int nid2curve_id(int nid)
-{
-       /* ECC curves from draft-ietf-tls-ecc-01.txt (Mar 15, 2001)
-        * (no changes in draft-ietf-tls-ecc-03.txt [June 2003]) */
-       switch (nid) {
-       case NID_sect163k1: /* sect163k1 (1) */
-               return 1;
-       case NID_sect163r1: /* sect163r1 (2) */
-               return 2;
-       case NID_sect163r2: /* sect163r2 (3) */
-               return 3;
-       case NID_sect193r1: /* sect193r1 (4) */ 
-               return 4;
-       case NID_sect193r2: /* sect193r2 (5) */ 
-               return 5;
-       case NID_sect233k1: /* sect233k1 (6) */
-               return 6;
-       case NID_sect233r1: /* sect233r1 (7) */ 
-               return 7;
-       case NID_sect239k1: /* sect239k1 (8) */ 
-               return 8;
-       case NID_sect283k1: /* sect283k1 (9) */
-               return 9;
-       case NID_sect283r1: /* sect283r1 (10) */ 
-               return 10;
-       case NID_sect409k1: /* sect409k1 (11) */ 
-               return 11;
-       case NID_sect409r1: /* sect409r1 (12) */
-               return 12;
-       case NID_sect571k1: /* sect571k1 (13) */ 
-               return 13;
-       case NID_sect571r1: /* sect571r1 (14) */ 
-               return 14;
-       case NID_secp160k1: /* secp160k1 (15) */
-               return 15;
-       case NID_secp160r1: /* secp160r1 (16) */ 
-               return 16;
-       case NID_secp160r2: /* secp160r2 (17) */ 
-               return 17;
-       case NID_secp192k1: /* secp192k1 (18) */
-               return 18;
-       case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
-               return 19;
-       case NID_secp224k1: /* secp224k1 (20) */ 
-               return 20;
-       case NID_secp224r1: /* secp224r1 (21) */
-               return 21;
-       case NID_secp256k1: /* secp256k1 (22) */ 
-               return 22;
-       case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
-               return 23;
-       case NID_secp384r1: /* secp384r1 (24) */
-               return 24;
-       case NID_secp521r1:  /* secp521r1 (25) */       
-               return 25;
-       default:
-               return 0;
-       }
-}
-#endif
index 7e2a8c170f11a805d518a597fb66a119a19cbd8c..f0ed4f105c6de97bd4927546d4d33181a0aaf33f 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -512,6 +512,8 @@ typedef struct ssl_session_st
 #ifndef OPENSSL_NO_EC
        size_t tlsext_ecpointformatlist_length;
        unsigned char *tlsext_ecpointformatlist; /* peer's list */
+       size_t tlsext_ellipticcurvelist_length;
+       unsigned char *tlsext_ellipticcurvelist; /* peer's list */
 #endif /* OPENSSL_NO_EC */
 #endif
        } SSL_SESSION;
@@ -1066,6 +1068,8 @@ struct ssl_st
 #ifndef OPENSSL_NO_EC
        size_t tlsext_ecpointformatlist_length;
        unsigned char *tlsext_ecpointformatlist; /* our list */
+       size_t tlsext_ellipticcurvelist_length;
+       unsigned char *tlsext_ellipticcurvelist; /* our list */
 #endif /* OPENSSL_NO_EC */
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
 #define session_ctx initial_ctx
index b9148b23dedf1cce0de45284f677334e394fbb86..dbe8ea8ebad0d8102af742b522e833a00287ab60 100644 (file)
@@ -108,6 +108,7 @@ typedef struct ssl_session_asn1_st
        ASN1_OCTET_STRING tlsext_hostname;
 #ifndef OPENSSL_NO_EC
        ASN1_OCTET_STRING tlsext_ecpointformatlist;
+       ASN1_OCTET_STRING tlsext_ellipticcurvelist;
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
@@ -119,7 +120,7 @@ typedef struct ssl_session_asn1_st
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
        {
 #define LSIZE2 (sizeof(long)*2)
-       int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0;
+       int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0,v7=0,v8=0,v9=0,v10=0;
        unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
        unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
        long l;
@@ -228,6 +229,12 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
                a.tlsext_ecpointformatlist.type=V_ASN1_OCTET_STRING;
                a.tlsext_ecpointformatlist.data=(unsigned char *)in->tlsext_ecpointformatlist;
                }
+       if (in->tlsext_ellipticcurvelist)
+               {
+               a.tlsext_ellipticcurvelist.length=in->tlsext_ellipticcurvelist_length;
+               a.tlsext_ellipticcurvelist.type=V_ASN1_OCTET_STRING;
+               a.tlsext_ellipticcurvelist.data=(unsigned char *)in->tlsext_ellipticcurvelist;
+               }
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
@@ -272,13 +279,15 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 #ifndef OPENSSL_NO_EC
        if (in->tlsext_ecpointformatlist)
                M_ASN1_I2D_len_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+       if (in->tlsext_ellipticcurvelist)
+               M_ASN1_I2D_len_EXP_opt(&(a.tlsext_ellipticcurvelist), i2d_ASN1_OCTET_STRING,8,v8);
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        if (in->psk_identity_hint)
-               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
+               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,9,v9);
        if (in->psk_identity)
-               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
+               M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,10,v10);
 #endif /* OPENSSL_NO_PSK */
 
        M_ASN1_I2D_seq_total();
@@ -310,13 +319,15 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 #ifndef OPENSSL_NO_EC
        if (in->tlsext_ecpointformatlist)
                M_ASN1_I2D_put_EXP_opt(&(a.tlsext_ecpointformatlist), i2d_ASN1_OCTET_STRING,7,v7);
+       if (in->tlsext_ellipticcurvelist)
+               M_ASN1_I2D_put_EXP_opt(&(a.tlsext_ellipticcurvelist), i2d_ASN1_OCTET_STRING,8,v8);
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 #ifndef OPENSSL_NO_PSK
        if (in->psk_identity_hint)
-               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,8,v8);
+               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,9,v9);
        if (in->psk_identity)
-               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,9,v9);
+               M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,10,v10);
 #endif /* OPENSSL_NO_PSK */
        M_ASN1_I2D_finish();
        }
@@ -517,13 +528,26 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
        else
                ret->tlsext_ecpointformatlist_length=0;
                ret->tlsext_ecpointformatlist=NULL;
+       os.length=0;
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
+       if (os.data)
+               {
+               ret->tlsext_ellipticcurvelist_length=os.length;
+               memcpy(ret->tlsext_ellipticcurvelist,os.data,ret->tlsext_ellipticcurvelist_length);
+               OPENSSL_free(os.data);
+               os.data = NULL;
+               os.length = 0;
+               }
+       else
+               ret->tlsext_ellipticcurvelist_length=0;
+               ret->tlsext_ellipticcurvelist=NULL;
 #endif /* OPENSSL_NO_EC */
 #endif /* OPENSSL_NO_TLSEXT */
 
 #ifndef OPENSSL_NO_PSK
        os.length=0;
        os.data=NULL;
-       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,9);
        if (os.data)
                {
                ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
@@ -536,7 +560,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 
        os.length=0;
        os.data=NULL;
-       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,9);
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
        if (os.data)
                {
                ret->psk_identity = BUF_strndup((char *)os.data, os.length);
index f0527f459a4014c2d6cf73a3640a5a763e946582..f98ac7735f1dcb304bfe009078c53777c12a74e9 100644 (file)
@@ -970,6 +970,11 @@ int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs);
 
 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);
+#endif /* OPENSSL_NO_EC */
+
 #ifndef OPENSSL_NO_TLSEXT
 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); 
index b5db2090ab476e7f9ac575dd2a7a324600d84daa..7e0e786a42c52ed4a10ff7c248baf5fa61192ced 100644 (file)
@@ -206,6 +206,8 @@ SSL_SESSION *SSL_SESSION_new(void)
 #ifndef OPENSSL_NO_EC
        ss->tlsext_ecpointformatlist_length = 0;
        ss->tlsext_ecpointformatlist = NULL;
+       ss->tlsext_ellipticcurvelist_length = 0;
+       ss->tlsext_ellipticcurvelist = NULL;
 #endif
 #endif
        CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
@@ -369,6 +371,18 @@ int ssl_get_new_session(SSL *s, int session)
                        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
                }
@@ -665,6 +679,8 @@ void SSL_SESSION_free(SSL_SESSION *ss)
 #ifndef OPENSSL_NO_EC
        ss->tlsext_ecpointformatlist_length = 0;
        if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
+       ss->tlsext_ellipticcurvelist_length = 0;
+       if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
 #endif /* OPENSSL_NO_EC */
 #endif
 #ifndef OPENSSL_NO_PSK
index ffb93b7b6bb96be19f2564eafcefd5e9512b8ab5..ec5f33235cd7b9799c8b22c9a633de655e5751ea 100644 (file)
@@ -201,6 +201,26 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
                ret+=s->tlsext_ecpointformatlist_length;
                }
+       if (s->tlsext_ellipticcurvelist != NULL)
+               {
+               /* Add TLS extension EllipticCurves to the ClientHello message */
+               long lenmax; 
+
+               if ((lenmax = limit - p - 5) < 0) return NULL; 
+               if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
+               if (s->tlsext_ellipticcurvelist_length > 255)
+                       {
+                       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);
+               *(ret++) = (unsigned char) ((s->tlsext_ellipticcurvelist_length >> 8) & 0xFF);
+               *(ret++) = (unsigned char) (s->tlsext_ellipticcurvelist_length & 0xFF);
+               memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
+               ret+=s->tlsext_ellipticcurvelist_length;
+               }
 #endif /* OPENSSL_NO_EC */
 
        if ((extdatalen = ret-p-2)== 0) 
@@ -245,6 +265,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
                ret+=s->tlsext_ecpointformatlist_length;
                }
+       /* Currently the server should not respond with a SupportedCurves extension */
 #endif /* OPENSSL_NO_EC */
        
        if ((extdatalen = ret-p-2)== 0) 
@@ -382,6 +403,34 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
                                fprintf(stderr,"%i ",*(sdata++));
                        fprintf(stderr,"\n");
+#endif
+                       }
+               else if (type == TLSEXT_TYPE_elliptic_curves)
+                       {
+                       unsigned char *sdata = data;
+                       int ellipticcurvelist_length = (*(sdata++) << 8);
+                       ellipticcurvelist_length += (*(sdata++));
+
+                       if (ellipticcurvelist_length != size - 2)
+                               {
+                               *al = TLS1_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ellipticcurvelist_length = 0;
+                       if (s->session->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->session->tlsext_ellipticcurvelist);
+                       if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
+                       memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
+#if 0
+                       fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
+                       sdata = s->session->tlsext_ellipticcurvelist;
+                       for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+                               fprintf(stderr,"%i ",*(sdata++));
+                       fprintf(stderr,"\n");
 #endif
                        }
 #endif /* OPENSSL_NO_EC */
@@ -400,9 +449,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned char *data = *p;
 
        int tlsext_servername = 0;
-#ifndef OPENSSL_NO_EC
-       int tlsext_ecpointformats = 0;
-#endif /* OPENSSL_NO_EC */
 
        if (data >= (d+n-2))
                return 1;
@@ -486,31 +532,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        }
                }
 
-#ifndef OPENSSL_NO_EC
-       if (!s->hit && tlsext_ecpointformats == 1)
-               {
-               if (s->tlsext_ecpointformatlist)
-                       {
-                       if (s->session->tlsext_ecpointformatlist == NULL)
-                               {
-                               s->session->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
-                               if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
-                               if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
-                                       {
-                                       *al = TLS1_AD_INTERNAL_ERROR;
-                                       return 0;
-                                       }
-                               memcpy(s->session->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
-                               }
-                       else 
-                               {
-                               *al = SSL_AD_DECODE_ERROR;
-                               return 0;
-                               }
-                       }
-               }
-#endif /* OPENSSL_NO_EC */
-
        *p = data;
        return 1;
 }
@@ -518,11 +539,12 @@ 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 we 
-        * support.
+       /* 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;
        int algs;
        STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
        for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
@@ -548,6 +570,19 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
                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);
+               if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(50)) == NULL)
+                       {
+                       SSLerr(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+                       return -1;
+                       }
+               s->tlsext_ellipticcurvelist_length = 50;
+               for (i = 1, j = s->tlsext_ellipticcurvelist; i <= 25; i++)
+                       {
+                       *(j++) = 0x00;
+                       *(j++) = i;
+                       }
                }
 #endif /* OPENSSL_NO_EC */
        return 1;
@@ -557,7 +592,8 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
        {
 #ifndef OPENSSL_NO_EC
        /* If we are server and using an ECC cipher suite, send the point formats we support 
-        * if the client sent us an ECPointsFormat extension.
+        * if the client sent us an ECPointsFormat extension.  Note that the server is not
+        * supposed to send an EllipticCurves extension.
         */
        int algs = s->s3->tmp.new_cipher->algorithms;
        int using_ecc = (algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA);
@@ -586,10 +622,11 @@ int ssl_check_clienthello_tlsext(SSL *s)
        int al = SSL_AD_UNRECOGNIZED_NAME;
 
 #ifndef OPENSSL_NO_EC
-       /* If we are server and using an elliptic curve cyrptography cipher suite, then we don't
-        * need to check EC point formats since all clients must support uncompressed and it's the
-        * only thing we support; we just need to copy the data in.  We probably ought to check it
-        * for validity, but we never use it.
+       /* The handling of the ECPointFormats extension is done elsewhere, namely in 
+        * ssl3_choose_cipher in s3_lib.c.
+        */
+       /* The handling of the EllipticCurves extension is done elsewhere, namely in 
+        * ssl3_choose_cipher in s3_lib.c.
         */
 #endif
 
@@ -675,3 +712,102 @@ int ssl_check_serverhello_tlsext(SSL *s)
        }
 }
 #endif
+
+#ifndef OPENSSL_NO_EC
+int tls1_ec_curve_id2nid(int curve_id)
+{
+       /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+       static int nid_list[26] =
+       {
+               0,
+               NID_sect163k1, /* sect163k1 (1) */
+               NID_sect163r1, /* sect163r1 (2) */
+               NID_sect163r2, /* sect163r2 (3) */
+               NID_sect193r1, /* sect193r1 (4) */ 
+               NID_sect193r2, /* sect193r2 (5) */ 
+               NID_sect233k1, /* sect233k1 (6) */
+               NID_sect233r1, /* sect233r1 (7) */ 
+               NID_sect239k1, /* sect239k1 (8) */ 
+               NID_sect283k1, /* sect283k1 (9) */
+               NID_sect283r1, /* sect283r1 (10) */ 
+               NID_sect409k1, /* sect409k1 (11) */ 
+               NID_sect409r1, /* sect409r1 (12) */
+               NID_sect571k1, /* sect571k1 (13) */ 
+               NID_sect571r1, /* sect571r1 (14) */ 
+               NID_secp160k1, /* secp160k1 (15) */
+               NID_secp160r1, /* secp160r1 (16) */ 
+               NID_secp160r2, /* secp160r2 (17) */ 
+               NID_secp192k1, /* secp192k1 (18) */
+               NID_X9_62_prime192v1, /* secp192r1 (19) */ 
+               NID_secp224k1, /* secp224k1 (20) */ 
+               NID_secp224r1, /* secp224r1 (21) */
+               NID_secp256k1, /* secp256k1 (22) */ 
+               NID_X9_62_prime256v1, /* secp256r1 (23) */ 
+               NID_secp384r1, /* secp384r1 (24) */
+               NID_secp521r1  /* secp521r1 (25) */     
+       };
+       
+       if ((curve_id < 1) || (curve_id > 25)) return 0;
+
+       return nid_list[curve_id];
+}
+
+int tls1_ec_nid2curve_id(int nid)
+{
+       /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+       switch (nid) {
+       case NID_sect163k1: /* sect163k1 (1) */
+               return 1;
+       case NID_sect163r1: /* sect163r1 (2) */
+               return 2;
+       case NID_sect163r2: /* sect163r2 (3) */
+               return 3;
+       case NID_sect193r1: /* sect193r1 (4) */ 
+               return 4;
+       case NID_sect193r2: /* sect193r2 (5) */ 
+               return 5;
+       case NID_sect233k1: /* sect233k1 (6) */
+               return 6;
+       case NID_sect233r1: /* sect233r1 (7) */ 
+               return 7;
+       case NID_sect239k1: /* sect239k1 (8) */ 
+               return 8;
+       case NID_sect283k1: /* sect283k1 (9) */
+               return 9;
+       case NID_sect283r1: /* sect283r1 (10) */ 
+               return 10;
+       case NID_sect409k1: /* sect409k1 (11) */ 
+               return 11;
+       case NID_sect409r1: /* sect409r1 (12) */
+               return 12;
+       case NID_sect571k1: /* sect571k1 (13) */ 
+               return 13;
+       case NID_sect571r1: /* sect571r1 (14) */ 
+               return 14;
+       case NID_secp160k1: /* secp160k1 (15) */
+               return 15;
+       case NID_secp160r1: /* secp160r1 (16) */ 
+               return 16;
+       case NID_secp160r2: /* secp160r2 (17) */ 
+               return 17;
+       case NID_secp192k1: /* secp192k1 (18) */
+               return 18;
+       case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+               return 19;
+       case NID_secp224k1: /* secp224k1 (20) */ 
+               return 20;
+       case NID_secp224r1: /* secp224r1 (21) */
+               return 21;
+       case NID_secp256k1: /* secp256k1 (22) */ 
+               return 22;
+       case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+               return 23;
+       case NID_secp384r1: /* secp384r1 (24) */
+               return 24;
+       case NID_secp521r1:  /* secp521r1 (25) */       
+               return 25;
+       default:
+               return 0;
+       }
+}
+#endif /* OPENSSL_NO_EC */