/** 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; }
/** We received an ESTABLISH_INTRO <b>cell</b>. Verify its signature and MAC, * given <b>circuit_key_material</b>. Return 0 on success else -1 on error. */ STATIC int verify_establish_intro_cell(const trn_cell_establish_intro_t *cell, const uint8_t *circuit_key_material, size_t circuit_key_material_len) { /* We only reach this function if the first byte of the cell is 0x02 which * means that auth_key_type is of ed25519 type, hence this check should * always pass. See hs_intro_received_establish_intro(). */ if (BUG(cell->auth_key_type != HS_INTRO_AUTH_KEY_TYPE_ED25519)) { return -1; } /* Make sure the auth key length is of the right size for this type. For * EXTRA safety, we check both the size of the array and the length which * must be the same. Safety first!*/ if (trn_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN || trn_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "ESTABLISH_INTRO auth key length is invalid"); return -1; } const uint8_t *msg = cell->start_cell; /* Verify the sig */ { ed25519_signature_t sig_struct; const uint8_t *sig_array = trn_cell_establish_intro_getconstarray_sig(cell); /* Make sure the signature length is of the right size. For EXTRA safety, * we check both the size of the array and the length which must be the * same. Safety first!*/ if (trn_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig) || trn_cell_establish_intro_get_sig_len(cell) != sizeof(sig_struct.sig)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "ESTABLISH_INTRO sig len is invalid"); return -1; } /* We are now sure that sig_len is of the right size. */ memcpy(sig_struct.sig, sig_array, cell->sig_len); ed25519_public_key_t auth_key; get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, cell); const size_t sig_msg_len = cell->end_sig_fields - msg; int sig_mismatch = ed25519_checksig_prefixed(&sig_struct, msg, sig_msg_len, ESTABLISH_INTRO_SIG_PREFIX, &auth_key); if (sig_mismatch) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "ESTABLISH_INTRO signature not as expected"); return -1; } } /* Verify the MAC */ { const size_t auth_msg_len = cell->end_mac_fields - msg; uint8_t mac[DIGEST256_LEN]; crypto_mac_sha3_256(mac, sizeof(mac), circuit_key_material, circuit_key_material_len, msg, auth_msg_len); if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "ESTABLISH_INTRO handshake_auth not as expected"); return -1; } } return 0; }