From ea7c13b82d7aa42eebb27ec5354bfb6b278ba83b Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 22 Jan 2024 11:27:25 -0500 Subject: [PATCH] prop346: Parse the ntorv3 subproto extension server side Signed-off-by: David Goulet --- src/core/crypto/onion_crypto.c | 110 ++++++++++++++++++++++++++++++++- src/core/crypto/onion_crypto.h | 7 +++ src/trunnel/ntorv3.h | 1 + src/trunnel/ntorv3.trunnel | 6 ++ 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c index 0839d8903f..a5f58cdabc 100644 --- a/src/core/crypto/onion_crypto.c +++ b/src/core/crypto/onion_crypto.c @@ -32,6 +32,7 @@ #include "core/or/or.h" #include "core/or/extendinfo.h" +#include "core/or/protover.h" #include "core/crypto/onion_crypto.h" #include "core/crypto/onion_fast.h" #include "core/crypto/onion_ntor.h" @@ -50,6 +51,7 @@ #include "trunnel/congestion_control.h" #include "trunnel/extension.h" +#include "trunnel/ntorv3.h" static const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend"; static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14; @@ -57,6 +59,106 @@ static const size_t NTOR3_CIRC_VERIFICATION_LEN = 14; #define NTOR3_VERIFICATION_ARGS \ NTOR3_CIRC_VERIFICATION, NTOR3_CIRC_VERIFICATION_LEN +/** Parse the ntor v3 subprotocol extension from the given extension field. The + * params_out is populated with the values found in the extension. These values + * are correct as they are validated. + * + * Return true iff parsing was successful. */ +static bool +parse_subproto_extension(const trn_extension_field_t *field, + circuit_params_t *params_out) +{ + bool ret = false; + trn_ntorv3_ext_subproto_t *request = NULL; + + tor_assert(field); + tor_assert(trn_extension_field_get_field_type(field) == + TRUNNEL_NTORV3_EXT_TYPE_SUBPROTO_REQ); + + if (trn_ntorv3_ext_subproto_parse(&request, + trn_extension_field_getconstarray_field(field), + trn_extension_field_getlen_field(field)) < 0) { + goto end; + } + + for (size_t i = 0; i < trn_ntorv3_ext_subproto_getlen_reqs(request); i++) { + const trn_ntorv3_ext_subproto_req_t *req = + trn_ntorv3_ext_subproto_getconst_reqs(request, i); + switch (req->proto_id) { + case PRT_FLOWCTRL: + /* Unsupported version is an automatic parsing failure which should + * result in closing the circuit. */ + if (!protover_is_supported_here(PRT_FLOWCTRL, req->proto_version)) { + ret = false; + goto end; + } + params_out->subproto.flow_ctrl = req->proto_version; + params_out->cc_enabled = true; + break; + default: + /* Reject any unknown values. */ + ret = false; + goto end; + } + } + + /* Success. */ + ret = true; + + end: + trn_ntorv3_ext_subproto_free(request); + return ret; +} + +/** Parse the ntor v3 server extension(s) that is the extension destined for + * the server from the given data and length. The params_out is populated with + * the values found in any known extension. + * + * WARNING: The data put in params out is NOT validated for correctness. + * + * Return true iff parsing was successful. */ +static bool +parse_ntor3_server_ext(const uint8_t *data, size_t data_len, + circuit_params_t *params_out) +{ + bool ret = false; + trn_extension_t *ext = NULL; + + /* Parse extension from payload. */ + if (trn_extension_parse(&ext, data, data_len) < 0) { + goto end; + } + + /* Go over all fields. And identify the known fields. Ignore unknowns. */ + for (size_t idx = 0; idx < trn_extension_get_num(ext); idx++) { + const trn_extension_field_t *field = trn_extension_get_fields(ext, idx); + tor_assert(field); + + switch (trn_extension_field_get_field_type(field)) { + case TRUNNEL_NTORV3_EXT_TYPE_SUBPROTO_REQ: + ret = parse_subproto_extension(field, params_out); + break; + case TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST: + /* Ignore CC field, it is parsed elsewhere. */ + break; + default: + ret = false; + break; + } + + if (!ret) { + goto end; + } + } + + /* Success. */ + ret = true; + + end: + trn_extension_free(ext); + return ret; +} + /** Return a new server_onion_keys_t object with all of the keys * and other info we might need to do onion handshakes. (We make a copy of * our keys for each cpuworker to avoid race conditions with the main thread, @@ -235,7 +337,13 @@ negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg, uint8_t **resp_msg_out, size_t *resp_msg_len_out) { - int ret; + int ret = -1; + + /* Failed to parse the extension. */ + if (!parse_ntor3_server_ext(param_request_msg, param_request_len, + params_out)) { + goto err; + } /* Parse request. */ ret = congestion_control_parse_ext_request(param_request_msg, diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h index cb0188ff54..8251111c37 100644 --- a/src/core/crypto/onion_crypto.h +++ b/src/core/crypto/onion_crypto.h @@ -25,6 +25,11 @@ typedef struct server_onion_keys_t { void onion_handshake_state_release(onion_handshake_state_t *state); +/** Negotiated subprotocol versions set after a ntorv3 handshake. */ +typedef struct circuit_subproto_t { + uint8_t flow_ctrl; +} circuit_subproto_t; + /** * Parameters negotiated as part of a circuit handshake. */ @@ -34,6 +39,8 @@ typedef struct circuit_params_t { bool cc_enabled; /** The number of cells in a sendme increment. Only used if cc_enabled=1. */ uint8_t sendme_inc_cells; + /** Subprotocol version allowed on the circuit. */ + circuit_subproto_t subproto; } circuit_params_t; int onion_skin_create(int type, diff --git a/src/trunnel/ntorv3.h b/src/trunnel/ntorv3.h index 5999e179b2..dfa4bac6dc 100644 --- a/src/trunnel/ntorv3.h +++ b/src/trunnel/ntorv3.h @@ -8,6 +8,7 @@ #include #include "trunnel.h" +#define TRUNNEL_EXT_TYPE_SUBPROTO_REQ 3 #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_NTORV3_EXT_SUBPROTO_REQ) struct trn_ntorv3_ext_subproto_req_st { uint8_t proto_id; diff --git a/src/trunnel/ntorv3.trunnel b/src/trunnel/ntorv3.trunnel index fba3bdeeb1..fee756af39 100644 --- a/src/trunnel/ntorv3.trunnel +++ b/src/trunnel/ntorv3.trunnel @@ -1,3 +1,9 @@ +/* + * The ntorv3 extension type value in order to recognize the subproto + * extension. + */ +const TRUNNEL_EXT_TYPE_SUBPROTO_REQ = 0x03; + /* * Extension used to negotiate subprotocol versions detailed in proposal 346. */ -- 2.47.3