diff --git a/crypto/shared.c b/crypto/shared.c index 08aa5e2b520850b09ddbff00beda27fa95006230..7e5219c52f2957a5463846370e0b1a1ceaf8bd8d 100644 --- a/crypto/shared.c +++ b/crypto/shared.c @@ -245,6 +245,35 @@ fail: return -1; } +/* + * crypto_set_local_transport_params gets local QUIC transport + * parameters from |conn| and sets it to |tls|. + * + * This function returns 0 if it succeeds, or -1. + */ +static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { + ngtcp2_transport_params_type exttype = + ngtcp2_conn_is_server(conn) + ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS + : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO; + ngtcp2_transport_params params; + ngtcp2_ssize nwrite; + uint8_t buf[256]; + + ngtcp2_conn_get_local_transport_params(conn, ¶ms); + + nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, ¶ms); + if (nwrite < 0) { + return -1; + } + + if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) { + return -1; + } + + return 0; +} + int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp_key, ngtcp2_crypto_level level, @@ -311,18 +340,23 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } break; case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen, + &hp_ctx); + if (rv != 0) { + goto fail; + } + if (ngtcp2_conn_is_server(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { goto fail; } - } - rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen, - &hp_ctx); - if (rv != 0) { - goto fail; + if (crypto_set_local_transport_params(conn, tls) != 0) { + goto fail; + } } + break; case NGTCP2_CRYPTO_LEVEL_APP: rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv, @@ -678,60 +712,29 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, return spktlen; } -/* - * crypto_set_local_transport_params gets local QUIC transport - * parameters from |conn| and sets it to |tls|. - * - * This function returns 0 if it succeeds, or -1. - */ -static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { - ngtcp2_transport_params_type exttype = - ngtcp2_conn_is_server(conn) - ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS - : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO; - ngtcp2_transport_params params; - ngtcp2_ssize nwrite; - uint8_t buf[256]; - - ngtcp2_conn_get_local_transport_params(conn, ¶ms); - - nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, ¶ms); - if (nwrite < 0) { - return -1; - } - - if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) { - return -1; - } - - return 0; -} - /* * crypto_setup_initial_crypto establishes the initial secrets and * encryption keys, and prepares local QUIC transport parameters. */ static int crypto_setup_initial_crypto(ngtcp2_conn *conn, const ngtcp2_cid *dcid) { - void *tls = ngtcp2_conn_get_tls_native_handle(conn); - - if (ngtcp2_crypto_derive_and_install_initial_key(conn, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - dcid) != 0) { - return -1; - } - - return crypto_set_local_transport_params(conn, tls); + return ngtcp2_crypto_derive_and_install_initial_key( + conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid); } int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) { const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(conn); + void *tls = ngtcp2_conn_get_tls_native_handle(conn); (void)user_data; if (crypto_setup_initial_crypto(conn, dcid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } + if (crypto_set_local_transport_params(conn, tls) != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + if (ngtcp2_crypto_read_write_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h index 2e420efe4caef7291f478bb6b77580d1beb06d97..6d161677ae58c7157adb74f9156a82b4ac04aa67 100644 --- a/lib/includes/ngtcp2/ngtcp2.h +++ b/lib/includes/ngtcp2/ngtcp2.h @@ -2427,6 +2427,27 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn, NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params( ngtcp2_conn *conn, const ngtcp2_transport_params *params); +/** + * @function + * + * `ngtcp2_conn_set_local_transport_params` sets the local transport + * parameters |params|. This function can only be called by server. + * Although the local transport parameters are passed to + * `ngtcp2_conn_server_new`, server might want to update them after + * ALPN is chosen. In that case, server can update the transport + * parameter with this function. Server must call this function + * before calling `ngtcp2_conn_install_tx_handshake_key`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGTCP2_ERR_INVALID_STATE` + * `ngtcp2_conn_install_tx_handshake_key` has been called. + */ +NGTCP2_EXTERN int +ngtcp2_conn_set_local_transport_params(ngtcp2_conn *conn, + const ngtcp2_transport_params *params); + /** * @function * diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c index a9a031e9c9a194a9bae8b67fc937e05d5a9e9ca3..90b64087ed01cc57e3ef8ae2db6877404019bc51 100644 --- a/lib/ngtcp2_conn.c +++ b/lib/ngtcp2_conn.c @@ -702,17 +702,6 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.settings.token.len = 0; } - if (params->active_connection_id_limit == 0) { - (*pconn)->local.settings.transport_params.active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; - } - - (*pconn)->local.settings.transport_params.initial_scid = *scid; - - if (scid->datalen == 0) { - (*pconn)->local.settings.transport_params.preferred_address_present = 0; - } - if (settings->max_udp_payload_size == 0) { (*pconn)->local.settings.max_udp_payload_size = NGTCP2_DEFAULT_MAX_PKTLEN; } @@ -772,10 +761,9 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_scident; } - ngtcp2_scid_init(scident, 0, scid, - params->stateless_reset_token_present - ? params->stateless_reset_token - : NULL); + /* Set stateless reset token later if it is available in the local + transport parameters */ + ngtcp2_scid_init(scident, 0, scid, NULL); rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); if (rv != 0) { @@ -784,26 +772,6 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, scident = NULL; - if (server && params->preferred_address_present) { - scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); - if (scident == NULL) { - rv = NGTCP2_ERR_NOMEM; - goto fail_scident; - } - - ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid, - params->preferred_address.stateless_reset_token); - - rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); - if (rv != 0) { - goto fail_scid_set_insert; - } - - scident = NULL; - - (*pconn)->scid.last_seq = 1; - } - ngtcp2_dcid_init(&(*pconn)->dcid.current, 0, dcid, NULL); ngtcp2_path_copy(&(*pconn)->dcid.current.ps.path, path); @@ -818,22 +786,12 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->version = version; (*pconn)->mem = mem; (*pconn)->user_data = user_data; - (*pconn)->rx.unsent_max_offset = (*pconn)->rx.max_offset = - params->initial_max_data; - (*pconn)->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi; - (*pconn)->remote.bidi.max_streams = params->initial_max_streams_bidi; - (*pconn)->remote.uni.unsent_max_streams = params->initial_max_streams_uni; - (*pconn)->remote.uni.max_streams = params->initial_max_streams_uni; (*pconn)->idle_ts = settings->initial_ts; (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX; ngtcp2_qlog_start(&(*pconn)->qlog, server ? &settings->qlog.odcid : dcid, server); - ngtcp2_qlog_parameters_set_transport_params( - &(*pconn)->qlog, &(*pconn)->local.settings.transport_params, server, - NGTCP2_QLOG_SIDE_LOCAL); - return 0; fail_seqgap_push: @@ -891,6 +849,16 @@ int ngtcp2_conn_client_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.bidi.next_stream_id = 0; (*pconn)->local.uni.next_stream_id = 2; + rv = ngtcp2_conn_commit_local_transport_params(*pconn); + if (rv != 0) { + ngtcp2_conn_del(*pconn); + return rv; + } + + ngtcp2_qlog_parameters_set_transport_params( + &(*pconn)->qlog, &(*pconn)->local.settings.transport_params, + (*pconn)->server, NGTCP2_QLOG_SIDE_LOCAL); + return 0; } @@ -8192,6 +8160,10 @@ int ngtcp2_conn_install_tx_handshake_key( pktns->crypto.tx.hp_ctx = *hp_ctx; + if (conn->server) { + return ngtcp2_conn_commit_local_transport_params(conn); + } + return 0; } @@ -8489,6 +8461,80 @@ void ngtcp2_conn_set_early_remote_transport_params( NGTCP2_QLOG_SIDE_REMOTE); } +int ngtcp2_conn_set_local_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params) { + assert(conn->server); + assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); + + if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) { + return NGTCP2_ERR_INVALID_STATE; + } + + conn->local.settings.transport_params = *params; + + return 0; +} + +int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) { + const ngtcp2_mem *mem = conn->mem; + ngtcp2_transport_params *params = &conn->local.settings.transport_params; + ngtcp2_scid *scident; + ngtcp2_ksl_it it; + int rv; + + assert(1 == ngtcp2_ksl_len(&conn->scid.set)); + + if (params->active_connection_id_limit == 0) { + params->active_connection_id_limit = + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + } + + params->initial_scid = conn->oscid; + + if (conn->oscid.datalen == 0) { + params->preferred_address_present = 0; + } + + if (conn->server) { + if (params->stateless_reset_token_present) { + it = ngtcp2_ksl_begin(&conn->scid.set); + scident = ngtcp2_ksl_it_get(&it); + + memcpy(scident->token, params->stateless_reset_token, + NGTCP2_STATELESS_RESET_TOKENLEN); + } + + if (params->preferred_address_present) { + scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); + if (scident == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid, + params->preferred_address.stateless_reset_token); + + rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident); + if (rv != 0) { + ngtcp2_mem_free(mem, scident); + return rv; + } + + conn->scid.last_seq = 1; + } + } + + conn->rx.unsent_max_offset = conn->rx.max_offset = params->initial_max_data; + conn->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi; + conn->remote.bidi.max_streams = params->initial_max_streams_bidi; + conn->remote.uni.unsent_max_streams = params->initial_max_streams_uni; + conn->remote.uni.max_streams = params->initial_max_streams_uni; + + ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, + NGTCP2_QLOG_SIDE_LOCAL); + + return 0; +} + void ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn, ngtcp2_transport_params *params) { *params = conn->local.settings.transport_params; diff --git a/lib/ngtcp2_conn.h b/lib/ngtcp2_conn.h index dbcb5d8847a871cacab5710049272cb3a66cd73b..1c0dc3ac448ecec9edac56dafa26bdb1c88b8456 100644 --- a/lib/ngtcp2_conn.h +++ b/lib/ngtcp2_conn.h @@ -622,4 +622,20 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, const ngtcp2_cid *dcid, ngtcp2_frame *fr, uint8_t rtb_flags, ngtcp2_tstamp ts); +/* + * ngtcp2_conn_commit_local_transport_params commits the local + * transport parameters, which is currently set to + * conn->local.settings.transport_params. This function will do some + * amends on transport parameters for adjusting default values. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + * NGTCP2_ERR_INVALID_ARGUMENT + * CID in preferred address equals to the original SCID. + */ +int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn); + #endif /* NGTCP2_CONN_H */