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)
{
}
/**
- * @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.
*
* @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;
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)
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.
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