X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Ft1_lib.c;h=c4670346648a3f1331deea8a9f1c3de989a7b869;hp=1aaf8905c8179cae1dad30400a0b9184de3e5727;hb=fbed9f8158ef50518706798a1488f9af4be3eb7d;hpb=02c27b113cfc6000d94644e19c06c0f45e3480af diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 1aaf8905c8..c467034664 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -113,6 +113,7 @@ #include #include #include +#include #include "ssl_locl.h" const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; @@ -153,13 +154,19 @@ int tls1_new(SSL *s) void tls1_free(SSL *s) { +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_session_ticket) + { + OPENSSL_free(s->tlsext_session_ticket); + } +#endif /* OPENSSL_NO_TLSEXT */ ssl3_free(s); } void tls1_clear(SSL *s) { ssl3_clear(s); - s->version=TLS1_VERSION; + s->version = s->method->version; } #ifndef OPENSSL_NO_EC @@ -195,7 +202,9 @@ static int nid_list[] = int tls1_ec_curve_id2nid(int curve_id) { /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ - if ((curve_id < 1) || (curve_id > sizeof(nid_list)/sizeof(nid_list[0]))) return 0; + if ((curve_id < 1) || ((unsigned int)curve_id > + sizeof(nid_list)/sizeof(nid_list[0]))) + return 0; return nid_list[curve_id-1]; } @@ -266,6 +275,11 @@ 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 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION + && !s->s3->send_connection_binding) + return p; + ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ @@ -302,8 +316,33 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret+=size_str; } + /* Add the renegotiation option: TODOEKR switch */ + { + 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_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; @@ -322,7 +361,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; @@ -352,10 +392,25 @@ 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) + { + ticklen = s->tlsext_session_ticket->length; + s->session->tlsext_tick = OPENSSL_malloc(ticklen); + if (!s->session->tlsext_tick) + return NULL; + memcpy(s->session->tlsext_tick, + s->tlsext_session_ticket->data, + ticklen); + s->session->tlsext_ticklen = ticklen; + } else ticklen = 0; + if (ticklen == 0 && s->tlsext_session_ticket && + s->tlsext_session_ticket->data == NULL) + goto skip_ext; /* Check for enough room 2 for extension type, 2 for len * rest for ticket */ @@ -368,9 +423,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += ticklen; } } + 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; @@ -387,6 +444,55 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp && + s->version != DTLS1_VERSION) + { + int i; + long extlen, idlen, itmp; + OCSP_RESPID *id; + + idlen = 0; + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + itmp = i2d_OCSP_RESPID(id, NULL); + if (itmp <= 0) + return NULL; + idlen += itmp + 2; + } + + if (s->tlsext_ocsp_exts) + { + extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); + if (extlen < 0) + return NULL; + } + else + extlen = 0; + + if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request, ret); + if (extlen + idlen > 0xFFF0) + return NULL; + s2n(extlen + idlen + 5, ret); + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + s2n(idlen, ret); + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + /* save position of id len */ + unsigned char *q = ret; + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + /* skip over id len */ + ret += 2; + itmp = i2d_OCSP_RESPID(id, &ret); + /* write id len */ + s2n(itmp, q); + } + s2n(extlen, ret); + if (extlen > 0) + i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); + } + if ((extdatalen = ret-p-2)== 0) return p; @@ -399,6 +505,10 @@ 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, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) + return p; + ret+=2; if (ret>=limit) return NULL; /* this really never occurs, but ... */ @@ -409,8 +519,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; @@ -432,7 +568,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } /* Currently the server should not respond with a SupportedCurves extension */ #endif /* OPENSSL_NO_EC */ - + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { @@ -441,8 +577,16 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(0,ret); } + if (s->tlsext_status_expected) + { + if ((long)(limit - ret - 4) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request,ret); + s2n(0,ret); + } + #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; @@ -458,6 +602,20 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += sol; } #endif + if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) + && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) + { const unsigned char cryptopro_ext[36] = { + 0xfd, 0xe8, /*65000*/ + 0x00, 0x20, /*32 bytes length*/ + 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06, + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08, + 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17}; + if (limit-ret<36) return NULL; + memcpy(ret,cryptopro_ext,36); + ret+=36; + + } if ((extdatalen = ret-p-2)== 0) return p; @@ -472,14 +630,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)) { @@ -487,8 +648,10 @@ 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 if (s->tlsext_debug_cb) s->tlsext_debug_cb(s, 0, type, data, size, s->tlsext_debug_arg); @@ -562,6 +725,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in s->session->tlsext_hostname[len]='\0'; if (strlen(s->session->tlsext_hostname) != len) { OPENSSL_free(s->session->tlsext_hostname); + s->session->tlsext_hostname = NULL; *al = TLS1_AD_UNRECOGNIZED_NAME; return 0; } @@ -589,7 +753,8 @@ int ssl_parse_clienthello_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++); @@ -616,7 +781,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); @@ -646,7 +812,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; @@ -675,12 +842,141 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } #endif + else if (type == TLSEXT_TYPE_session_ticket) + { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } + 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) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + s->tlsext_status_type = *data++; + size--; + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { + const unsigned char *sdata; + int dsize; + /* Read in responder_id_list */ + n2s(data,dsize); + size -= 2; + if (dsize > size ) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + while (dsize > 0) + { + OCSP_RESPID *id; + int idsize; + if (dsize < 4) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data, idsize); + dsize -= 2 + idsize; + if (dsize < 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + data += idsize; + id = d2i_OCSP_RESPID(NULL, + &sdata, idsize); + if (!id) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (data != sdata) + { + OCSP_RESPID_free(id); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!s->tlsext_ocsp_ids + && !(s->tlsext_ocsp_ids = + sk_OCSP_RESPID_new_null())) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!sk_OCSP_RESPID_push( + s->tlsext_ocsp_ids, id)) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + /* Read in request_extensions */ + n2s(data,dsize); + size -= 2; + if (dsize > size) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + if (dsize > 0) + { + s->tlsext_ocsp_exts = + d2i_X509_EXTENSIONS(NULL, + &sdata, dsize); + if (!s->tlsext_ocsp_exts + || (data + dsize != sdata)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } + /* We don't know what to do with any other type + * so ignore it. + */ + else + s->tlsext_status_type = -1; + } /* session ticket processed earlier */ data+=size; } *p = data; + + ri_check: + + /* Need RI if renegotiating */ + + if (!renegotiate_seen && s->new_session && + !(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; } @@ -690,11 +986,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in 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); @@ -704,7 +1000,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, @@ -721,7 +1017,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++); @@ -752,6 +1049,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else if (type == TLSEXT_TYPE_session_ticket) { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || (size > 0)) { @@ -761,7 +1064,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; @@ -791,7 +1095,26 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } #endif - + 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. + */ + if ((s->tlsext_status_type == -1) || (size > 0)) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* 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; } @@ -823,6 +1146,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->new_session || !(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; } @@ -874,7 +1217,8 @@ int ssl_prepare_clienthello_tlsext(SSL *s) SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); return -1; } - for (i = 1, j = s->tlsext_ellipticcurvelist; i <= sizeof(nid_list)/sizeof(nid_list[0]); i++) + for (i = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= + sizeof(nid_list)/sizeof(nid_list[0]); i++) s2n(i,j); } #endif /* OPENSSL_NO_EC */ @@ -966,6 +1310,36 @@ int ssl_check_clienthello_tlsext(SSL *s) else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); + /* If status request then ask callback what to do. + * Note: this must be called after servername callbacks in case + * the certificate has changed. + */ + if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) + { + int r; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + switch (r) + { + /* We don't want to send a status request response */ + case SSL_TLSEXT_ERR_NOACK: + s->tlsext_status_expected = 0; + break; + /* status request response should be sent */ + case SSL_TLSEXT_ERR_OK: + if (s->tlsext_ocsp_resp) + s->tlsext_status_expected = 1; + else + s->tlsext_status_expected = 0; + break; + /* something bad happened */ + case SSL_TLSEXT_ERR_ALERT_FATAL: + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + else + s->tlsext_status_expected = 0; #ifdef TLSEXT_TYPE_opaque_prf_input { @@ -1022,8 +1396,8 @@ int ssl_check_clienthello_tlsext(SSL *s) al = SSL_AD_HANDSHAKE_FAILURE; } } -#endif +#endif err: switch (ret) { @@ -1111,6 +1485,35 @@ int ssl_check_serverhello_tlsext(SSL *s) } #endif + /* If we've requested certificate status and we wont get one + * tell the callback + */ + if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) + && s->ctx && s->ctx->tlsext_status_cb) + { + int r; + /* Set resp to NULL, resplen to -1 so callback knows + * there is no response. + */ + if (s->tlsext_ocsp_resp) + { + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + } + s->tlsext_ocsp_resplen = -1; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (r == 0) + { + al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + if (r < 0) + { + al = SSL_AD_INTERNAL_ERROR; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: @@ -1139,10 +1542,25 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, /* Point after session ID in client hello */ const unsigned char *p = session_id + len; unsigned short i; + + /* If tickets disabled behave as if no ticket present + * to permit stateful resumption. + */ + if (SSL_get_options(s) & SSL_OP_NO_TICKET) + return 1; + if ((s->version <= SSL3_VERSION) || !limit) return 1; if (p >= limit) return -1; + /* Skip past DTLS cookie */ + if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) + { + i = *(p++); + p+= i; + if (p >= limit) + return -1; + } /* Skip past cipher list */ n2s(p, i); p+= i; @@ -1170,8 +1588,8 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, * trigger a full handshake */ if (SSL_get_options(s) & SSL_OP_NO_TICKET) - return 0; - /* If zero length not client will accept a ticket + return 1; + /* If zero length note client will accept a ticket * and indicate cache miss to trigger full handshake */ if (size == 0) @@ -1179,6 +1597,15 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, s->tlsext_ticket_expected = 1; return 0; /* Cache miss */ } + if (s->tls_session_secret_cb) + { + /* Indicate cache miss here and instead of + * generating the session from ticket now, + * trigger abbreviated handshake based on + * external mechanism to calculate the master + * secret later. */ + return 0; + } return tls_decrypt_ticket(s, p, size, session_id, len, ret); } @@ -1194,39 +1621,59 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, SSL_SESSION *sess; unsigned char *sdec; const unsigned char *p; - int slen, mlen; + int slen, mlen, renew_ticket = 0; 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 (tctx->tlsext_ticket_key_cb) + { + unsigned char *nctick = (unsigned char *)etick; + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, + &ctx, &hctx, 0); + if (rv < 0) + return -1; + if (rv == 0) + goto tickerr; + if (rv == 2) + renew_ticket = 1; + } + else + { + /* Check key name matches */ + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) + goto tickerr; + HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL); + EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, etick + 16); + } /* Attempt to process session ticket, first conduct sanity and * integrity checks on ticket. */ - mlen = EVP_MD_size(tlsext_tick_md()); + mlen = HMAC_size(&hctx); + if (mlen < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; + } eticklen -= mlen; - /* Need at least keyname + iv + some encrypted data */ - if (eticklen < 48) - goto tickerr; - /* Check key name matches */ - if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16)) - goto tickerr; /* Check HMAC of encrypted ticket */ - HMAC_CTX_init(&hctx); - HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16, - tlsext_tick_md(), NULL); HMAC_Update(&hctx, etick, eticklen); HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); if (memcmp(tick_hmac, etick + eticklen, mlen)) goto tickerr; - /* Set p to start of IV */ - p = etick + 16; - EVP_CIPHER_CTX_init(&ctx); /* Attempt to decrypt session data */ - EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - s->ctx->tlsext_tick_aes_key, p); /* Move p after IV to start of encrypted ticket, update length */ - p += 16; - eticklen -= 32; + p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); + eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); sdec = OPENSSL_malloc(eticklen); if (!sdec) { @@ -1253,6 +1700,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, memcpy(sess->session_id, sess_id, sesslen); sess->session_id_length = sesslen; *psess = sess; + s->tlsext_ticket_expected = renew_ticket; return 1; } /* If session decrypt failure indicate a cache miss and set state to