diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-07-05 16:31:38 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-07-05 17:15:50 -0400 |
commit | 63b4ea22af8e8314dd718f02046de5f4b91edf9d (patch) | |
tree | af52b6fba37f22c86447fd5267dd5eb557807c8b /src/or/hs_ntor.c | |
parent | ce84200542f48a92e8b56a8d032401ecd153e90c (diff) | |
download | tor-63b4ea22af8e8314dd718f02046de5f4b91edf9d.tar.gz tor-63b4ea22af8e8314dd718f02046de5f4b91edf9d.zip |
Move literally everything out of src/or
This commit won't build yet -- it just puts everything in a slightly
more logical place.
The reasoning here is that "src/core" will hold the stuff that every (or
nearly every) tor instance will need in order to do onion routing.
Other features (including some necessary ones) will live in
"src/feature". The "src/app" directory will hold the stuff needed
to have Tor be an application you can actually run.
This commit DOES NOT refactor the former contents of src/or into a
logical set of acyclic libraries, or change any code at all. That
will have to come in the future.
We will continue to move things around and split them in the future,
but I hope this lays a reasonable groundwork for doing so.
Diffstat (limited to 'src/or/hs_ntor.c')
-rw-r--r-- | src/or/hs_ntor.c | 620 |
1 files changed, 0 insertions, 620 deletions
diff --git a/src/or/hs_ntor.c b/src/or/hs_ntor.c deleted file mode 100644 index b5007545db..0000000000 --- a/src/or/hs_ntor.c +++ /dev/null @@ -1,620 +0,0 @@ -/* Copyright (c) 2017-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** \file hs_ntor.c - * \brief Implements the ntor variant used in Tor hidden services. - * - * \details - * This module handles the variant of the ntor handshake that is documented in - * section [NTOR-WITH-EXTRA-DATA] of rend-spec-ng.txt . - * - * The functions in this file provide an API that should be used when sending - * or receiving INTRODUCE1/RENDEZVOUS1 cells to generate the various key - * material required to create and handle those cells. - * - * In the case of INTRODUCE1 it provides encryption and MAC keys to - * encode/decode the encrypted blob (see hs_ntor_intro_cell_keys_t). The - * relevant pub functions are hs_ntor_{client,service}_get_introduce1_keys(). - * - * In the case of RENDEZVOUS1 it calculates the MAC required to authenticate - * the cell, and also provides the key seed that is used to derive the crypto - * material for rendezvous encryption (see hs_ntor_rend_cell_keys_t). The - * relevant pub functions are hs_ntor_{client,service}_get_rendezvous1_keys(). - * It also provides a function (hs_ntor_circuit_key_expansion()) that does the - * rendezvous key expansion to setup end-to-end rend circuit keys. - */ - -#include "or/or.h" -#include "lib/crypt_ops/crypto_util.h" -#include "lib/crypt_ops/crypto_curve25519.h" -#include "lib/crypt_ops/crypto_ed25519.h" -#include "or/hs_ntor.h" - -/* String constants used by the ntor HS protocol */ -#define PROTOID "tor-hs-ntor-curve25519-sha3-256-1" -#define PROTOID_LEN (sizeof(PROTOID) - 1) -#define SERVER_STR "Server" -#define SERVER_STR_LEN (sizeof(SERVER_STR) - 1) - -/* Protocol-specific tweaks to our crypto inputs */ -#define T_HSENC PROTOID ":hs_key_extract" -#define T_HSENC_LEN (sizeof(T_HSENC) - 1) -#define T_HSVERIFY PROTOID ":hs_verify" -#define T_HSMAC PROTOID ":hs_mac" -#define M_HSEXPAND PROTOID ":hs_key_expand" -#define M_HSEXPAND_LEN (sizeof(M_HSEXPAND) - 1) - -/************************* Helper functions: *******************************/ - -/** Helper macro: copy <b>len</b> bytes from <b>inp</b> to <b>ptr</b> and - *advance <b>ptr</b> by the number of bytes copied. Stolen from onion_ntor.c */ -#define APPEND(ptr, inp, len) \ - STMT_BEGIN { \ - memcpy(ptr, (inp), (len)); \ - ptr += len; \ - } STMT_END - -/* Length of EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID */ -#define REND_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN * 2 + \ - ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN) -/* Length of auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" */ -#define REND_AUTH_INPUT_LEN (DIGEST256_LEN + ED25519_PUBKEY_LEN + \ - CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN + SERVER_STR_LEN) - -/** Helper function: Compute the last part of the HS ntor handshake which - * derives key material necessary to create and handle RENDEZVOUS1 - * cells. Function used by both client and service. The actual calculations is - * as follows: - * - * NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc) - * verify = MAC(rend_secret_hs_input, t_hsverify) - * auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" - * auth_input_mac = MAC(auth_input, t_hsmac) - * - * where in the above, AUTH_KEY is <b>intro_auth_pubkey</b>, B is - * <b>intro_enc_pubkey</b>, Y is <b>service_ephemeral_rend_pubkey</b>, and X - * is <b>client_ephemeral_enc_pubkey</b>. The provided - * <b>rend_secret_hs_input</b> is of size REND_SECRET_HS_INPUT_LEN. - * - * The final results of NTOR_KEY_SEED and auth_input_mac are placed in - * <b>hs_ntor_rend_cell_keys_out</b>. Return 0 if everything went fine. */ -static int -get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input, - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_public_key_t *service_ephemeral_rend_pubkey, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out) -{ - int bad = 0; - uint8_t ntor_key_seed[DIGEST256_LEN]; - uint8_t ntor_verify[DIGEST256_LEN]; - uint8_t rend_auth_input[REND_AUTH_INPUT_LEN]; - uint8_t rend_cell_auth[DIGEST256_LEN]; - uint8_t *ptr; - - /* Let's build NTOR_KEY_SEED */ - crypto_mac_sha3_256(ntor_key_seed, sizeof(ntor_key_seed), - rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN, - (const uint8_t *)T_HSENC, strlen(T_HSENC)); - bad |= safe_mem_is_zero(ntor_key_seed, DIGEST256_LEN); - - /* Let's build ntor_verify */ - crypto_mac_sha3_256(ntor_verify, sizeof(ntor_verify), - rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN, - (const uint8_t *)T_HSVERIFY, strlen(T_HSVERIFY)); - bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN); - - /* Let's build auth_input: */ - ptr = rend_auth_input; - /* Append ntor_verify */ - APPEND(ptr, ntor_verify, sizeof(ntor_verify)); - /* Append AUTH_KEY */ - APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN); - /* Append B */ - APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append Y */ - APPEND(ptr, - service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append X */ - APPEND(ptr, - client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append PROTOID */ - APPEND(ptr, PROTOID, strlen(PROTOID)); - /* Append "Server" */ - APPEND(ptr, SERVER_STR, strlen(SERVER_STR)); - tor_assert(ptr == rend_auth_input + sizeof(rend_auth_input)); - - /* Let's build auth_input_mac that goes in RENDEZVOUS1 cell */ - crypto_mac_sha3_256(rend_cell_auth, sizeof(rend_cell_auth), - rend_auth_input, sizeof(rend_auth_input), - (const uint8_t *)T_HSMAC, strlen(T_HSMAC)); - bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN); - - { /* Get the computed RENDEZVOUS1 material! */ - memcpy(&hs_ntor_rend_cell_keys_out->rend_cell_auth_mac, - rend_cell_auth, DIGEST256_LEN); - memcpy(&hs_ntor_rend_cell_keys_out->ntor_key_seed, - ntor_key_seed, DIGEST256_LEN); - } - - memwipe(rend_cell_auth, 0, sizeof(rend_cell_auth)); - memwipe(rend_auth_input, 0, sizeof(rend_auth_input)); - memwipe(ntor_key_seed, 0, sizeof(ntor_key_seed)); - - return bad; -} - -/** Length of secret_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID */ -#define INTRO_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN +ED25519_PUBKEY_LEN +\ - CURVE25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN + PROTOID_LEN) -/* Length of info = m_hsexpand | subcredential */ -#define INFO_BLOB_LEN (M_HSEXPAND_LEN + DIGEST256_LEN) -/* Length of KDF input = intro_secret_hs_input | t_hsenc | info */ -#define KDF_INPUT_LEN (INTRO_SECRET_HS_INPUT_LEN + T_HSENC_LEN + INFO_BLOB_LEN) - -/** Helper function: Compute the part of the HS ntor handshake that generates - * key material for creating and handling INTRODUCE1 cells. Function used - * by both client and service. Specifically, calculate the following: - * - * info = m_hsexpand | subcredential - * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN) - * ENC_KEY = hs_keys[0:S_KEY_LEN] - * MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN] - * - * where intro_secret_hs_input is <b>secret_input</b> (of size - * INTRO_SECRET_HS_INPUT_LEN), and <b>subcredential</b> is of size - * DIGEST256_LEN. - * - * If everything went well, fill <b>hs_ntor_intro_cell_keys_out</b> with the - * necessary key material, and return 0. */ -static void -get_introduce1_key_material(const uint8_t *secret_input, - const uint8_t *subcredential, - hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out) -{ - uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN]; - uint8_t info_blob[INFO_BLOB_LEN]; - uint8_t kdf_input[KDF_INPUT_LEN]; - crypto_xof_t *xof; - uint8_t *ptr; - - /* Let's build info */ - ptr = info_blob; - APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND)); - APPEND(ptr, subcredential, DIGEST256_LEN); - tor_assert(ptr == info_blob + sizeof(info_blob)); - - /* Let's build the input to the KDF */ - ptr = kdf_input; - APPEND(ptr, secret_input, INTRO_SECRET_HS_INPUT_LEN); - APPEND(ptr, T_HSENC, strlen(T_HSENC)); - APPEND(ptr, info_blob, sizeof(info_blob)); - tor_assert(ptr == kdf_input + sizeof(kdf_input)); - - /* Now we need to run kdf_input over SHAKE-256 */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)) ; - crypto_xof_free(xof); - - { /* Get the keys */ - memcpy(&hs_ntor_intro_cell_keys_out->enc_key, keystream,CIPHER256_KEY_LEN); - memcpy(&hs_ntor_intro_cell_keys_out->mac_key, - keystream+CIPHER256_KEY_LEN, DIGEST256_LEN); - } - - memwipe(keystream, 0, sizeof(keystream)); - memwipe(kdf_input, 0, sizeof(kdf_input)); -} - -/** Helper function: Calculate the 'intro_secret_hs_input' element used by the - * HS ntor handshake and place it in <b>secret_input_out</b>. This function is - * used by both client and service code. - * - * For the client-side it looks like this: - * - * intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID - * - * whereas for the service-side it looks like this: - * - * intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID - * - * In this function, <b>dh_result</b> carries the EXP() result (and has size - * CURVE25519_OUTPUT_LEN) <b>intro_auth_pubkey</b> is AUTH_KEY, - * <b>client_ephemeral_enc_pubkey</b> is X, and <b>intro_enc_pubkey</b> is B. - */ -static void -get_intro_secret_hs_input(const uint8_t *dh_result, - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - const curve25519_public_key_t *intro_enc_pubkey, - uint8_t *secret_input_out) -{ - uint8_t *ptr; - - /* Append EXP() */ - ptr = secret_input_out; - APPEND(ptr, dh_result, CURVE25519_OUTPUT_LEN); - /* Append AUTH_KEY */ - APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN); - /* Append X */ - APPEND(ptr, client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append B */ - APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append PROTOID */ - APPEND(ptr, PROTOID, strlen(PROTOID)); - tor_assert(ptr == secret_input_out + INTRO_SECRET_HS_INPUT_LEN); -} - -/** Calculate the 'rend_secret_hs_input' element used by the HS ntor handshake - * and place it in <b>rend_secret_hs_input_out</b>. This function is used by - * both client and service code. - * - * The computation on the client side is: - * rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID - * whereas on the service side it is: - * rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID - * - * where: - * <b>dh_result1</b> and <b>dh_result2</b> carry the two EXP() results (of size - * CURVE25519_OUTPUT_LEN) - * <b>intro_auth_pubkey</b> is AUTH_KEY, - * <b>intro_enc_pubkey</b> is B, - * <b>client_ephemeral_enc_pubkey</b> is X, and - * <b>service_ephemeral_rend_pubkey</b> is Y. - */ -static void -get_rend_secret_hs_input(const uint8_t *dh_result1, const uint8_t *dh_result2, - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - const curve25519_public_key_t *service_ephemeral_rend_pubkey, - uint8_t *rend_secret_hs_input_out) -{ - uint8_t *ptr; - - ptr = rend_secret_hs_input_out; - /* Append the first EXP() */ - APPEND(ptr, dh_result1, CURVE25519_OUTPUT_LEN); - /* Append the other EXP() */ - APPEND(ptr, dh_result2, CURVE25519_OUTPUT_LEN); - /* Append AUTH_KEY */ - APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN); - /* Append B */ - APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append X */ - APPEND(ptr, - client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append Y */ - APPEND(ptr, - service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN); - /* Append PROTOID */ - APPEND(ptr, PROTOID, strlen(PROTOID)); - tor_assert(ptr == rend_secret_hs_input_out + REND_SECRET_HS_INPUT_LEN); -} - -/************************* Public functions: *******************************/ - -/* Public function: Do the appropriate ntor calculations and derive the keys - * needed to encrypt and authenticate INTRODUCE1 cells. Return 0 and place the - * final key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went - * well, otherwise return -1; - * - * The relevant calculations are as follows: - * - * intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID - * info = m_hsexpand | subcredential - * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN) - * ENC_KEY = hs_keys[0:S_KEY_LEN] - * MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN] - * - * where: - * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor), - * <b>intro_enc_pubkey</b> is B (also found in HS descriptor), - * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X) - * <b>subcredential</b> is the hidden service subcredential (of size - * DIGEST256_LEN). */ -int -hs_ntor_client_get_introduce1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_keypair_t *client_ephemeral_enc_keypair, - const uint8_t *subcredential, - hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out) -{ - int bad = 0; - uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN]; - uint8_t dh_result[CURVE25519_OUTPUT_LEN]; - - tor_assert(intro_auth_pubkey); - tor_assert(intro_enc_pubkey); - tor_assert(client_ephemeral_enc_keypair); - tor_assert(subcredential); - tor_assert(hs_ntor_intro_cell_keys_out); - - /* Calculate EXP(B,x) */ - curve25519_handshake(dh_result, - &client_ephemeral_enc_keypair->seckey, - intro_enc_pubkey); - bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN); - - /* Get intro_secret_hs_input */ - get_intro_secret_hs_input(dh_result, intro_auth_pubkey, - &client_ephemeral_enc_keypair->pubkey, - intro_enc_pubkey, secret_input); - bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN); - - /* Get ENC_KEY and MAC_KEY! */ - get_introduce1_key_material(secret_input, subcredential, - hs_ntor_intro_cell_keys_out); - - /* Cleanup */ - memwipe(secret_input, 0, sizeof(secret_input)); - if (bad) { - memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t)); - } - - return bad ? -1 : 0; -} - -/* Public function: Do the appropriate ntor calculations and derive the keys - * needed to verify RENDEZVOUS1 cells and encrypt further rendezvous - * traffic. Return 0 and place the final key material in - * <b>hs_ntor_rend_cell_keys_out</b> if everything went well, else return -1. - * - * The relevant calculations are as follows: - * - * rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID - * NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc) - * verify = MAC(rend_secret_hs_input, t_hsverify) - * auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" - * auth_input_mac = MAC(auth_input, t_hsmac) - * - * where: - * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor), - * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X) - * <b>intro_enc_pubkey</b> is B (also found in HS descriptor), - * <b>service_ephemeral_rend_pubkey</b> is Y (SERVER_PK in RENDEZVOUS1 cell) */ -int -hs_ntor_client_get_rendezvous1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *client_ephemeral_enc_keypair, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_public_key_t *service_ephemeral_rend_pubkey, - hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out) -{ - int bad = 0; - uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN]; - uint8_t dh_result1[CURVE25519_OUTPUT_LEN]; - uint8_t dh_result2[CURVE25519_OUTPUT_LEN]; - - tor_assert(intro_auth_pubkey); - tor_assert(client_ephemeral_enc_keypair); - tor_assert(intro_enc_pubkey); - tor_assert(service_ephemeral_rend_pubkey); - tor_assert(hs_ntor_rend_cell_keys_out); - - /* Compute EXP(Y, x) */ - curve25519_handshake(dh_result1, - &client_ephemeral_enc_keypair->seckey, - service_ephemeral_rend_pubkey); - bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN); - - /* Compute EXP(B, x) */ - curve25519_handshake(dh_result2, - &client_ephemeral_enc_keypair->seckey, - intro_enc_pubkey); - bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN); - - /* Get rend_secret_hs_input */ - get_rend_secret_hs_input(dh_result1, dh_result2, - intro_auth_pubkey, intro_enc_pubkey, - &client_ephemeral_enc_keypair->pubkey, - service_ephemeral_rend_pubkey, - rend_secret_hs_input); - - /* Get NTOR_KEY_SEED and the auth_input MAC */ - bad |= get_rendezvous1_key_material(rend_secret_hs_input, - intro_auth_pubkey, - intro_enc_pubkey, - service_ephemeral_rend_pubkey, - &client_ephemeral_enc_keypair->pubkey, - hs_ntor_rend_cell_keys_out); - - memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input)); - if (bad) { - memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t)); - } - - return bad ? -1 : 0; -} - -/* Public function: Do the appropriate ntor calculations and derive the keys - * needed to decrypt and verify INTRODUCE1 cells. Return 0 and place the final - * key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went well, - * otherwise return -1; - * - * The relevant calculations are as follows: - * - * intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID - * info = m_hsexpand | subcredential - * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN) - * HS_DEC_KEY = hs_keys[0:S_KEY_LEN] - * HS_MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN] - * - * where: - * <b>intro_auth_pubkey</b> is AUTH_KEY (introduction point auth key), - * <b>intro_enc_keypair</b> is (b,B) (introduction point encryption keypair), - * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell), - * <b>subcredential</b> is the HS subcredential (of size DIGEST256_LEN) */ -int -hs_ntor_service_get_introduce1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *intro_enc_keypair, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - const uint8_t *subcredential, - hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out) -{ - int bad = 0; - uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN]; - uint8_t dh_result[CURVE25519_OUTPUT_LEN]; - - tor_assert(intro_auth_pubkey); - tor_assert(intro_enc_keypair); - tor_assert(client_ephemeral_enc_pubkey); - tor_assert(subcredential); - tor_assert(hs_ntor_intro_cell_keys_out); - - /* Compute EXP(X, b) */ - curve25519_handshake(dh_result, - &intro_enc_keypair->seckey, - client_ephemeral_enc_pubkey); - bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN); - - /* Get intro_secret_hs_input */ - get_intro_secret_hs_input(dh_result, intro_auth_pubkey, - client_ephemeral_enc_pubkey, - &intro_enc_keypair->pubkey, - secret_input); - bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN); - - /* Get ENC_KEY and MAC_KEY! */ - get_introduce1_key_material(secret_input, subcredential, - hs_ntor_intro_cell_keys_out); - - memwipe(secret_input, 0, sizeof(secret_input)); - if (bad) { - memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t)); - } - - return bad ? -1 : 0; -} - -/* Public function: Do the appropriate ntor calculations and derive the keys - * needed to create and authenticate RENDEZVOUS1 cells. Return 0 and place the - * final key material in <b>hs_ntor_rend_cell_keys_out</b> if all went fine, - * return -1 if error happened. - * - * The relevant calculations are as follows: - * - * rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID - * NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc) - * verify = MAC(rend_secret_hs_input, t_hsverify) - * auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" - * auth_input_mac = MAC(auth_input, t_hsmac) - * - * where: - * <b>intro_auth_pubkey</b> is AUTH_KEY (intro point auth key), - * <b>intro_enc_keypair</b> is (b,B) (intro point enc keypair) - * <b>service_ephemeral_rend_keypair</b> is a fresh (y,Y) keypair - * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell) */ -int -hs_ntor_service_get_rendezvous1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *intro_enc_keypair, - const curve25519_keypair_t *service_ephemeral_rend_keypair, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out) -{ - int bad = 0; - uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN]; - uint8_t dh_result1[CURVE25519_OUTPUT_LEN]; - uint8_t dh_result2[CURVE25519_OUTPUT_LEN]; - - tor_assert(intro_auth_pubkey); - tor_assert(intro_enc_keypair); - tor_assert(service_ephemeral_rend_keypair); - tor_assert(client_ephemeral_enc_pubkey); - tor_assert(hs_ntor_rend_cell_keys_out); - - /* Compute EXP(X, y) */ - curve25519_handshake(dh_result1, - &service_ephemeral_rend_keypair->seckey, - client_ephemeral_enc_pubkey); - bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN); - - /* Compute EXP(X, b) */ - curve25519_handshake(dh_result2, - &intro_enc_keypair->seckey, - client_ephemeral_enc_pubkey); - bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN); - - /* Get rend_secret_hs_input */ - get_rend_secret_hs_input(dh_result1, dh_result2, - intro_auth_pubkey, - &intro_enc_keypair->pubkey, - client_ephemeral_enc_pubkey, - &service_ephemeral_rend_keypair->pubkey, - rend_secret_hs_input); - - /* Get NTOR_KEY_SEED and AUTH_INPUT_MAC! */ - bad |= get_rendezvous1_key_material(rend_secret_hs_input, - intro_auth_pubkey, - &intro_enc_keypair->pubkey, - &service_ephemeral_rend_keypair->pubkey, - client_ephemeral_enc_pubkey, - hs_ntor_rend_cell_keys_out); - - memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input)); - if (bad) { - memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t)); - } - - return bad ? -1 : 0; -} - -/** Given a received RENDEZVOUS2 MAC in <b>mac</b> (of length DIGEST256_LEN), - * and the RENDEZVOUS1 key material in <b>hs_ntor_rend_cell_keys</b>, return 1 - * if the MAC is good, otherwise return 0. */ -int -hs_ntor_client_rendezvous2_mac_is_good( - const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys, - const uint8_t *rcvd_mac) -{ - tor_assert(rcvd_mac); - tor_assert(hs_ntor_rend_cell_keys); - - return tor_memeq(hs_ntor_rend_cell_keys->rend_cell_auth_mac, - rcvd_mac, DIGEST256_LEN); -} - -/* Input length to KDF for key expansion */ -#define NTOR_KEY_EXPANSION_KDF_INPUT_LEN (DIGEST256_LEN + M_HSEXPAND_LEN) - -/** Given the rendezvous key seed in <b>ntor_key_seed</b> (of size - * DIGEST256_LEN), do the circuit key expansion as specified by section - * '4.2.1. Key expansion' and place the keys in <b>keys_out</b> (which must be - * of size HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN). - * - * Return 0 if things went well, else return -1. */ -int -hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len, - uint8_t *keys_out, size_t keys_out_len) -{ - uint8_t *ptr; - uint8_t kdf_input[NTOR_KEY_EXPANSION_KDF_INPUT_LEN]; - crypto_xof_t *xof; - - /* Sanity checks on lengths to make sure we are good */ - if (BUG(seed_len != DIGEST256_LEN)) { - return -1; - } - if (BUG(keys_out_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) { - return -1; - } - - /* Let's build the input to the KDF */ - ptr = kdf_input; - APPEND(ptr, ntor_key_seed, DIGEST256_LEN); - APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND)); - tor_assert(ptr == kdf_input + sizeof(kdf_input)); - - /* Generate the keys */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); - crypto_xof_squeeze_bytes(xof, keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN); - crypto_xof_free(xof); - - return 0; -} |