From: Neil Horman Date: Sun, 12 Jan 2025 03:16:16 +0000 (-0500) Subject: Add new token generation transmission X-Git-Tag: openssl-3.5.0-alpha1~242 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e73f330e99031f53820a382cf3a0776375f5b719;p=thirdparty%2Fopenssl.git Add new token generation transmission When we bind a channel, create a NEW_TOKEN token to be sent on the next available datagram, once the channel is validated Reviewed-by: Matt Caswell Reviewed-by: Saša Nedvědický (Merged from https://github.com/openssl/openssl/pull/26517) --- diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index c426cfad68d..852551e5624 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -210,6 +210,13 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch); void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code, const char *app_reason); +/** + * @brief schedules a NEW_TOKEN frame for sending on the channel + */ +int ossl_quic_channel_schedule_new_token(QUIC_CHANNEL *ch, + const unsigned char *token, + size_t token_len); + /* * Called when the handshake is confirmed. */ diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 19d0513059d..3c13437bb54 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -517,6 +517,55 @@ SSL *ossl_quic_channel_get0_tls(QUIC_CHANNEL *ch) return ch->tls; } +static void free_buf_mem(unsigned char *buf, size_t buf_len, void *arg) +{ + BUF_MEM_free((BUF_MEM *)arg); +} + +int ossl_quic_channel_schedule_new_token(QUIC_CHANNEL *ch, + const unsigned char *token, + size_t token_len) +{ + int rc = 0; + QUIC_CFQ_ITEM *cfq_item; + WPACKET wpkt; + BUF_MEM *buf_mem = NULL; + size_t l = 0; + + buf_mem = BUF_MEM_new(); + if (buf_mem == NULL) + goto err; + + if (!WPACKET_init(&wpkt, buf_mem)) + goto err; + + if (!ossl_quic_wire_encode_frame_new_token(&wpkt, token, + token_len)) { + WPACKET_cleanup(&wpkt); + goto err; + } + + WPACKET_finish(&wpkt); + + if (!WPACKET_get_total_written(&wpkt, &l)) + goto err; + + cfq_item = ossl_quic_cfq_add_frame(ch->cfq, 1, + QUIC_PN_SPACE_APP, + OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, 0, + (unsigned char *)buf_mem->data, l, + free_buf_mem, + buf_mem); + if (cfq_item == NULL) + goto err; + + rc = 1; +err: + if (!rc) + BUF_MEM_free(buf_mem); + return rc; +} + QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, uint64_t stream_id) { diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c index 863ff2f6d7c..da658c8a5be 100644 --- a/ssl/quic/quic_port.c +++ b/ssl/quic/quic_port.c @@ -794,7 +794,8 @@ static void cleanup_validation_token(QUIC_VALIDATION_TOKEN *token) } /** - * @brief Generates a validation token for a RETRY packet. + * @brief Generates a validation token for a RETRY/NEW_TOKEN packet. + * * * @param peer Address of the client peer receiving the packet. * @param odcid DCID of the connection attempt. @@ -803,10 +804,11 @@ static void cleanup_validation_token(QUIC_VALIDATION_TOKEN *token) * * @return 1 if validation token is filled successfully, 0 otherwise. */ -static int generate_retry_token(BIO_ADDR *peer, QUIC_CONN_ID odcid, - QUIC_CONN_ID rscid, QUIC_VALIDATION_TOKEN *token) +static int generate_token(BIO_ADDR *peer, QUIC_CONN_ID odcid, + QUIC_CONN_ID rscid, QUIC_VALIDATION_TOKEN *token, + int is_retry) { - token->is_retry = 1; + token->is_retry = is_retry; token->timestamp = ossl_time_now(); token->remote_addr = NULL; token->odcid = odcid; @@ -1082,8 +1084,8 @@ static void port_send_retry(QUIC_PORT *port, goto err; /* Generate retry validation token */ - if (!generate_retry_token(peer, client_hdr->dst_conn_id, - hdr.src_conn_id, &token) + if (!generate_token(peer, client_hdr->dst_conn_id, + hdr.src_conn_id, &token, 1) || !marshal_validation_token(&token, buffer, &token_buf_len) || !encrypt_validation_token(port, buffer, token_buf_len, NULL, &ct_len) @@ -1336,6 +1338,36 @@ err: return ret; } +static void generate_new_token(QUIC_CHANNEL *ch, BIO_ADDR *peer) +{ + QUIC_CONN_ID rscid = { 0 }; + QUIC_VALIDATION_TOKEN token; + unsigned char buffer[ENCRYPTED_TOKEN_MAX_LEN]; + unsigned char ct_buf[ENCRYPTED_TOKEN_MAX_LEN]; + size_t ct_len; + size_t token_buf_len = 0; + + /* Clients never send a NEW_TOKEN */ + if (!ch->is_server) + return; + + if (!ossl_quic_lcidm_get_unused_cid(ch->port->lcidm, &rscid)) + return; + + if (!generate_token(peer, ch->init_dcid, rscid, &token, 0) + || !marshal_validation_token(&token, buffer, &token_buf_len) + || !encrypt_validation_token(ch->port, buffer, token_buf_len, NULL, + &ct_len) + || ct_len > ENCRYPTED_TOKEN_MAX_LEN + || !encrypt_validation_token(ch->port, buffer, token_buf_len, ct_buf, + &ct_len) + || !ossl_assert(ct_len >= QUIC_RETRY_INTEGRITY_TAG_LEN)) + return; + + ossl_quic_channel_schedule_new_token(ch, ct_buf, ct_len); + cleanup_validation_token(&token); +} + /* * This is called by the demux when we get a packet not destined for any known * DCID. @@ -1457,6 +1489,11 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg, port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id, &odcid, &new_ch); + /* + * Generate a token for sending in a later NEW_TOKEN frame + */ + generate_new_token(new_ch, &e->peer); + /* * The channel will do all the LCID registration needed, but as an * optimization inject this packet directly into the channel's QRX for