/** 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; }
/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS * circuitmap is maintained properly. */ static void test_intro_point_registration(void *arg) { int retval; hs_circuitmap_ht *the_hs_circuitmap = NULL; or_circuit_t *intro_circ = NULL; trn_cell_establish_intro_t *establish_intro_cell = NULL; ed25519_public_key_t auth_key; crypto_pk_t *legacy_auth_key = NULL; or_circuit_t *legacy_intro_circ = NULL; or_circuit_t *returned_intro_circ = NULL; (void) arg; MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell); hs_circuitmap_init(); /* Check that the circuitmap is currently empty */ { the_hs_circuitmap = get_hs_circuitmap(); tt_assert(the_hs_circuitmap); tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap)); /* Do a circuitmap query in any case */ returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); tt_ptr_op(returned_intro_circ, OP_EQ, NULL); } /* Create a v3 intro point */ { intro_circ = or_circuit_new(0, NULL); tt_assert(intro_circ); establish_intro_cell = helper_establish_intro_v3(intro_circ); /* Check that the intro point was registered on the HS circuitmap */ the_hs_circuitmap = get_hs_circuitmap(); tt_assert(the_hs_circuitmap); tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap)); get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, establish_intro_cell); returned_intro_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ); } /* Create a v2 intro point */ { char key_digest[DIGEST_LEN]; legacy_intro_circ = or_circuit_new(1, NULL); tt_assert(legacy_intro_circ); legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ); tt_assert(legacy_auth_key); /* Check that the circuitmap now has two elements */ the_hs_circuitmap = get_hs_circuitmap(); tt_assert(the_hs_circuitmap); tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap)); /* Check that the new element is our legacy intro circuit. */ retval = crypto_pk_get_digest(legacy_auth_key, key_digest); tt_int_op(retval, OP_EQ, 0); returned_intro_circ = hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest); tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ); } /* XXX Continue test and try to register a second v3 intro point with the * same auth key. Make sure that old intro circuit gets closed. */ done: crypto_pk_free(legacy_auth_key); circuit_free_(TO_CIRCUIT(intro_circ)); circuit_free_(TO_CIRCUIT(legacy_intro_circ)); trn_cell_establish_intro_free(establish_intro_cell); test_circuitmap_free_all(); UNMOCK(hs_intro_send_intro_established_cell); }