X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=ed6518166cfacdde6bbf86ea0b3f911ef777d60a;hp=4d6789264d381d7b16774d7014f19841ef2c112c;hb=a149b2466e8adb97b1fe855d189bac58d3b654dd;hpb=2e9802b7a7b2d05554adf96a3ec06497fe066ee9 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 4d6789264d..ed6518166c 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -166,7 +166,7 @@ void tls1_free(SSL *s) void tls1_clear(SSL *s) { ssl3_clear(s); - s->version=TLS1_VERSION; + s->version = s->method->version; } #ifndef OPENSSL_NO_EC @@ -275,8 +275,9 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha int extdatalen=0; unsigned char *ret = p; - /* don't add extensions for SSLv3 */ - if (s->client_version == SSL3_VERSION) + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION + && !s->s3->send_connection_binding) return p; ret+=2; @@ -315,8 +316,58 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret+=size_str; } + /* Add RI if renegotiating */ + if (s->renegotiate) + { + int el; + + if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } + +#ifndef OPENSSL_NO_SRP +#define MIN(x,y) (((x)<(y))?(x):(y)) + /* we add SRP username the first time only if we have one! */ + if (s->srp_ctx.login != NULL) + {/* Add TLS extension SRP username to the Client Hello message */ + int login_len = MIN(strlen(s->srp_ctx.login) + 1, 255); + long lenmax; + + if ((lenmax = limit - ret - 5) < 0) return NULL; + if (login_len > lenmax) return NULL; + if (login_len > 255) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + s2n(TLSEXT_TYPE_srp,ret); + s2n(login_len+1,ret); + + (*ret++) = (unsigned char) MIN(strlen(s->srp_ctx.login), 254); + memcpy(ret, s->srp_ctx.login, MIN(strlen(s->srp_ctx.login), 254)); + ret+=login_len; + } +#endif + #ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist != NULL) + if (s->tlsext_ecpointformatlist != NULL && + s->version != DTLS1_VERSION) { /* Add TLS extension ECPointFormats to the ClientHello message */ long lenmax; @@ -335,7 +386,8 @@ 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) + if (s->tlsext_ellipticcurvelist != NULL && + s->version != DTLS1_VERSION) { /* Add TLS extension EllipticCurves to the ClientHello message */ long lenmax; @@ -365,7 +417,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { int ticklen; - if (s->session && s->session->tlsext_tick) + if (!s->new_session && s->session && s->session->tlsext_tick) ticklen = s->session->tlsext_ticklen; else if (s->session && s->tlsext_session_ticket && s->tlsext_session_ticket->data) @@ -399,7 +451,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha skip_ext: #ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->client_opaque_prf_input != NULL) + if (s->s3->client_opaque_prf_input != NULL && + s->version != DTLS1_VERSION) { size_t col = s->s3->client_opaque_prf_input_len; @@ -416,7 +469,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp && + s->version != DTLS1_VERSION) { int i; long extlen, idlen, itmp; @@ -476,8 +530,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha int extdatalen=0; unsigned char *ret = p; - /* don't add extensions for SSLv3 */ - if (s->version == SSL3_VERSION) + /* don't add extensions for SSLv3, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) return p; ret+=2; @@ -490,8 +544,34 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(TLSEXT_TYPE_server_name,ret); s2n(0,ret); } + + if(s->s3->send_connection_binding) + { + int el; + + if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } + #ifndef OPENSSL_NO_EC - if (s->tlsext_ecpointformatlist != NULL) + if (s->tlsext_ecpointformatlist != NULL && + s->version != DTLS1_VERSION) { /* Add TLS extension ECPointFormats to the ServerHello message */ long lenmax; @@ -530,7 +610,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } #ifdef TLSEXT_TYPE_opaque_prf_input - if (s->s3->server_opaque_prf_input != NULL) + if (s->s3->server_opaque_prf_input != NULL && + s->version != DTLS1_VERSION) { size_t sol = s->s3->server_opaque_prf_input_len; @@ -574,15 +655,17 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short size; unsigned short len; unsigned char *data = *p; + int renegotiate_seen = 0; + s->servername_done = 0; s->tlsext_status_type = -1; if (data >= (d+n-2)) - return 1; + goto ri_check; n2s(data,len); if (data > (d+n-len)) - return 1; + goto ri_check; while (data <= (d+n-4)) { @@ -590,7 +673,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in n2s(data,size); if (data+size > (d+n)) - return 1; + goto ri_check; #if 0 fprintf(stderr,"Received extension type %d size %d\n",type,size); #endif @@ -655,14 +738,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in switch (servname_type) { case TLSEXT_NAMETYPE_host_name: - if (s->session->tlsext_hostname == NULL) + if (!s->hit) { - if (len > TLSEXT_MAXLEN_host_name || - ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)) + if(s->session->tlsext_hostname) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (len > TLSEXT_MAXLEN_host_name) { *al = TLS1_AD_UNRECOGNIZED_NAME; return 0; } + if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } memcpy(s->session->tlsext_hostname, sdata, len); s->session->tlsext_hostname[len]='\0'; if (strlen(s->session->tlsext_hostname) != len) { @@ -675,7 +767,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } else - s->servername_done = strlen(s->session->tlsext_hostname) == len + s->servername_done = s->session->tlsext_hostname + && strlen(s->session->tlsext_hostname) == len && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0; break; @@ -693,9 +786,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } +#ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) + { + if (size > 0) + { + len = data[0]; + if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL) + return -1; + memcpy(s->srp_ctx.login, &data[1], len); + s->srp_ctx.login[len]='\0'; + } + } +#endif #ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats) + else if (type == TLSEXT_TYPE_ec_point_formats && + s->version != DTLS1_VERSION) { unsigned char *sdata = data; int ecpointformatlist_length = *(sdata++); @@ -705,15 +812,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in *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; + if(s->session->tlsext_ecpointformatlist) + { + OPENSSL_free(s->session->tlsext_ecpointformatlist); + s->session->tlsext_ecpointformatlist = NULL; + } + s->session->tlsext_ecpointformatlist_length = 0; + 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_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length); sdata = s->session->tlsext_ecpointformatlist; @@ -722,7 +836,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in fprintf(stderr,"\n"); #endif } - else if (type == TLSEXT_TYPE_elliptic_curves) + else if (type == TLSEXT_TYPE_elliptic_curves && + s->version != DTLS1_VERSION) { unsigned char *sdata = data; int ellipticcurvelist_length = (*(sdata++) << 8); @@ -733,15 +848,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in *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) + if (!s->hit) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; + if(s->session->tlsext_ellipticcurvelist) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + s->session->tlsext_ellipticcurvelist_length = 0; + 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); } - 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; @@ -752,7 +874,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } #endif /* OPENSSL_NO_EC */ #ifdef TLSEXT_TYPE_opaque_prf_input - else if (type == TLSEXT_TYPE_opaque_prf_input) + else if (type == TLSEXT_TYPE_opaque_prf_input && + s->version != DTLS1_VERSION) { unsigned char *sdata = data; @@ -790,8 +913,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in return 0; } } - else if (type == TLSEXT_TYPE_status_request - && s->ctx->tlsext_status_cb) + else if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } + else if (type == TLSEXT_TYPE_status_request && + s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) { if (size < 5) @@ -825,6 +954,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } n2s(data, idsize); dsize -= 2 + idsize; + size -= 2 + idsize; if (dsize < 0) { *al = SSL_AD_DECODE_ERROR; @@ -863,9 +993,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } /* Read in request_extensions */ + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } n2s(data,dsize); size -= 2; - if (dsize > size) + if (dsize != size) { *al = SSL_AD_DECODE_ERROR; return 0; @@ -896,22 +1031,41 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } *p = data; + + ri_check: + + /* Need RI if renegotiating */ + + if (!renegotiate_seen && s->renegotiate && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + return 1; } int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) { + unsigned short length; unsigned short type; unsigned short size; - unsigned short len; unsigned char *data = *p; - int tlsext_servername = 0; + int renegotiate_seen = 0; if (data >= (d+n-2)) - return 1; + goto ri_check; - n2s(data,len); + n2s(data,length); + if (data+length != d+n) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } while(data <= (d+n-4)) { @@ -919,7 +1073,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in n2s(data,size); if (data+size > (d+n)) - return 1; + goto ri_check; if (s->tlsext_debug_cb) s->tlsext_debug_cb(s, 1, type, data, size, @@ -936,7 +1090,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } #ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats) + else if (type == TLSEXT_TYPE_ec_point_formats && + s->version != DTLS1_VERSION) { unsigned char *sdata = data; int ecpointformatlist_length = *(sdata++); @@ -982,7 +1137,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in s->tlsext_ticket_expected = 1; } #ifdef TLSEXT_TYPE_opaque_prf_input - else if (type == TLSEXT_TYPE_opaque_prf_input) + else if (type == TLSEXT_TYPE_opaque_prf_input && + s->version != DTLS1_VERSION) { unsigned char *sdata = data; @@ -1012,7 +1168,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } #endif - else if (type == TLSEXT_TYPE_status_request) + else if (type == TLSEXT_TYPE_status_request && + s->version != DTLS1_VERSION) { /* MUST be empty and only sent if we've requested * a status request message. @@ -1025,7 +1182,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in /* Set flag to expect CertificateStatus message */ s->tlsext_status_expected = 1; } - + else if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } data+=size; } @@ -1057,6 +1219,26 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } *p = data; + + ri_check: + + /* Determine if we need to see RI. Strictly speaking if we want to + * avoid an attack we should *always* see RI even on initial server + * hello because the client doesn't see any renegotiation during an + * attack. However this would mean we could not connect to any server + * which doesn't support RI so for the immediate future tolerate RI + * absence on initial connect only. + */ + if (!renegotiate_seen + && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + return 1; } @@ -1085,7 +1267,7 @@ int ssl_prepare_clienthello_tlsext(SSL *s) break; } } - using_ecc = using_ecc && (s->version == TLS1_VERSION); + using_ecc = using_ecc && (s->version >= TLS1_VERSION); if (using_ecc) { if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); @@ -1313,23 +1495,20 @@ int ssl_check_serverhello_tlsext(SSL *s) int al = SSL_AD_UNRECOGNIZED_NAME; #ifndef OPENSSL_NO_EC - /* If we are client and using an elliptic curve cryptography cipher suite, then server - * must return a an EC point formats lists containing uncompressed. + /* If we are client and using an elliptic curve cryptography cipher + * suite, then if server returns an EC point formats lists extension + * it must contain uncompressed. */ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && + (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA))) { /* we are using an ECC cipher */ size_t i; unsigned char *list; int found_uncompressed = 0; - if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length == 0)) - { - SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); - return -1; - } list = s->session->tlsext_ecpointformatlist; for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) { @@ -1516,16 +1695,17 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, unsigned char tick_hmac[EVP_MAX_MD_SIZE]; HMAC_CTX hctx; EVP_CIPHER_CTX ctx; + SSL_CTX *tctx = s->initial_ctx; /* Need at least keyname + iv + some encrypted data */ if (eticklen < 48) goto tickerr; /* Initialize session ticket encryption and HMAC contexts */ HMAC_CTX_init(&hctx); EVP_CIPHER_CTX_init(&ctx); - if (s->ctx->tlsext_ticket_key_cb) + if (tctx->tlsext_ticket_key_cb) { unsigned char *nctick = (unsigned char *)etick; - int rv = s->ctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, 0); if (rv < 0) return -1; @@ -1537,12 +1717,12 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, else { /* Check key name matches */ - if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16)) + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) goto tickerr; - HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, + HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL); EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - s->ctx->tlsext_tick_aes_key, etick + 16); + tctx->tlsext_tick_aes_key, etick + 16); } /* Attempt to process session ticket, first conduct sanity and * integrity checks on ticket.