From: Matt Caswell Date: Wed, 5 Jul 2017 07:45:46 +0000 (+0100) Subject: Send and receive the ticket_nonce field in a NewSessionTicket X-Git-Tag: OpenSSL_1_1_1-pre1~1086 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=9b6a82546151d6f971628e2d7828752ee47bfef7;hp=07ff590f8f2d0affcd89afad103274100bb5705b;ds=inline Send and receive the ticket_nonce field in a NewSessionTicket This just adds the processing for sending and receiving the newly added ticket_nonce field. It doesn't actually use it yet. Reviewed-by: Ben Kaduk (Merged from https://github.com/openssl/openssl/pull/3852) --- diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 340fcf288b..f6019bca06 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -41,6 +41,7 @@ typedef struct { uint64_t flags; uint32_t max_early_data; ASN1_OCTET_STRING *alpn_selected; + ASN1_OCTET_STRING *tick_nonce; } SSL_SESSION_ASN1; ASN1_SEQUENCE(SSL_SESSION_ASN1) = { @@ -69,7 +70,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = { ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, flags, ZUINT64, 13), ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_tick_age_add, ZUINT32, 14), ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15), - ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16) + ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16), + ASN1_EXP_OPT(SSL_SESSION_ASN1, tick_nonce, ASN1_OCTET_STRING, 17) } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1) IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1) @@ -118,6 +120,7 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) ASN1_OCTET_STRING psk_identity, psk_identity_hint; #endif ASN1_OCTET_STRING alpn_selected; + ASN1_OCTET_STRING tick_nonce; long l; @@ -187,6 +190,12 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) ssl_session_oinit(&as.alpn_selected, &alpn_selected, in->ext.alpn_selected, in->ext.alpn_selected_len); + if (in->ext.tick_nonce == NULL) + as.tick_nonce = NULL; + else + ssl_session_oinit(&as.tick_nonce, &tick_nonce, + in->ext.tick_nonce, in->ext.tick_nonce_len); + return i2d_SSL_SESSION_ASN1(&as, pp); } @@ -352,6 +361,15 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, ret->ext.alpn_selected_len = 0; } + if (as->tick_nonce != NULL) { + ret->ext.tick_nonce = as->tick_nonce->data; + ret->ext.tick_nonce_len = as->tick_nonce->length; + as->tick_nonce->data = NULL; + } else { + ret->ext.tick_nonce = NULL; + ret->ext.tick_nonce_len = 0; + } + M_ASN1_free_of(as, SSL_SESSION_ASN1); if ((a != NULL) && (*a == NULL)) diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 1105416d96..10762859dd 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -551,6 +551,8 @@ struct ssl_session_st { /* Session lifetime hint in seconds */ unsigned long tick_lifetime_hint; uint32_t tick_age_add; + unsigned char *tick_nonce; + size_t tick_nonce_len; int tick_identity; /* Max number of bytes that can be sent as early data */ uint32_t max_early_data; diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index e7fe714e58..8740e15daa 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -130,6 +130,8 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) dest->peer = NULL; memset(&dest->ex_data, 0, sizeof(dest->ex_data)); + dest->ext.tick_nonce = NULL; + /* We deliberately don't copy the prev and next pointers */ dest->prev = NULL; dest->next = NULL; @@ -222,6 +224,13 @@ SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) } } + if (src->ext.tick_nonce != NULL) { + dest->ext.tick_nonce = OPENSSL_memdup(src->ext.tick_nonce, + src->ext.tick_nonce_len); + if (dest->ext.tick_nonce == NULL) + goto err; + } + #ifndef OPENSSL_NO_SRP if (src->srp_username) { dest->srp_username = OPENSSL_strdup(src->srp_username); @@ -785,6 +794,7 @@ void SSL_SESSION_free(SSL_SESSION *ss) OPENSSL_free(ss->srp_username); #endif OPENSSL_free(ss->ext.alpn_selected); + OPENSSL_free(ss->ext.tick_nonce); CRYPTO_THREAD_lock_free(ss->lock); OPENSSL_clear_free(ss, sizeof(*ss)); } diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 53aa1dc0dc..e6c72268ca 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -2421,9 +2421,15 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt) unsigned long ticket_lifetime_hint, age_add = 0; unsigned int sess_len; RAW_EXTENSION *exts = NULL; + PACKET nonce; if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint) - || (SSL_IS_TLS13(s) && !PACKET_get_net_4(pkt, &age_add)) + || (SSL_IS_TLS13(s) + && (!PACKET_get_net_4(pkt, &age_add) + || !PACKET_get_length_prefixed_1(pkt, &nonce) + || PACKET_remaining(&nonce) == 0 + || !PACKET_memdup(&nonce, &s->session->ext.tick_nonce, + &s->session->ext.tick_nonce_len))) || !PACKET_get_net_2(pkt, &ticklen) || (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) != ticklen) || (SSL_IS_TLS13(s) diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 05405b0e0d..cfe6f513ff 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -3381,6 +3381,19 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0) goto err; s->session->ext.tick_age_add = age_add_u.age_add; + /* + * ticket_nonce is set to a single 0 byte because we only ever send a + * single ticket per connection. IMPORTANT: If we ever support multiple + * tickets per connection then this will need to be changed. + */ + OPENSSL_free(s->session->ext.tick_nonce); + s->session->ext.tick_nonce = OPENSSL_zalloc(sizeof(char)); + if (s->session->ext.tick_nonce == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_MALLOC_FAILURE); + goto err; + } + s->session->ext.tick_nonce_len = 1; s->session->time = (long)time(NULL); if (s->s3->alpn_selected != NULL) { OPENSSL_free(s->session->ext.alpn_selected); @@ -3497,7 +3510,11 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *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_put_bytes_u32(pkt, age_add_u.age_add) + /* ticket_nonce */ + || !WPACKET_start_sub_packet_u8(pkt) + || !WPACKET_put_bytes_u8(pkt, 0) + || !WPACKET_close(pkt))) /* Now the actual ticket data */ || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_get_total_written(pkt, &macoffset)