X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=2dea51852ed1c463acfc6f60c7e71ac2d3cab44d;hp=bf96ae25c31583d1792390646962e67809893e2d;hb=bd34823e554706e822ae8990afa9454d94e4ce68;hpb=5a32dd8930212e2d93c023229083034d8282a596 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index bf96ae25c3..2dea51852e 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -113,6 +113,9 @@ #include #include #include +#ifdef OPENSSL_NO_EC2M +#include +#endif #include #include #include "ssl_locl.h" @@ -260,31 +263,43 @@ static const unsigned char ecformats_default[] = static const unsigned char eccurves_default[] = { +#ifndef OPENSSL_NO_EC2M 0,14, /* sect571r1 (14) */ 0,13, /* sect571k1 (13) */ +#endif 0,25, /* secp521r1 (25) */ 0,28, /* brainpool512r1 (28) */ +#ifndef OPENSSL_NO_EC2M 0,11, /* sect409k1 (11) */ 0,12, /* sect409r1 (12) */ +#endif 0,27, /* brainpoolP384r1 (27) */ 0,24, /* secp384r1 (24) */ +#ifndef OPENSSL_NO_EC2M 0,9, /* sect283k1 (9) */ 0,10, /* sect283r1 (10) */ +#endif 0,26, /* brainpoolP256r1 (26) */ 0,22, /* secp256k1 (22) */ 0,23, /* secp256r1 (23) */ +#ifndef OPENSSL_NO_EC2M 0,8, /* sect239k1 (8) */ 0,6, /* sect233k1 (6) */ 0,7, /* sect233r1 (7) */ +#endif 0,20, /* secp224k1 (20) */ 0,21, /* secp224r1 (21) */ +#ifndef OPENSSL_NO_EC2M 0,4, /* sect193r1 (4) */ 0,5, /* sect193r2 (5) */ +#endif 0,18, /* secp192k1 (18) */ 0,19, /* secp192r1 (19) */ +#ifndef OPENSSL_NO_EC2M 0,1, /* sect163k1 (1) */ 0,2, /* sect163r1 (2) */ 0,3, /* sect163r2 (3) */ +#endif 0,15, /* secp160k1 (15) */ 0,16, /* secp160r1 (16) */ 0,17, /* secp160r2 (17) */ @@ -296,9 +311,53 @@ static const unsigned char suiteb_curves[] = 0, TLSEXT_curve_P_384 }; +#ifdef OPENSSL_FIPS +/* Brainpool not allowed in FIPS mode */ +static const unsigned char fips_curves_default[] = + { +#ifndef OPENSSL_NO_EC2M + 0,14, /* sect571r1 (14) */ + 0,13, /* sect571k1 (13) */ +#endif + 0,25, /* secp521r1 (25) */ +#ifndef OPENSSL_NO_EC2M + 0,11, /* sect409k1 (11) */ + 0,12, /* sect409r1 (12) */ +#endif + 0,24, /* secp384r1 (24) */ +#ifndef OPENSSL_NO_EC2M + 0,9, /* sect283k1 (9) */ + 0,10, /* sect283r1 (10) */ +#endif + 0,22, /* secp256k1 (22) */ + 0,23, /* secp256r1 (23) */ +#ifndef OPENSSL_NO_EC2M + 0,8, /* sect239k1 (8) */ + 0,6, /* sect233k1 (6) */ + 0,7, /* sect233r1 (7) */ +#endif + 0,20, /* secp224k1 (20) */ + 0,21, /* secp224r1 (21) */ +#ifndef OPENSSL_NO_EC2M + 0,4, /* sect193r1 (4) */ + 0,5, /* sect193r2 (5) */ +#endif + 0,18, /* secp192k1 (18) */ + 0,19, /* secp192r1 (19) */ +#ifndef OPENSSL_NO_EC2M + 0,1, /* sect163k1 (1) */ + 0,2, /* sect163r1 (2) */ + 0,3, /* sect163r2 (3) */ +#endif + 0,15, /* secp160k1 (15) */ + 0,16, /* secp160r1 (16) */ + 0,17, /* secp160r2 (17) */ + }; +#endif + int tls1_ec_curve_id2nid(int curve_id) { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + /* ECC curves from RFC 4492 and RFC 7027 */ if ((curve_id < 1) || ((unsigned int)curve_id > sizeof(nid_list)/sizeof(nid_list[0]))) return 0; @@ -307,7 +366,7 @@ int tls1_ec_curve_id2nid(int curve_id) int tls1_ec_nid2curve_id(int nid) { - /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + /* ECC curves from RFC 4492 and RFC 7027 */ switch (nid) { case NID_sect163k1: /* sect163k1 (1) */ @@ -370,51 +429,85 @@ int tls1_ec_nid2curve_id(int nid) return 0; } } -/* Get curves list, if "sess" is set return client curves otherwise - * preferred list +/* + * Get curves list, if "sess" is set return client curves otherwise + * preferred list. + * Sets |num_curves| to the number of curves in the list, i.e., + * the length of |pcurves| is 2 * num_curves. + * Returns 1 on success and 0 if the client curves list has invalid format. + * The latter indicates an internal error: we should not be accepting such + * lists in the first place. + * TODO(emilia): we should really be storing the curves list in explicitly + * parsed form instead. (However, this would affect binary compatibility + * so cannot happen in the 1.0.x series.) */ -static void tls1_get_curvelist(SSL *s, int sess, +static int tls1_get_curvelist(SSL *s, int sess, const unsigned char **pcurves, - size_t *pcurveslen) + size_t *num_curves) { + size_t pcurveslen = 0; if (sess) { *pcurves = s->session->tlsext_ellipticcurvelist; - *pcurveslen = s->session->tlsext_ellipticcurvelist_length; - return; + pcurveslen = s->session->tlsext_ellipticcurvelist_length; } - /* For Suite B mode only include P-256, P-384 */ - switch (tls1_suiteb(s)) + else { - case SSL_CERT_FLAG_SUITEB_128_LOS: - *pcurves = suiteb_curves; - *pcurveslen = sizeof(suiteb_curves); - break; + /* For Suite B mode only include P-256, P-384 */ + switch (tls1_suiteb(s)) + { + case SSL_CERT_FLAG_SUITEB_128_LOS: + *pcurves = suiteb_curves; + pcurveslen = sizeof(suiteb_curves); + break; - case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY: - *pcurves = suiteb_curves; - *pcurveslen = 2; - break; + case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY: + *pcurves = suiteb_curves; + pcurveslen = 2; + break; - case SSL_CERT_FLAG_SUITEB_192_LOS: - *pcurves = suiteb_curves + 2; - *pcurveslen = 2; - break; - default: - *pcurves = s->tlsext_ellipticcurvelist; - *pcurveslen = s->tlsext_ellipticcurvelist_length; + case SSL_CERT_FLAG_SUITEB_192_LOS: + *pcurves = suiteb_curves + 2; + pcurveslen = 2; + break; + default: + *pcurves = s->tlsext_ellipticcurvelist; + pcurveslen = s->tlsext_ellipticcurvelist_length; + } + if (!*pcurves) + { +#ifdef OPENSSL_FIPS + if (FIPS_mode()) + { + *pcurves = fips_curves_default; + *pcurveslen = sizeof(fips_curves_default); + } + else +#endif + { + *pcurves = eccurves_default; + pcurveslen = sizeof(eccurves_default); + } + } } - if (!*pcurves) + /* We do not allow odd length arrays to enter the system. */ + if (pcurveslen & 1) { - *pcurves = eccurves_default; - *pcurveslen = sizeof(eccurves_default); + SSLerr(SSL_F_TLS1_GET_CURVELIST, ERR_R_INTERNAL_ERROR); + *num_curves = 0; + return 0; + } + else + { + *num_curves = pcurveslen / 2; + return 1; } } /* Check a curve is one of our preferences */ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len) { const unsigned char *curves; - size_t curveslen, i; + size_t num_curves, i; unsigned int suiteb_flags = tls1_suiteb(s); if (len != 3 || p[0] != NAMED_CURVE_TYPE) return 0; @@ -437,8 +530,9 @@ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len) else /* Should never happen */ return 0; } - tls1_get_curvelist(s, 0, &curves, &curveslen); - for (i = 0; i < curveslen; i += 2, curves += 2) + if (!tls1_get_curvelist(s, 0, &curves, &num_curves)) + return 0; + for (i = 0; i < num_curves; i++, curves += 2) { if (p[1] == curves[0] && p[2] == curves[1]) return 1; @@ -446,15 +540,16 @@ int tls1_check_curve(SSL *s, const unsigned char *p, size_t len) return 0; } -/* Return nth shared curve. If nmatch == -1 return number of - * matches. For nmatch == -2 return the NID of the curve to use for - * an EC tmp key. +/* + * Return |nmatch|th shared curve or NID_undef if there is no match. + * For nmatch == -1, return number of matches + * For nmatch == -2, return the NID of the curve to use for + * an EC tmp key, or NID_undef if there is no match. */ - int tls1_shared_curve(SSL *s, int nmatch) { const unsigned char *pref, *supp; - size_t preflen, supplen, i, j; + size_t num_pref, num_supp, i, j; int k; /* Can't do anything on client side */ if (s->server == 0) @@ -478,17 +573,22 @@ int tls1_shared_curve(SSL *s, int nmatch) /* If not Suite B just return first preference shared curve */ nmatch = 0; } - tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), - &supp, &supplen); - tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), - &pref, &preflen); - preflen /= 2; - supplen /= 2; + /* + * Avoid truncation. tls1_get_curvelist takes an int + * but s->options is a long... + */ + if (!tls1_get_curvelist(s, (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0, + &supp, &num_supp)) + /* In practice, NID_undef == 0 but let's be precise. */ + return nmatch == -1 ? 0 : NID_undef; + if(!tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), + &pref, &num_pref)) + return nmatch == -1 ? 0 : NID_undef; k = 0; - for (i = 0; i < preflen; i++, pref+=2) + for (i = 0; i < num_pref; i++, pref+=2) { const unsigned char *tsupp = supp; - for (j = 0; j < supplen; j++, tsupp+=2) + for (j = 0; j < num_supp; j++, tsupp+=2) { if (pref[0] == tsupp[0] && pref[1] == tsupp[1]) { @@ -503,7 +603,8 @@ int tls1_shared_curve(SSL *s, int nmatch) } if (nmatch == -1) return k; - return 0; + /* Out of range (nmatch > k). */ + return NID_undef; } int tls1_set_curves(unsigned char **pext, size_t *pextlen, @@ -515,6 +616,10 @@ int tls1_set_curves(unsigned char **pext, size_t *pextlen, * while curve ids < 32 */ unsigned long dup_list = 0; +#ifdef OPENSSL_NO_EC2M + EC_GROUP *curve; +#endif + clist = OPENSSL_malloc(ncurves * 2); if (!clist) return 0; @@ -523,6 +628,27 @@ int tls1_set_curves(unsigned char **pext, size_t *pextlen, unsigned long idmask; int id; id = tls1_ec_nid2curve_id(curves[i]); +#ifdef OPENSSL_FIPS + /* NB: 25 is last curve ID supported by FIPS module */ + if (FIPS_mode() && id > 25) + { + OPENSSL_free(clist); + return 0; + } +#endif +#ifdef OPENSSL_NO_EC2M + curve = EC_GROUP_new_by_curve_name(curves[i]); + if(!curve || + EC_METHOD_get_field_type(EC_GROUP_method_of(curve)) + == NID_X9_62_characteristic_two_field) + { + if(curve) EC_GROUP_free(curve); + OPENSSL_free(clist); + return 0; + } + else + EC_GROUP_free(curve); +#endif idmask = 1L << id; if (!id || (dup_list & idmask)) { @@ -641,22 +767,22 @@ static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id, static int tls1_check_ec_key(SSL *s, unsigned char *curve_id, unsigned char *comp_id) { - const unsigned char *p; - size_t plen, i; + const unsigned char *pformats, *pcurves; + size_t num_formats, num_curves, i; int j; /* If point formats extension present check it, otherwise everything * is supported (see RFC4492). */ if (comp_id && s->session->tlsext_ecpointformatlist) { - p = s->session->tlsext_ecpointformatlist; - plen = s->session->tlsext_ecpointformatlist_length; - for (i = 0; i < plen; i++, p++) + pformats = s->session->tlsext_ecpointformatlist; + num_formats = s->session->tlsext_ecpointformatlist_length; + for (i = 0; i < num_formats; i++, pformats++) { - if (*comp_id == *p) + if (*comp_id == *pformats) break; } - if (i == plen) + if (i == num_formats) return 0; } if (!curve_id) @@ -664,13 +790,15 @@ static int tls1_check_ec_key(SSL *s, /* Check curve is consistent with client and server preferences */ for (j = 0; j <= 1; j++) { - tls1_get_curvelist(s, j, &p, &plen); - for (i = 0; i < plen; i+=2, p+=2) + if (!tls1_get_curvelist(s, j, &pcurves, &num_curves)) + return 0; + for (i = 0; i < num_curves; i++, pcurves += 2) { - if (p[0] == curve_id[0] && p[1] == curve_id[1]) + if (pcurves[0] == curve_id[0] && + pcurves[1] == curve_id[1]) break; } - if (i == plen) + if (i == num_curves) return 0; /* For clients can only check sent curve list */ if (!s->server) @@ -680,23 +808,23 @@ static int tls1_check_ec_key(SSL *s, } static void tls1_get_formatlist(SSL *s, const unsigned char **pformats, - size_t *pformatslen) + size_t *num_formats) { /* If we have a custom point format list use it otherwise * use default */ if (s->tlsext_ecpointformatlist) { *pformats = s->tlsext_ecpointformatlist; - *pformatslen = s->tlsext_ecpointformatlist_length; + *num_formats = s->tlsext_ecpointformatlist_length; } else { *pformats = ecformats_default; /* For Suite B we don't support char2 fields */ if (tls1_suiteb(s)) - *pformatslen = sizeof(ecformats_default) - 1; + *num_formats = sizeof(ecformats_default) - 1; else - *pformatslen = sizeof(ecformats_default); + *num_formats = sizeof(ecformats_default); } } @@ -1086,26 +1214,21 @@ void ssl_set_client_disabled(SSL *s) c->mask_k |= SSL_kPSK; } #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (!(s->srp_ctx.srp_Mask & SSL_kSRP)) + { + c->mask_a |= SSL_aSRP; + c->mask_k |= SSL_kSRP; + } +#endif c->valid = 1; } -/* byte_compare is a compare function for qsort(3) that compares bytes. */ -static int byte_compare(const void *in_a, const void *in_b) - { - unsigned char a = *((const unsigned char*) in_a); - unsigned char b = *((const unsigned char*) in_b); - - if (a > b) - return 1; - else if (a < b) - return -1; - return 0; -} - -unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al) +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, int *al) { int extdatalen=0; - unsigned char *ret = p; + unsigned char *orig = buf; + unsigned char *ret = buf; #ifndef OPENSSL_NO_EC /* See if we support any ECC ciphersuites */ int using_ecc = 0; @@ -1134,7 +1257,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha /* don't add extensions for SSLv3 unless doing secure renegotiation */ if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) - return p; + return orig; ret+=2; @@ -1183,7 +1306,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha return NULL; } - if((limit - p - 4 - el) < 0) return NULL; + if((limit - ret - 4 - el) < 0) return NULL; s2n(TLSEXT_TYPE_renegotiate,ret); s2n(el,ret); @@ -1230,48 +1353,44 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha { /* Add TLS extension ECPointFormats to the ClientHello message */ long lenmax; - const unsigned char *plist; - size_t plistlen; + const unsigned char *pcurves, *pformats; + size_t num_curves, num_formats, curves_list_len; - tls1_get_formatlist(s, &plist, &plistlen); + tls1_get_formatlist(s, &pformats, &num_formats); if ((lenmax = limit - ret - 5) < 0) return NULL; - if (plistlen > (size_t)lenmax) return NULL; - if (plistlen > 255) + if (num_formats > (size_t)lenmax) return NULL; + if (num_formats > 255) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); return NULL; } s2n(TLSEXT_TYPE_ec_point_formats,ret); - s2n(plistlen + 1,ret); - *(ret++) = (unsigned char)plistlen ; - memcpy(ret, plist, plistlen); - ret+=plistlen; + /* The point format list has 1-byte length. */ + s2n(num_formats + 1,ret); + *(ret++) = (unsigned char)num_formats ; + memcpy(ret, pformats, num_formats); + ret+=num_formats; /* Add TLS extension EllipticCurves to the ClientHello message */ - plist = s->tlsext_ellipticcurvelist; - tls1_get_curvelist(s, 0, &plist, &plistlen); + pcurves = s->tlsext_ellipticcurvelist; + if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) + return NULL; if ((lenmax = limit - ret - 6) < 0) return NULL; - if (plistlen > (size_t)lenmax) return NULL; - if (plistlen > 65532) + if (num_curves > (size_t)lenmax / 2) return NULL; + if (num_curves > 65532 / 2) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); return NULL; } - + curves_list_len = 2*num_curves; s2n(TLSEXT_TYPE_elliptic_curves,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(plistlen, ret); - memcpy(ret, plist, plistlen); - ret+=plistlen; + s2n(curves_list_len + 2, ret); + s2n(curves_list_len, ret); + memcpy(ret, pcurves, curves_list_len); + ret+=curves_list_len; } #endif /* OPENSSL_NO_EC */ @@ -1393,6 +1512,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha #ifndef OPENSSL_NO_HEARTBEATS /* Add Heartbeat extension */ + if ((limit - ret - 4 - 1) < 0) + return NULL; s2n(TLSEXT_TYPE_heartbeat,ret); s2n(1,ret); /* Set mode: @@ -1429,13 +1550,13 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += s->alpn_client_proto_list_len; } - if(SSL_get_srtp_profiles(s)) + if(SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) { int el; ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); - if((limit - p - 4 - el) < 0) return NULL; + if((limit - ret - 4 - el) < 0) return NULL; s2n(TLSEXT_TYPE_use_srtp,ret); s2n(el,ret); @@ -1447,84 +1568,53 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } ret += el; } - + custom_ext_init(&s->cert->cli_ext); /* Add custom TLS Extensions to ClientHello */ - if (s->ctx->custom_cli_ext_records_count) - { - size_t i; - custom_cli_ext_record* record; - - for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++) - { - const unsigned char* out = NULL; - unsigned short outlen = 0; - - record = &s->ctx->custom_cli_ext_records[i]; - /* NULL callback sends empty extension */ - /* -1 from callback omits extension */ - if (record->fn1) - { - int cb_retval = 0; - cb_retval = record->fn1(s, record->ext_type, - &out, &outlen, al, - record->arg); - if (cb_retval == 0) - return NULL; /* error */ - if (cb_retval == -1) - continue; /* skip this extension */ - } - if (limit < ret + 4 + outlen) - return NULL; - s2n(record->ext_type, ret); - s2n(outlen, ret); - memcpy(ret, out, outlen); - ret += outlen; - } - } + if (!custom_ext_add(s, 0, &ret, limit, al)) + return NULL; -#ifdef TLSEXT_TYPE_padding /* Add padding to workaround bugs in F5 terminators. - * See https://tools.ietf.org/html/draft-agl-tls-padding-02 + * See https://tools.ietf.org/html/draft-agl-tls-padding-03 * * NB: because this code works out the length of all existing * extensions it MUST always appear last. */ - { - int hlen = ret - (unsigned char *)s->init_buf->data; - /* The code in s23_clnt.c to build ClientHello messages includes the - * 5-byte record header in the buffer, while the code in s3_clnt.c does - * not. */ - if (s->state == SSL23_ST_CW_CLNT_HELLO_A) - hlen -= 5; - if (hlen > 0xff && hlen < 0x200) - { - hlen = 0x200 - hlen; - if (hlen >= 4) - hlen -= 4; - else - hlen = 0; + if (s->options & SSL_OP_TLSEXT_PADDING) + { + int hlen = ret - (unsigned char *)s->init_buf->data; + /* The code in s23_clnt.c to build ClientHello messages + * includes the 5-byte record header in the buffer, while + * the code in s3_clnt.c does not. + */ + if (s->state == SSL23_ST_CW_CLNT_HELLO_A) + hlen -= 5; + if (hlen > 0xff && hlen < 0x200) + { + hlen = 0x200 - hlen; + if (hlen >= 4) + hlen -= 4; + else + hlen = 0; - s2n(TLSEXT_TYPE_padding, ret); - s2n(hlen, ret); - memset(ret, 0, hlen); - ret += hlen; + s2n(TLSEXT_TYPE_padding, ret); + s2n(hlen, ret); + memset(ret, 0, hlen); + ret += hlen; + } } - } -#endif - if ((extdatalen = ret-p-2) == 0) - return p; + if ((extdatalen = ret-orig-2)== 0) + return orig; - s2n(extdatalen,p); + s2n(extdatalen, orig); return ret; } -unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al) +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, int *al) { int extdatalen=0; - unsigned char *ret = p; - size_t i; - custom_srv_ext_record *record; + unsigned char *orig = buf; + unsigned char *ret = buf; #ifndef OPENSSL_NO_NEXTPROTONEG int next_proto_neg_seen; #endif @@ -1536,7 +1626,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha #endif /* don't add extensions for SSLv3, unless doing secure renegotiation */ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) - return p; + return orig; ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ @@ -1559,7 +1649,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha return NULL; } - if((limit - p - 4 - el) < 0) return NULL; + if((limit - ret - 4 - el) < 0) return NULL; s2n(TLSEXT_TYPE_renegotiate,ret); s2n(el,ret); @@ -1634,13 +1724,13 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif - if(s->srtp_profile) + if(SSL_IS_DTLS(s) && s->srtp_profile) { int el; ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); - if((limit - p - 4 - el) < 0) return NULL; + if((limit - ret - 4 - el) < 0) return NULL; s2n(TLSEXT_TYPE_use_srtp,ret); s2n(el,ret); @@ -1672,6 +1762,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Add Heartbeat extension if we've received one */ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) { + if ((limit - ret - 4 - 1) < 0) + return NULL; s2n(TLSEXT_TYPE_heartbeat,ret); s2n(1,ret); /* Set mode: @@ -1707,32 +1799,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } } #endif - - for (i = 0; i < s->ctx->custom_srv_ext_records_count; i++) - { - const unsigned char *out = NULL; - unsigned short outlen = 0; - int cb_retval = 0; - - record = &s->ctx->custom_srv_ext_records[i]; - - /* NULL callback or -1 omits extension */ - if (!record->fn2) - continue; - cb_retval = record->fn2(s, record->ext_type, - &out, &outlen, al, - record->arg); - if (cb_retval == 0) - return NULL; /* error */ - if (cb_retval == -1) - continue; /* skip this extension */ - if (limit < ret + 4 + outlen) - return NULL; - s2n(record->ext_type, ret); - s2n(outlen, ret); - memcpy(ret, out, outlen); - ret += outlen; - } + if (!custom_ext_add(s, 1, &ret, limit, al)) + return NULL; if (s->s3->alpn_selected) { @@ -1749,10 +1817,10 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += len; } - if ((extdatalen = ret-p-2)== 0) - return p; + if ((extdatalen = ret-orig-2)== 0) + return orig; - s2n(extdatalen,p); + s2n(extdatalen, orig); return ret; } @@ -1916,7 +1984,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char unsigned short len; unsigned char *data = *p; int renegotiate_seen = 0; - size_t i; s->servername_done = 0; s->tlsext_status_type = -1; @@ -1924,14 +1991,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char s->s3->next_proto_neg_seen = 0; #endif - /* Clear observed custom extensions */ - s->s3->serverinfo_client_tlsext_custom_types_count = 0; - if (s->s3->serverinfo_client_tlsext_custom_types != NULL) - { - OPENSSL_free(s->s3->serverinfo_client_tlsext_custom_types); - s->s3->serverinfo_client_tlsext_custom_types = NULL; - } - if (s->s3->alpn_selected) { OPENSSL_free(s->s3->alpn_selected); @@ -1954,18 +2013,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char OPENSSL_free(s->cert->peer_sigalgs); s->cert->peer_sigalgs = NULL; } - /* Clear any shared sigtnature algorithms */ - if (s->cert->shared_sigalgs) - { - OPENSSL_free(s->cert->shared_sigalgs); - s->cert->shared_sigalgs = NULL; - } - /* Clear certificate digests and validity flags */ - for (i = 0; i < SSL_PKEY_NUM; i++) - { - s->cert->pkeys[i].digest = NULL; - s->cert->pkeys[i].valid_flags = 0; - } if (data >= (d+n-2)) goto ri_check; @@ -2162,7 +2209,9 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char ellipticcurvelist_length += (*(sdata++)); if (ellipticcurvelist_length != size - 2 || - ellipticcurvelist_length < 1) + ellipticcurvelist_length < 1 || + /* Each NamedCurve is 2 bytes. */ + ellipticcurvelist_length & 1) { *al = TLS1_AD_DECODE_ERROR; return 0; @@ -2252,21 +2301,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *al = SSL_AD_DECODE_ERROR; return 0; } - if (!tls1_process_sigalgs(s, data, dsize)) + if (!tls1_save_sigalgs(s, data, dsize)) { *al = SSL_AD_DECODE_ERROR; return 0; } - /* If sigalgs received and no shared algorithms fatal - * error. - */ - if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) - { - SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, - SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } } else if (type == TLSEXT_TYPE_status_request) { @@ -2433,32 +2472,13 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char } /* session ticket processed earlier */ - else if (type == TLSEXT_TYPE_use_srtp) + else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s) + && type == TLSEXT_TYPE_use_srtp) { if(ssl_parse_clienthello_use_srtp_ext(s, data, size, al)) return 0; } - /* If this ClientHello extension was unhandled and this is - * a nonresumed connection, check whether the extension is a - * custom TLS Extension (has a custom_srv_ext_record), and if - * so call the callback and record the extension number so that - * an appropriate ServerHello may be later returned. - */ - else if (!s->hit && s->ctx->custom_srv_ext_records_count) - { - custom_srv_ext_record *record; - - for (i=0; i < s->ctx->custom_srv_ext_records_count; i++) - { - record = &s->ctx->custom_srv_ext_records[i]; - if (type == record->ext_type) - { - if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg)) - return 0; - } - } - } data+=size; } @@ -2477,9 +2497,41 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); return 0; } - /* If no signature algorithms extension set default values */ - if (!s->cert->peer_sigalgs) - ssl_cert_set_default_md(s->cert); + + return 1; + } + +/* + * Parse any custom extensions found. "data" is the start of the extension data + * and "limit" is the end of the record. TODO: add strict syntax checking. + */ + +static int ssl_scan_clienthello_custom_tlsext(SSL *s, const unsigned char *data, const unsigned char *limit, int *al) + { + unsigned short type, size, len; + /* If resumed session or no custom extensions nothing to do */ + if (s->hit || s->cert->srv_ext.meths_count == 0) + return 1; + + if (data >= limit - 2) + return 1; + n2s(data, len); + + if (data > limit - len) + return 1; + + while (data <= limit - 4) + { + n2s(data, type); + n2s(data, size); + + if (data+size > limit) + return 1; + if (custom_ext_parse(s, 1 /* server */, type, data, size, al) <= 0) + return 0; + + data+=size; + } return 1; } @@ -2487,6 +2539,13 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n) { int al = -1; + unsigned char *ptmp = *p; + /* + * Internally supported extensions are parsed first so SNI can be handled + * before custom extensions. An application processing SNI will typically + * switch the parent context using SSL_set_SSL_CTX and custom extensions + * need to be handled by the new SSL_CTX structure. + */ if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0) { ssl3_send_alert(s,SSL3_AL_FATAL,al); @@ -2498,6 +2557,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,SSL_R_CLIENTHELLO_TLSEXT); return 0; } + + custom_ext_init(&s->cert->srv_ext); + if (ssl_scan_clienthello_custom_tlsext(s, ptmp, d + n, &al) <= 0) + { + ssl3_send_alert(s,SSL3_AL_FATAL,al); + return 0; + } + return 1; } @@ -2533,6 +2600,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char #ifndef OPENSSL_NO_NEXTPROTONEG s->s3->next_proto_neg_seen = 0; #endif + s->tlsext_ticket_expected = 0; if (s->s3->alpn_selected) { @@ -2588,15 +2656,18 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *al = TLS1_AD_DECODE_ERROR; return 0; } - s->session->tlsext_ecpointformatlist_length = 0; - if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); - if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL) + if (!s->hit) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; + s->session->tlsext_ecpointformatlist_length = 0; + if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist); + if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length; + memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length); } - s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length; - memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length); #if 0 fprintf(stderr,"ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist "); sdata = s->session->tlsext_ecpointformatlist; @@ -2771,7 +2842,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char } } #endif - else if (type == TLSEXT_TYPE_use_srtp) + else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) { if(ssl_parse_serverhello_use_srtp_ext(s, data, size, al)) @@ -2780,22 +2851,8 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char /* If this extension type was not otherwise handled, but * matches a custom_cli_ext_record, then send it to the c * callback */ - else if (s->ctx->custom_cli_ext_records_count) - { - size_t i; - custom_cli_ext_record* record; - - for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++) - { - record = &s->ctx->custom_cli_ext_records[i]; - if (record->ext_type == type) - { - if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg)) - return 0; - break; - } - } - } + else if (custom_ext_parse(s, 0, type, data, size, al) <= 0) + return 0; data += size; } @@ -2992,6 +3049,50 @@ static int ssl_check_clienthello_tlsext_early(SSL *s) } } +int tls1_set_server_sigalgs(SSL *s) + { + int al; + size_t i; + /* Clear any shared sigtnature algorithms */ + if (s->cert->shared_sigalgs) + { + OPENSSL_free(s->cert->shared_sigalgs); + s->cert->shared_sigalgs = NULL; + } + /* Clear certificate digests and validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) + { + s->cert->pkeys[i].digest = NULL; + s->cert->pkeys[i].valid_flags = 0; + } + + /* If sigalgs received process it. */ + if (s->cert->peer_sigalgs) + { + if (!tls1_process_sigalgs(s)) + { + SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS, + ERR_R_MALLOC_FAILURE); + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + /* Fatal error is no shared signature algorithms */ + if (!s->cert->shared_sigalgs) + { + SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS, + SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); + al = SSL_AD_ILLEGAL_PARAMETER; + goto err; + } + } + else + ssl_cert_set_default_md(s->cert); + return 1; + err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; + } + int ssl_check_clienthello_tlsext_late(SSL *s) { int ret = SSL_TLSEXT_ERR_OK; @@ -3378,7 +3479,10 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) + { + EVP_CIPHER_CTX_cleanup(&ctx); return 2; + } /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); @@ -3391,7 +3495,11 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, } EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_free(sdec); return 2; + } slen += mlen; EVP_CIPHER_CTX_cleanup(&ctx); p = sdec; @@ -3619,6 +3727,11 @@ static int tls1_set_shared_sigalgs(SSL *s) TLS_SIGALGS *salgs = NULL; CERT *c = s->cert; unsigned int is_suiteb = tls1_suiteb(s); + if (c->shared_sigalgs) + { + OPENSSL_free(c->shared_sigalgs); + c->shared_sigalgs = NULL; + } /* If client use client signature algorithms if not NULL */ if (!s->server && c->client_sigalgs && !is_suiteb) { @@ -3661,13 +3774,9 @@ static int tls1_set_shared_sigalgs(SSL *s) /* Set preferred digest for each key type */ -int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) +int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize) { - int idx; - size_t i; - const EVP_MD *md; CERT *c = s->cert; - TLS_SIGALGS *sigptr; /* Extension ignored for inappropriate versions */ if (!SSL_USE_SIGALGS(s)) return 1; @@ -3675,13 +3784,25 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) if (!c) return 0; + if (c->peer_sigalgs) + OPENSSL_free(c->peer_sigalgs); c->peer_sigalgs = OPENSSL_malloc(dsize); if (!c->peer_sigalgs) return 0; c->peer_sigalgslen = dsize; memcpy(c->peer_sigalgs, data, dsize); + return 1; + } - tls1_set_shared_sigalgs(s); +int tls1_process_sigalgs(SSL *s) + { + int idx; + size_t i; + const EVP_MD *md; + CERT *c = s->cert; + TLS_SIGALGS *sigptr; + if (!tls1_set_shared_sigalgs(s)) + return 0; #ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) @@ -3807,16 +3928,20 @@ tls1_process_heartbeat(SSL *s) unsigned int payload; unsigned int padding = 16; /* Use minimum padding */ - /* Read type and payload length first */ - hbtype = *p++; - n2s(p, payload); - pl = p; - if (s->msg_callback) s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, &s->s3->rrec.data[0], s->s3->rrec.length, s, s->msg_callback_arg); + /* Read type and payload length first */ + if (1 + 2 + 16 > s->s3->rrec.length) + return 0; /* silently discard */ + hbtype = *p++; + n2s(p, payload); + if (1 + 2 + payload + 16 > s->s3->rrec.length) + return 0; /* silently discard per RFC 6520 sec. 4 */ + pl = p; + if (hbtype == TLS1_HB_REQUEST) { unsigned char *buffer, *bp; @@ -4155,13 +4280,10 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, if (check_flags) check_flags |= CERT_PKEY_SUITEB; ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags); - if (ok != X509_V_OK) - { - if (check_flags) - rv |= CERT_PKEY_SUITEB; - else - goto end; - } + if (ok == X509_V_OK) + rv |= CERT_PKEY_SUITEB; + else if (!check_flags) + goto end; } /* Check all signature algorithms are consistent with