From 6b870763ac55ce1c748e68293e8169aa61cb4eb2 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Fri, 6 Apr 2012 20:12:35 +0000 Subject: [PATCH] Initial revision of ECC extension handling. 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. (backport from HEAD) --- CHANGES | 7 + apps/s_cb.c | 23 +++- apps/s_client.c | 12 ++ apps/s_server.c | 24 ++++ ssl/s3_lib.c | 26 +++- ssl/ssl.h | 27 +++- ssl/ssl_lib.c | 30 +++++ ssl/ssl_locl.h | 9 ++ ssl/ssl_sess.c | 26 ---- ssl/t1_lib.c | 352 ++++++++++++++++++++++++++++++++++-------------- 10 files changed, 401 insertions(+), 135 deletions(-) diff --git a/CHANGES b/CHANGES index 40a93dd122..6765cdeb95 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,13 @@ Changes between 1.0.1 and 1.0.2 [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. diff --git a/apps/s_cb.c b/apps/s_cb.c index eab0a08038..141c222895 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -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; } diff --git a/apps/s_client.c b/apps/s_client.c index ced07f3a71..96cb4a61f9 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -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) @@ -1175,6 +1181,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; diff --git a/apps/s_server.c b/apps/s_server.c index 68394238f8..a6b872e855 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -270,6 +270,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 @@ -433,6 +434,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; @@ -1161,6 +1163,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; } @@ -1820,6 +1827,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); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 80123b0b49..8b80dc7fb5 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -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; } @@ -3654,6 +3668,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 :-) */ diff --git a/ssl/ssl.h b/ssl/ssl.h index 7e09362714..60b61043f6 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -973,6 +973,13 @@ struct ssl_ctx_st # endif /* SRTP profiles we are willing to do from RFC 5764 */ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; +# 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 }; @@ -1608,7 +1615,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) @@ -1668,9 +1678,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); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 0ff086bc78..dd7012b00f 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -356,6 +356,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 @@ -1972,6 +1994,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); diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index f00223d5c8..184a568567 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1104,9 +1104,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); diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index ad40fadd02..ee50885002 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -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 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b8943a11f3..7898d84cb4 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -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 { -- 2.34.1