]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
prop346: Parse the ntorv3 subproto extension server side
authorDavid Goulet <dgoulet@torproject.org>
Mon, 22 Jan 2024 16:27:25 +0000 (11:27 -0500)
committerDavid Goulet <dgoulet@torproject.org>
Wed, 31 Jan 2024 15:15:07 +0000 (10:15 -0500)
Signed-off-by: David Goulet <dgoulet@torproject.org>
src/core/crypto/onion_crypto.c
src/core/crypto/onion_crypto.h
src/trunnel/ntorv3.h
src/trunnel/ntorv3.trunnel

index 0839d8903f17d707a45df22f13be5234e4ca61fa..a5f58cdabc39460eb301305fbc5c0eb2e89bb5bf 100644 (file)
@@ -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,
index cb0188ff54ef4c488fe7abdee5f2eb6d76e4f314..8251111c37ccbe617c7d24a3230b61a71e34569e 100644 (file)
@@ -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,
index 5999e179b2aa1b5e1ad583339c2465a14e942f6c..dfa4bac6dcda6e455ff67d448d675bab30913be9 100644 (file)
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #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;
index fba3bdeeb1558e5d8304dbefd3a3e667e977a831..fee756af390148cbc67b778be8cf032cd9e8be99 100644 (file)
@@ -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.
  */