static void test_fast_handshake(void *arg) { /* tests for the obsolete "CREATE_FAST" handshake. */ (void) arg; fast_handshake_state_t *state = NULL; uint8_t client_handshake[CREATE_FAST_LEN]; uint8_t server_handshake[CREATED_FAST_LEN]; uint8_t s_keys[100], c_keys[100]; /* First, test an entire handshake. */ memset(client_handshake, 0, sizeof(client_handshake)); tt_int_op(0, OP_EQ, fast_onionskin_create(&state, client_handshake)); tt_assert(! tor_mem_is_zero((char*)client_handshake, sizeof(client_handshake))); tt_int_op(0, OP_EQ, fast_server_handshake(client_handshake, server_handshake, s_keys, 100)); const char *msg = NULL; tt_int_op(0, OP_EQ, fast_client_handshake(state, server_handshake, c_keys, 100, &msg)); tt_ptr_op(msg, OP_EQ, NULL); tt_mem_op(s_keys, OP_EQ, c_keys, 100); /* Now test a failing handshake. */ server_handshake[0] ^= 3; tt_int_op(-1, OP_EQ, fast_client_handshake(state, server_handshake, c_keys, 100, &msg)); tt_str_op(msg, OP_EQ, "Digest DOES NOT MATCH on fast handshake. " "Bug or attack."); done: fast_handshake_state_free(state); }
/** 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 * <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 usre about. */ 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 *rend_authenticator_out, const char **msg_out) { if (handshake_state->tag != type) return -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (reply_len != TAP_ONIONSKIN_REPLY_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (onion_skin_TAP_client_handshake(handshake_state->u.tap, (const char*)reply, (char *)keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_FAST: if (reply_len != CREATED_FAST_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (fast_client_handshake(handshake_state->u.fast, reply, keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_NTOR: if (reply_len < NTOR_REPLY_LEN) { if (msg_out) *msg_out = "ntor reply was not of the correct length."; return -1; } { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_tmp_len); if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, reply, keys_tmp, keys_tmp_len, msg_out) < 0) { 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); 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(); return -1; } }