]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Propagate longer keylens through onion handshakes.
authorNick Mathewson <nickm@torproject.org>
Wed, 28 May 2025 16:51:08 +0000 (12:51 -0400)
committerNick Mathewson <nickm@torproject.org>
Tue, 10 Jun 2025 23:06:47 +0000 (19:06 -0400)
src/core/crypto/onion_crypto.c
src/core/crypto/onion_crypto.h
src/core/mainloop/cpuworker.c
src/core/or/circuitbuild.c
src/core/or/command.c
src/test/test_ntor_v3.c

index f8088745d2e55b70582c8636ef9af2583caaed1c..f32633879bbf1e31a1eb835ef347a063e78d7c93 100644 (file)
@@ -259,6 +259,9 @@ negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg,
  * <b>reply_out</b>, generate <b>keys_out_len</b> bytes worth of key material
  * in <b>keys_out_len</b>, a hidden service nonce to <b>rend_nonce_out</b>,
  * and return the length of the reply. On failure, return -1.
+ *
+ * Requires that *keys_len_out of bytes are allocated at keys_out;
+ * adjusts *keys_out_len to the number of bytes actually genarated.
  */
 int
 onion_skin_server_handshake(int type,
@@ -267,12 +270,19 @@ onion_skin_server_handshake(int type,
                       const circuit_params_t *our_ns_params,
                       uint8_t *reply_out,
                       size_t reply_out_maxlen,
-     // XXXX keys_out_len will depend on the algorithm we're negotiating.
-                      uint8_t *keys_out, size_t keys_out_len,
+                      uint8_t *keys_out, size_t *keys_len_out,
                       uint8_t *rend_nonce_out,
                       circuit_params_t *params_out)
 {
   int r = -1;
+
+  relay_crypto_alg_t relay_alg = RELAY_CRYPTO_ALG_TOR1;
+  size_t keys_out_needed = relay_crypto_key_material_len(relay_alg);
+  if (BUG(*keys_len_out < keys_out_needed)) {
+    return -1;
+  }
+  *keys_len_out = keys_out_needed;
+
   memset(params_out, 0, sizeof(*params_out));
 
   switch (type) {
@@ -283,7 +293,8 @@ onion_skin_server_handshake(int type,
       return -1;
     if (onionskin_len != CREATE_FAST_LEN)
       return -1;
-    if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0)
+    if (fast_server_handshake(onion_skin, reply_out, keys_out,
+                              keys_out_needed)<0)
       return -1;
     r = CREATED_FAST_LEN;
     memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN);
@@ -294,7 +305,7 @@ onion_skin_server_handshake(int type,
     if (onionskin_len < NTOR_ONIONSKIN_LEN)
       return -1;
     {
-      size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+      size_t keys_tmp_len = keys_out_needed + DIGEST_LEN;
       tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
       uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
 
@@ -307,14 +318,14 @@ onion_skin_server_handshake(int type,
         return -1;
       }
 
-      memcpy(keys_out, keys_tmp, keys_out_len);
-      memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+      memcpy(keys_out, keys_tmp, keys_out_needed);
+      memcpy(rend_nonce_out, keys_tmp+keys_out_needed, DIGEST_LEN);
       memwipe(keys_tmp, 0, sizeof(keys_tmp));
       r = NTOR_REPLY_LEN;
     }
     break;
   case ONION_HANDSHAKE_TYPE_NTOR_V3: {
-    size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+    size_t keys_tmp_len = keys_out_needed + DIGEST_LEN;
     tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
     uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
     uint8_t *client_msg = NULL;
@@ -367,8 +378,8 @@ onion_skin_server_handshake(int type,
       return -1;
     }
 
-    memcpy(keys_out, keys_tmp, keys_out_len);
-    memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+    memcpy(keys_out, keys_tmp, keys_out_needed);
+    memcpy(rend_nonce_out, keys_tmp+keys_out_needed, DIGEST_LEN);
     memcpy(reply_out, server_handshake, server_handshake_len);
     memwipe(keys_tmp, 0, keys_tmp_len);
     memwipe(server_handshake, 0, server_handshake_len);
@@ -430,17 +441,22 @@ negotiate_v3_ntor_client_circ_params(const uint8_t *param_response_msg,
 
 /** Perform the final (client-side) step of a circuit-creation handshake of
  * type <b>type</b>, using our state in <b>handshake_state</b> and the
- * server's response in <b>reply</b>. On success, generate <b>keys_out_len</b>
- * bytes worth of key material in <b>keys_out_len</b>, set
+ * server's response in <b>reply</b>. On success, generate an appropriate
+ * amount of key material in <b>keys_out</b>,
+ * set <b>keys_out_len</b> to the amount generated, set
  * <b>rend_authenticator_out</b> to the "KH" field that can be used to
  * establish introduction points at this hop, and return 0. On failure,
  * return -1, and set *msg_out to an error message if this is worth
- * complaining to the user about. */
+ * complaining to the user about.
+ *
+ * Requires that *keys_len_out of bytes are allocated at keys_out;
+ * adjusts *keys_out_len to the number of bytes actually genarated.
+ */
 int
 onion_skin_client_handshake(int type,
                       const onion_handshake_state_t *handshake_state,
                       const uint8_t *reply, size_t reply_len,
-                      uint8_t *keys_out, size_t keys_out_len,
+                      uint8_t *keys_out, size_t *keys_len_out,
                       uint8_t *rend_authenticator_out,
                       circuit_params_t *params_out,
                       const char **msg_out)
@@ -448,6 +464,13 @@ onion_skin_client_handshake(int type,
   if (handshake_state->tag != type)
     return -1;
 
+  relay_crypto_alg_t relay_alg = RELAY_CRYPTO_ALG_TOR1;
+  size_t keys_out_needed = relay_crypto_key_material_len(relay_alg);
+  if (BUG(*keys_len_out < keys_out_needed)) {
+    return -1;
+  }
+  *keys_len_out = keys_out_needed;
+
   memset(params_out, 0, sizeof(*params_out));
 
   switch (type) {
@@ -460,7 +483,7 @@ onion_skin_client_handshake(int type,
       return -1;
     }
     if (fast_client_handshake(handshake_state->u.fast, reply,
-                              keys_out, keys_out_len, msg_out) < 0)
+                              keys_out, keys_out_needed, msg_out) < 0)
       return -1;
 
     memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN);
@@ -472,7 +495,7 @@ onion_skin_client_handshake(int type,
       return -1;
     }
     {
-      size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+      size_t keys_tmp_len = keys_out_needed + DIGEST_LEN;
       uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
       if (onion_skin_ntor_client_handshake(handshake_state->u.ntor,
                                         reply,
@@ -480,14 +503,14 @@ onion_skin_client_handshake(int type,
         tor_free(keys_tmp);
         return -1;
       }
-      memcpy(keys_out, keys_tmp, keys_out_len);
-      memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+      memcpy(keys_out, keys_tmp, keys_out_needed);
+      memcpy(rend_authenticator_out, keys_tmp + keys_out_needed, DIGEST_LEN);
       memwipe(keys_tmp, 0, keys_tmp_len);
       tor_free(keys_tmp);
     }
     return 0;
   case ONION_HANDSHAKE_TYPE_NTOR_V3: {
-    size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+    size_t keys_tmp_len = keys_out_needed + DIGEST_LEN;
     uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
     uint8_t *server_msg = NULL;
     size_t server_msg_len = 0;
@@ -512,8 +535,8 @@ onion_skin_client_handshake(int type,
     }
     tor_free(server_msg);
 
-    memcpy(keys_out, keys_tmp, keys_out_len);
-    memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+    memcpy(keys_out, keys_tmp, keys_out_needed);
+    memcpy(rend_authenticator_out, keys_tmp + keys_out_needed, DIGEST_LEN);
     memwipe(keys_tmp, 0, keys_tmp_len);
     tor_free(keys_tmp);
 
index cb0188ff54ef4c488fe7abdee5f2eb6d76e4f314..7d19961fc61a8f712d3c3882f52771001dff6962 100644 (file)
@@ -47,13 +47,13 @@ int onion_skin_server_handshake(int type,
                       const circuit_params_t *ns_params,
                       uint8_t *reply_out,
                       size_t reply_out_maxlen,
-                      uint8_t *keys_out, size_t key_out_len,
+                      uint8_t *keys_out, size_t *keys_len_out,
                       uint8_t *rend_nonce_out,
                       circuit_params_t *negotiated_params_out);
 int onion_skin_client_handshake(int type,
                       const onion_handshake_state_t *handshake_state,
                       const uint8_t *reply, size_t reply_len,
-                      uint8_t *keys_out, size_t key_out_len,
+                      uint8_t *keys_out, size_t *keys_out_len,
                       uint8_t *rend_authenticator_out,
                       circuit_params_t *negotiated_params_out,
                       const char **msg_out);
index 9f8a88b6de505f4b55cdf95019118c9ffb8c2174..6714bc2f945663190e32c4ca29ee0822d81b3760 100644 (file)
@@ -498,15 +498,18 @@ cpuworker_onion_handshake_threadfn(void *state_, void *work_)
   rpl.handshake_type = cc->handshake_type;
   if (req.timed)
     tor_gettimeofday(&tv_start);
+  size_t keys_len = sizeof(rpl.keys);
   n = onion_skin_server_handshake(cc->handshake_type,
                                   cc->onionskin, cc->handshake_len,
                                   onion_keys,
                                   &req.circ_ns_params,
                                   cell_out->reply,
                                   sizeof(cell_out->reply),
-                                  rpl.keys, CPATH_KEY_MATERIAL_LEN,
+                                  rpl.keys, &keys_len,
                                   rpl.rend_auth_material,
                                   &rpl.circ_params);
+  // XXXX Will be wrong for cgo.
+  tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
   if (n < 0) {
     /* failure */
     log_debug(LD_OR,"onion_skin_server_handshake failed.");
index da8b51c374533c4ca6bdabafa0a8a1c76112b62f..adeb96d507f295cf0230ebab0b9e573f4903864c 100644 (file)
@@ -1281,15 +1281,18 @@ circuit_finish_handshake(origin_circuit_t *circ,
   circuit_params_t params;
   {
     const char *msg = NULL;
+    size_t keylen = sizeof(keys);
     if (onion_skin_client_handshake(hop->handshake_state.tag,
                                     &hop->handshake_state,
                                     reply->reply, reply->handshake_len,
-                                    (uint8_t*)keys, sizeof(keys),
+                                    (uint8_t*)keys, &keylen,
                                     (uint8_t*)hop->rend_circ_nonce,
                                     &params,
                                     &msg) < 0) {
       if (msg)
         log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg);
+      // XXXX This will be wrong for CGO.
+      tor_assert(keylen == sizeof(keys));
       return -END_CIRC_REASON_TORPROTOCOL;
     }
   }
index e808166623aa34e1e69cd880e30485305e9bb6e2..5684844592fc4db9a73fc3061a4d54011aea425f 100644 (file)
@@ -371,6 +371,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
     circuit_params_t params;
 
     memset(&created_cell, 0, sizeof(created_cell));
+    size_t keylen = sizeof(keys);
     len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
                                        create_cell->onionskin,
                                        create_cell->handshake_len,
@@ -378,11 +379,11 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
                                        NULL,
                                        created_cell.reply,
                                        sizeof(created_cell.reply),
-                                       keys, CPATH_KEY_MATERIAL_LEN,
+                                        keys, &keylen,
                                        rend_circ_nonce,
                                        &params);
     tor_free(create_cell);
-    if (len < 0) {
+    if (len < 0 || keylen != sizeof(keys)) {
       log_warn(LD_OR,"Failed to generate key material. Closing.");
       circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
       return;
index 0d51c684a0f10fc372af06ac9f17297ab5c406f2..8106b6f6483241cc7b5e7d2a2b23c925bed39d42 100644 (file)
@@ -218,18 +218,20 @@ run_full_handshake(circuit_params_t *serv_params_in,
 
   server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair;
 
+  size_t serv_keylen = sizeof(serv_keys);
+  size_t client_keylen = sizeof(serv_keys);
   reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
                               onionskin, onionskin_len,
                               &server_keys, serv_params_in,
                               serv_reply, sizeof(serv_reply),
-                              serv_keys, sizeof(serv_keys),
+                              serv_keys, &serv_keylen,
                               rend_nonce, serv_params_out);
   tt_int_op(reply_len, OP_NE, -1);
 
   tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3,
                               &handshake_state,
                               serv_reply, reply_len,
-                              client_keys, sizeof(client_keys),
+                              client_keys, &client_keylen,
                               rend_auth, client_params_out,
                               NULL), OP_EQ, 0);