From: Bodo Möller Date: Thu, 30 Mar 2006 02:44:56 +0000 (+0000) Subject: Implement Supported Elliptic Curves Extension. X-Git-Tag: OpenSSL_0_9_8k^2~1466 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=332737217a9b8eb07d53634ae72b0e2e9ec9b8c6 Implement Supported Elliptic Curves Extension. Submitted by: Douglas Stebila --- diff --git a/CHANGES b/CHANGES index b33ec32743..462befa49f 100644 --- 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] diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index a8f2b8f557..1b9b586f96 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -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 diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index a488692579..8e59a92905 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -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 */ diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 121cdfb6f2..bfbf951f72 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -170,10 +170,6 @@ 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 diff --git a/ssl/ssl.h b/ssl/ssl.h index 7e2a8c170f..f0ed4f105c 100644 --- 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 diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index b9148b23de..dbe8ea8eba 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -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); diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index f0527f459a..f98ac7735f 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -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); diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index b5db2090ab..7e0e786a42 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -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 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index ffb93b7b6b..ec5f33235c 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -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 */