From: Nick Mathewson Date: Wed, 28 May 2025 16:51:08 +0000 (-0400) Subject: Propagate longer keylens through onion handshakes. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e5d40b9d934f0e18fd3939d9c7ddc4dd4b29b136;p=thirdparty%2Ftor.git Propagate longer keylens through onion handshakes. --- diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c index f8088745d2..f32633879b 100644 --- a/src/core/crypto/onion_crypto.c +++ b/src/core/crypto/onion_crypto.c @@ -259,6 +259,9 @@ negotiate_v3_ntor_server_circ_params(const uint8_t *param_request_msg, * reply_out, generate keys_out_len bytes worth of key material * in keys_out_len, a hidden service nonce to rend_nonce_out, * 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 type, using our state in handshake_state and the - * server's response in reply. On success, generate keys_out_len - * bytes worth of key material in keys_out_len, set + * server's response in reply. On success, generate an appropriate + * amount of key material in keys_out, + * set keys_out_len to the amount generated, set * rend_authenticator_out 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); diff --git a/src/core/crypto/onion_crypto.h b/src/core/crypto/onion_crypto.h index cb0188ff54..7d19961fc6 100644 --- a/src/core/crypto/onion_crypto.h +++ b/src/core/crypto/onion_crypto.h @@ -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); diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c index 9f8a88b6de..6714bc2f94 100644 --- a/src/core/mainloop/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -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."); diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index da8b51c374..adeb96d507 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -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, ¶ms, &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; } } diff --git a/src/core/or/command.c b/src/core/or/command.c index e808166623..5684844592 100644 --- a/src/core/or/command.c +++ b/src/core/or/command.c @@ -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, ¶ms); 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; diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c index 0d51c684a0..8106b6f648 100644 --- a/src/test/test_ntor_v3.c +++ b/src/test/test_ntor_v3.c @@ -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);