#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
+#include "core/crypto/onion_ntor_v3.h"
#include "core/crypto/onion_tap.h"
#include "feature/relay/router.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "feature/relay/routerkeys.h"
+
+#include "core/or/circuitbuild.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
+/* TODO: Add this to the specification! */
+const uint8_t NTOR3_CIRC_VERIFICATION[] = "circuit extend";
+const size_t NTOR3_CIRC_VERIFICATION_LEN = 14;
+
+#define NTOR3_VERIFICATION_ARGS \
+ NTOR3_CIRC_VERIFICATION, NTOR3_CIRC_VERIFICATION_LEN
+
/** 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,
{
server_onion_keys_t *keys = tor_malloc_zero(sizeof(server_onion_keys_t));
memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
+ ed25519_pubkey_copy(&keys->my_ed_identity, get_master_identity_key());
dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
keys->curve25519_key_map = construct_ntor_key_map();
keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
ntor_handshake_state_free(state->u.ntor);
state->u.ntor = NULL;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ ntor3_handshake_state_free(state->u.ntor3);
+ break;
default:
/* LCOV_EXCL_START
* This state should not even exist. */
r = NTOR_ONIONSKIN_LEN;
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ if (!extend_info_supports_ntor_v3(node))
+ return -1;
+ if (ed25519_public_key_is_zero(&node->ed_identity))
+ return -1;
+ size_t msg_len = 0;
+ uint8_t *msg = NULL;
+ if (client_circ_negotiation_message(node, &msg, &msg_len) < 0)
+ return -1;
+ uint8_t *onion_skin = NULL;
+ size_t onion_skin_len = 0;
+ int status = onion_skin_ntor3_create(
+ &node->ed_identity,
+ &node->curve25519_onion_key,
+ NTOR3_VERIFICATION_ARGS,
+ msg, msg_len, /* client message */
+ &state_out->u.ntor3,
+ &onion_skin, &onion_skin_len);
+ tor_free(msg);
+ if (status < 0) {
+ return -1;
+ }
+ if (onion_skin_len > onion_skin_out_maxlen) {
+ tor_free(onion_skin);
+ return -1;
+ }
+ memcpy(onion_skin_out, onion_skin, onion_skin_len);
+ tor_free(onion_skin);
+ r = (int) onion_skin_len;
+ break;
+
default:
/* LCOV_EXCL_START
* We should never try to create an impossible handshake type. */
r = NTOR_REPLY_LEN;
}
break;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3: {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
+ uint8_t keys_tmp[MAX_KEYS_TMP_LEN];
+ uint8_t *client_msg = NULL;
+ size_t client_msg_len = 0;
+ ntor3_server_handshake_state_t *state = NULL;
+
+ if (onion_skin_ntor3_server_handshake_part1(
+ keys->curve25519_key_map,
+ keys->junk_keypair,
+ &keys->my_ed_identity,
+ onion_skin, onionskin_len,
+ NTOR3_VERIFICATION_ARGS,
+ &client_msg, &client_msg_len,
+ &state) < 0) {
+ return -1;
+ }
+
+ uint8_t reply_msg[1] = { 0 };
+ size_t reply_msg_len = 1;
+ {
+ /* TODO, Okay, we have a message from the client trying to negotiate
+ * parameters. We need to decide whether the client's request is
+ * okay, what we're going to say in response, and what circuit
+ * parameters we've just negotiated
+ */
+
+ tor_free(client_msg);
+ }
+
+ uint8_t *server_handshake = NULL;
+ size_t server_handshake_len = 0;
+ if (onion_skin_ntor3_server_handshake_part2(
+ state,
+ NTOR3_VERIFICATION_ARGS,
+ reply_msg, reply_msg_len,
+ &server_handshake, &server_handshake_len,
+ keys_tmp, keys_tmp_len) < 0) {
+ // XXX TODO free some stuff
+ return -1;
+ }
+
+ if (server_handshake_len > reply_out_maxlen) {
+ // XXX TODO free that stuff
+ return -1;
+ }
+
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN);
+ memcpy(reply_out, server_handshake, server_handshake_len);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ memwipe(server_handshake, 0, server_handshake_len);
+ tor_free(server_handshake);
+
+ r = (int) server_handshake_len;
+ }
+ break;
default:
/* LCOV_EXCL_START
* We should have rejected this far before this point */
tor_free(keys_tmp);
}
return 0;
+ case ONION_HANDSHAKE_TYPE_NTOR_V3: {
+ size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
+ uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
+ uint8_t *server_msg = NULL;
+ size_t server_msg_len = 0;
+ int r = onion_ntor3_client_handshake(
+ handshake_state->u.ntor3,
+ reply, reply_len,
+ NTOR3_VERIFICATION_ARGS,
+ keys_tmp, keys_tmp_len,
+ &server_msg, &server_msg_len);
+ if (r < 0) {
+ tor_free(keys_tmp);
+ tor_free(server_msg);
+ return -1;
+ }
+
+ // XXXX handle the server message!
+ {
+ // XXXX TODO: see what the server said, make sure it's okay, see what
+ // parameters it gave us, make sure we like them, and put them into
+ // `params_out`
+ }
+ tor_free(server_msg);
+
+ memcpy(keys_out, keys_tmp, keys_out_len);
+ memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN);
+ memwipe(keys_tmp, 0, keys_tmp_len);
+ tor_free(keys_tmp);
+
+ return 0;
+ }
default:
log_warn(LD_BUG, "called with unknown handshake state type %d", type);
tor_fragile_assert();