X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fstatem%2Fstatem_srvr.c;h=a4a0ea2438f83ea15f6ad9c14f8fed08a037c268;hp=c690cf0191cd9f42228198d4eb06c90190950cb1;hb=6a11d5c5ededa1543c2eeb2f9edcbe39bc58bb70;hpb=4ff1a5266685f4a687a9f91b531c2f979b96db22 diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index c690cf0191..a4a0ea2438 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -3739,7 +3739,44 @@ int tls_construct_server_certificate(SSL *s, WPACKET *pkt) return 1; } -int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) +static int create_ticket_prequel(SSL *s, WPACKET *pkt, uint32_t age_add, + unsigned char *tick_nonce) +{ + /* + * Ticket lifetime hint: For TLSv1.2 this is advisory only and we leave this + * unspecified for resumed session (for simplicity). + * In TLSv1.3 we reset the "time" field above, and always specify the + * timeout. + */ + if (!WPACKET_put_bytes_u32(pkt, + (s->hit && !SSL_IS_TLS13(s)) + ? 0 : s->session->timeout)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (SSL_IS_TLS13(s)) { + if (!WPACKET_put_bytes_u32(pkt, age_add) + || !WPACKET_sub_memcpy_u8(pkt, tick_nonce, TICKET_NONCE_SIZE)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL, + ERR_R_INTERNAL_ERROR); + return 0; + } + } + + /* Start the sub-packet for the actual ticket data */ + if (!WPACKET_start_sub_packet_u16(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CREATE_TICKET_PREQUEL, + ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +static int construct_stateless_ticket(SSL *s, WPACKET *pkt, uint32_t age_add, + unsigned char *tick_nonce) { unsigned char *senc = NULL; EVP_CIPHER_CTX *ctx = NULL; @@ -3752,123 +3789,8 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) SSL_CTX *tctx = s->session_ctx; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char key_name[TLSEXT_KEYNAME_LENGTH]; - int iv_len; + int iv_len, ok = 0; size_t macoffset, macendoffset; - union { - unsigned char age_add_c[sizeof(uint32_t)]; - uint32_t age_add; - } age_add_u; - - if (SSL_IS_TLS13(s)) { - size_t i, hashlen; - uint64_t nonce; - const char nonce_label[] = "resumption"; - const EVP_MD *md = ssl_handshake_md(s); - void (*cb) (const SSL *ssl, int type, int val) = NULL; - int hashleni = EVP_MD_size(md); - - /* Ensure cast to size_t is safe */ - if (!ossl_assert(hashleni >= 0)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, - ERR_R_INTERNAL_ERROR); - goto err; - } - hashlen = (size_t)hashleni; - - if (s->info_callback != NULL) - cb = s->info_callback; - else if (s->ctx->info_callback != NULL) - cb = s->ctx->info_callback; - - - if (cb != NULL) { - /* - * We don't start and stop the handshake in between each ticket when - * sending more than one - but it should appear that way to the info - * callback. - */ - if (s->sent_tickets != 0) { - ossl_statem_set_in_init(s, 0); - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - ossl_statem_set_in_init(s, 1); - } - cb(s, SSL_CB_HANDSHAKE_START, 1); - } - /* - * If we already sent one NewSessionTicket then we need to take a copy - * of it and create a new session from it. - */ - if (s->sent_tickets != 0) { - SSL_SESSION *new_sess = ssl_session_dup(s->session, 0); - - if (new_sess == NULL) { - /* SSLfatal already called */ - goto err; - } - - SSL_SESSION_free(s->session); - s->session = new_sess; - } - - if (!ssl_generate_session_id(s, s->session)) { - /* SSLfatal() already called */ - goto err; - } - if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, - ERR_R_INTERNAL_ERROR); - goto err; - } - s->session->ext.tick_age_add = age_add_u.age_add; - - OPENSSL_free(s->session->ext.tick_nonce); - s->session->ext.tick_nonce = OPENSSL_zalloc(TICKET_NONCE_SIZE); - if (s->session->ext.tick_nonce == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, - ERR_R_MALLOC_FAILURE); - goto err; - } - nonce = s->next_ticket_nonce; - for (i = TICKET_NONCE_SIZE; nonce > 0 && i > 0; i--) { - s->session->ext.tick_nonce[i - 1] = nonce & 0xff; - nonce >>= 8; - } - s->session->ext.tick_nonce_len = TICKET_NONCE_SIZE; - - if (!tls13_hkdf_expand(s, md, s->resumption_master_secret, - (const unsigned char *)nonce_label, - sizeof(nonce_label) - 1, - s->session->ext.tick_nonce, - s->session->ext.tick_nonce_len, - s->session->master_key, - hashlen)) { - /* SSLfatal() already called */ - goto err; - } - s->session->master_key_length = hashlen; - - s->session->time = (long)time(NULL); - if (s->s3->alpn_selected != NULL) { - OPENSSL_free(s->session->ext.alpn_selected); - s->session->ext.alpn_selected = - OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len); - if (s->session->ext.alpn_selected == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, - SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, - ERR_R_MALLOC_FAILURE); - goto err; - } - s->session->ext.alpn_selected_len = s->s3->alpn_selected_len; - } - s->session->ext.max_early_data = s->max_early_data; - } - - if (tctx->generate_ticket_cb != NULL && - tctx->generate_ticket_cb(s, tctx->ticket_cb_data) == 0) - goto err; /* get session encoding length */ slen_full = i2d_SSL_SESSION(s->session, NULL); @@ -3981,22 +3903,12 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) sizeof(tctx->ext.tick_key_name)); } - /* - * Ticket lifetime hint: For TLSv1.2 this is advisory only and we leave this - * unspecified for resumed session (for simplicity). - * In TLSv1.3 we reset the "time" field above, and always specify the - * timeout. - */ - if (!WPACKET_put_bytes_u32(pkt, - (s->hit && !SSL_IS_TLS13(s)) - ? 0 : s->session->timeout) - || (SSL_IS_TLS13(s) - && (!WPACKET_put_bytes_u32(pkt, age_add_u.age_add) - || !WPACKET_sub_memcpy_u8(pkt, s->session->ext.tick_nonce, - s->session->ext.tick_nonce_len))) - /* Now the actual ticket data */ - || !WPACKET_start_sub_packet_u16(pkt) - || !WPACKET_get_total_written(pkt, &macoffset) + if (!create_ticket_prequel(s, pkt, age_add, tick_nonce)) { + /* SSLfatal() already called */ + goto err; + } + + if (!WPACKET_get_total_written(pkt, &macoffset) /* Output key name */ || !WPACKET_memcpy(pkt, key_name, sizeof(key_name)) /* output IV */ @@ -4019,12 +3931,145 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) || !HMAC_Final(hctx, macdata1, &hlen) || hlen > EVP_MAX_MD_SIZE || !WPACKET_allocate_bytes(pkt, hlen, &macdata2) - || macdata1 != macdata2 - || !WPACKET_close(pkt)) { + || macdata1 != macdata2) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR); goto err; } + + /* Close the sub-packet created by create_ticket_prequel() */ + if (!WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR); + goto err; + } + + ok = 1; + err: + OPENSSL_free(senc); + EVP_CIPHER_CTX_free(ctx); + HMAC_CTX_free(hctx); + return ok; +} + +int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) +{ + SSL_CTX *tctx = s->session_ctx; + unsigned char tick_nonce[TICKET_NONCE_SIZE]; + union { + unsigned char age_add_c[sizeof(uint32_t)]; + uint32_t age_add; + } age_add_u; + + age_add_u.age_add = 0; + + if (SSL_IS_TLS13(s)) { + size_t i, hashlen; + uint64_t nonce; + static const unsigned char nonce_label[] = "resumption"; + const EVP_MD *md = ssl_handshake_md(s); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int hashleni = EVP_MD_size(md); + + /* Ensure cast to size_t is safe */ + if (!ossl_assert(hashleni >= 0)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_INTERNAL_ERROR); + goto err; + } + hashlen = (size_t)hashleni; + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + if (cb != NULL) { + /* + * We don't start and stop the handshake in between each ticket when + * sending more than one - but it should appear that way to the info + * callback. + */ + if (s->sent_tickets != 0) { + ossl_statem_set_in_init(s, 0); + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + ossl_statem_set_in_init(s, 1); + } + cb(s, SSL_CB_HANDSHAKE_START, 1); + } + /* + * If we already sent one NewSessionTicket, or we resumed then + * s->session may already be in a cache and so we must not modify it. + * Instead we need to take a copy of it and modify that. + */ + if (s->sent_tickets != 0 || s->hit) { + SSL_SESSION *new_sess = ssl_session_dup(s->session, 0); + + if (new_sess == NULL) { + /* SSLfatal already called */ + goto err; + } + + SSL_SESSION_free(s->session); + s->session = new_sess; + } + + if (!ssl_generate_session_id(s, s->session)) { + /* SSLfatal() already called */ + goto err; + } + if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_INTERNAL_ERROR); + goto err; + } + s->session->ext.tick_age_add = age_add_u.age_add; + + nonce = s->next_ticket_nonce; + for (i = TICKET_NONCE_SIZE; i > 0; i--) { + tick_nonce[i - 1] = (unsigned char)(nonce & 0xff); + nonce >>= 8; + } + + if (!tls13_hkdf_expand(s, md, s->resumption_master_secret, + nonce_label, + sizeof(nonce_label) - 1, + tick_nonce, + TICKET_NONCE_SIZE, + s->session->master_key, + hashlen)) { + /* SSLfatal() already called */ + goto err; + } + s->session->master_key_length = hashlen; + + s->session->time = (long)time(NULL); + if (s->s3->alpn_selected != NULL) { + OPENSSL_free(s->session->ext.alpn_selected); + s->session->ext.alpn_selected = + OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len); + if (s->session->ext.alpn_selected == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_MALLOC_FAILURE); + goto err; + } + s->session->ext.alpn_selected_len = s->s3->alpn_selected_len; + } + s->session->ext.max_early_data = s->max_early_data; + } + + if (tctx->generate_ticket_cb != NULL && + tctx->generate_ticket_cb(s, tctx->ticket_cb_data) == 0) + goto err; + + if (!construct_stateless_ticket(s, pkt, age_add_u.age_add, tick_nonce)) { + /* SSLfatal() already called */ + goto err; + } + if (SSL_IS_TLS13(s)) { if (!tls_construct_extensions(s, pkt, SSL_EXT_TLS1_3_NEW_SESSION_TICKET, @@ -4041,15 +4086,9 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) s->next_ticket_nonce++; ssl_update_cache(s, SSL_SESS_CACHE_SERVER); } - EVP_CIPHER_CTX_free(ctx); - HMAC_CTX_free(hctx); - OPENSSL_free(senc); return 1; err: - OPENSSL_free(senc); - EVP_CIPHER_CTX_free(ctx); - HMAC_CTX_free(hctx); return 0; }