[tor-commits] [tor/release-0.4.5] Merge branch 'ticket40237_035_01' into ticket40237_043_01

asn at torproject.org asn at torproject.org
Tue Jan 12 16:13:25 UTC 2021


commit 60da5d62225c975842ef57195b7243baa7033acb
Merge: 4b39f46a61 04b0263974
Author: David Goulet <dgoulet at torproject.org>
Date:   Tue Jan 12 10:46:25 2021 -0500

    Merge branch 'ticket40237_035_01' into ticket40237_043_01

 changes/ticket40237                          |  5 ++++
 src/core/mainloop/mainloop.c                 |  3 ++-
 src/feature/hs/hs_cache.c                    |  5 +++-
 src/feature/hs/hs_client.c                   |  8 ++++---
 src/feature/hs/hs_common.c                   | 12 +++++++---
 src/feature/hs/hs_service.c                  |  7 ++++--
 src/feature/hs_common/shared_random_client.c | 23 ++++++++++++------
 src/feature/nodelist/nodelist.c              |  2 +-
 src/test/test_hs_cache.c                     |  7 +++---
 src/test/test_hs_client.c                    | 34 +++++++++++++-------------
 src/test/test_hs_common.c                    | 36 ++++++++++++++++++----------
 src/test/test_hs_service.c                   | 21 ++++++++--------
 src/test/test_shared_random.c                | 22 +++++++++++++----
 13 files changed, 121 insertions(+), 64 deletions(-)

diff --cc src/test/test_hs_client.c
index 945f631459,53ee3c53d2..32a79a7f49
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@@ -1100,382 -985,9 +1102,382 @@@ test_close_intro_circuits_new_desc(voi
    hs_descriptor_free(desc1);
    hs_descriptor_free(desc2);
    hs_free_all();
-   UNMOCK(networkstatus_get_live_consensus);
+   UNMOCK(networkstatus_get_reasonably_live_consensus);
  }
  
 +static void
 +test_close_intro_circuits_cache_clean(void *arg)
 +{
 +  int ret;
 +  ed25519_keypair_t service_kp;
 +  circuit_t *circ = NULL;
 +  origin_circuit_t *ocirc = NULL;
 +  hs_descriptor_t *desc1 = NULL;
 +
 +  (void) arg;
 +
 +  hs_init();
 +  rend_cache_init();
 +
 +  /* This is needed because of the client cache expiration timestamp is based
 +   * on having a consensus. See cached_client_descriptor_has_expired(). */
 +  MOCK(networkstatus_get_live_consensus,
 +       mock_networkstatus_get_live_consensus);
 +
 +  /* Set consensus time */
 +  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
 +                     &mock_ns.valid_after);
 +  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
 +                     &mock_ns.fresh_until);
 +  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
 +                     &mock_ns.valid_until);
 +
 +  /* Generate service keypair */
 +  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
 +
 +  /* Create and add to the global list a dummy client introduction circuits.
 +   * We'll then make sure the hs_ident is attached to a dummy descriptor. */
 +  circ = dummy_origin_circuit_new(0);
 +  tt_assert(circ);
 +  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
 +  ocirc = TO_ORIGIN_CIRCUIT(circ);
 +
 +  /* Build the first descriptor and cache it. */
 +  {
 +    char *encoded;
 +    desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
 +    tt_assert(desc1);
 +    ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
 +    tt_int_op(ret, OP_EQ, 0);
 +    tt_assert(encoded);
 +
 +    /* Store it */
 +    ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
 +    tt_int_op(ret, OP_EQ, 0);
 +    tor_free(encoded);
 +    tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
 +  }
 +
 +  /* We'll pick one introduction point and associate it with the circuit. */
 +  {
 +    const hs_desc_intro_point_t *ip =
 +      smartlist_get(desc1->encrypted_data.intro_points, 0);
 +    tt_assert(ip);
 +    ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
 +    ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
 +                        &ip->auth_key_cert->signed_key);
 +  }
 +
 +  /* Before we are about to clean up the intro circuits, make sure it is
 +   * actually there. */
 +  tt_assert(circuit_get_next_intro_circ(NULL, true));
 +
 +  /* Cleanup the client cache. The ns valid after time is what decides if the
 +   * descriptor has expired so put it in the future enough (72h) so we are
 +   * sure to always expire. */
 +  mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60);
 +  hs_cache_clean_as_client(0);
 +
 +  /* Once stored, our intro circuit should be closed because it is related to
 +   * an old introduction point that doesn't exists anymore. */
 +  tt_assert(!circuit_get_next_intro_circ(NULL, true));
 +
 + done:
 +  circuit_free(circ);
 +  hs_descriptor_free(desc1);
 +  hs_free_all();
 +  rend_cache_free_all();
 +  UNMOCK(networkstatus_get_live_consensus);
 +}
 +
 +static void
 +test_socks_hs_errors(void *arg)
 +{
 +  int ret;
 +  char *desc_encoded = NULL;
 +  ed25519_keypair_t service_kp;
 +  ed25519_keypair_t signing_kp;
 +  entry_connection_t *socks_conn = NULL;
 +  dir_connection_t *dir_conn = NULL;
 +  hs_descriptor_t *desc = NULL;
 +  uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
 +
 +  (void) arg;
 +
 +  MOCK(networkstatus_get_live_consensus,
 +       mock_networkstatus_get_live_consensus);
 +  MOCK(connection_mark_unattached_ap_,
 +       mock_connection_mark_unattached_ap_no_close);
 +  MOCK(read_file_to_str, mock_read_file_to_str);
 +  MOCK(tor_listdir, mock_tor_listdir);
 +  MOCK(check_private_dir, mock_check_private_dir);
 +
 +    /* Set consensus time */
 +  parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
 +                           &mock_ns.valid_after);
 +  parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
 +                           &mock_ns.fresh_until);
 +  parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
 +                           &mock_ns.valid_until);
 +
 +  hs_init();
 +
 +  ret = ed25519_keypair_generate(&service_kp, 0);
 +  tt_int_op(ret, OP_EQ, 0);
 +  ret = ed25519_keypair_generate(&signing_kp, 0);
 +  tt_int_op(ret, OP_EQ, 0);
 +
 +  socks_conn = helper_build_socks_connection(&service_kp.pubkey,
 +                                             AP_CONN_STATE_RENDDESC_WAIT);
 +  tt_assert(socks_conn);
 +
 +  /* Create directory connection. */
 +  dir_conn = dir_connection_new(AF_INET);
 +  dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
 +  TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
 +  ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_kp.pubkey);
 +
 +  /* Encode descriptor so we can decode it. */
 +  desc = hs_helper_build_hs_desc_with_ip(&service_kp);
 +  tt_assert(desc);
 +
 +  crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
 +  ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
 +                                  &desc_encoded);
 +  tt_int_op(ret, OP_EQ, 0);
 +  tt_assert(desc_encoded);
 +
 +  /* Try decoding. Point this to an existing descriptor. The following should
 +   * fail thus the desc_out should be set to NULL. */
 +  hs_descriptor_t *desc_out = desc;
 +  ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
 +                                    &desc_out);
 +  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
 +  tt_assert(desc_out == NULL);
 +
 +  /* The caching will fail to decrypt because the descriptor_cookie used above
 +   * is not known to the HS subsystem. This will lead to a missing client
 +   * auth. */
 +  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
 +
 +  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
 +            SOCKS5_HS_MISSING_CLIENT_AUTH);
 +
 +  /* Add in the global client auth list bad creds for this service. */
 +  helper_add_random_client_auth(&service_kp.pubkey);
 +
 +  ret = hs_client_decode_descriptor(desc_encoded, &service_kp.pubkey,
 +                                    &desc_out);
 +  tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
 +  tt_assert(desc_out == NULL);
 +
 +  /* Simmulate a fetch done again. This should replace the cached descriptor
 +   * and signal a bad client authorization. */
 +  hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
 +  tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
 +            SOCKS5_HS_BAD_CLIENT_AUTH);
 +
 + done:
 +  connection_free_minimal(ENTRY_TO_CONN(socks_conn));
 +  connection_free_minimal(TO_CONN(dir_conn));
 +  hs_descriptor_free(desc);
 +  tor_free(desc_encoded);
 +
 +  hs_free_all();
 +
 +  UNMOCK(networkstatus_get_live_consensus);
 +  UNMOCK(connection_mark_unattached_ap_);
 +  UNMOCK(read_file_to_str);
 +  UNMOCK(tor_listdir);
 +  UNMOCK(check_private_dir);
 +}
 +
 +static void
 +test_close_intro_circuit_failure(void *arg)
 +{
 +  char digest[DIGEST_LEN];
 +  circuit_t *circ = NULL;
 +  ed25519_keypair_t service_kp, intro_kp;
 +  origin_circuit_t *ocirc = NULL;
 +  tor_addr_t addr;
 +  const hs_cache_intro_state_t *entry;
 +
 +  (void) arg;
 +
 +  hs_init();
 +
 +  /* Generate service keypair */
 +  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
 +  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&intro_kp, 0));
 +
 +  /* Create and add to the global list a dummy client introduction circuit at
 +   * the ACK WAIT state. */
 +  circ = dummy_origin_circuit_new(0);
 +  tt_assert(circ);
 +  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
 +  ocirc = TO_ORIGIN_CIRCUIT(circ);
 +  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
 +  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
 +  /* Code path will log this exit so build it. */
 +  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
 +                                                    NULL, NULL, NULL, &addr,
 +                                                    4242);
 +  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
 +
 +  /* We'll make for close the circuit for a timeout failure. It should _NOT_
 +   * end up in the failure cache just yet. We do that on free() only. */
 +  circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
 +  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
 +                                              &intro_kp.pubkey));
 +  /* Time to free. It should get removed. */
 +  circuit_free(circ);
 +  entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
 +                                           &intro_kp.pubkey);
 +  tt_assert(entry);
 +  tt_uint_op(entry->timed_out, OP_EQ, 1);
 +  hs_cache_client_intro_state_purge();
 +
 +  /* Again, create and add to the global list a dummy client introduction
 +   * circuit at the INTRODUCING state. */
 +  circ = dummy_origin_circuit_new(0);
 +  tt_assert(circ);
 +  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
 +  ocirc = TO_ORIGIN_CIRCUIT(circ);
 +  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
 +  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
 +  /* Code path will log this exit so build it. */
 +  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
 +                                                    NULL, NULL, NULL, &addr,
 +                                                    4242);
 +  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
 +
 +  /* On free, we should get an unreachable failure. */
 +  circuit_free(circ);
 +  entry = hs_cache_client_intro_state_find(&service_kp.pubkey,
 +                                           &intro_kp.pubkey);
 +  tt_assert(entry);
 +  tt_uint_op(entry->unreachable_count, OP_EQ, 1);
 +  hs_cache_client_intro_state_purge();
 +
 +  /* Again, create and add to the global list a dummy client introduction
 +   * circuit at the INTRODUCING state but we'll close it for timeout. It
 +   * should not be noted as a timeout failure. */
 +  circ = dummy_origin_circuit_new(0);
 +  tt_assert(circ);
 +  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
 +  ocirc = TO_ORIGIN_CIRCUIT(circ);
 +  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
 +  ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
 +  /* Code path will log this exit so build it. */
 +  ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
 +                                                    NULL, NULL, NULL, &addr,
 +                                                    4242);
 +  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
 +
 +  circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
 +  circuit_free(circ);
 +  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
 +                                              &intro_kp.pubkey));
 +
 +  /* Again, create and add to the global list a dummy client introduction
 +   * circuit at the INTRODUCING state but without a chosen_exit. In theory, it
 +   * can not happen but we'll make sure it doesn't end up in the failure cache
 +   * anyway. */
 +  circ = dummy_origin_circuit_new(0);
 +  tt_assert(circ);
 +  circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
 +  ocirc = TO_ORIGIN_CIRCUIT(circ);
 +  ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
 +  ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk, &intro_kp.pubkey);
 +
 +  circuit_free(circ);
 +  tt_assert(!hs_cache_client_intro_state_find(&service_kp.pubkey,
 +                                              &intro_kp.pubkey));
 +
 + done:
 +  circuit_free(circ);
 +  hs_free_all();
 +}
 +
 +static void
 +test_purge_ephemeral_client_auth(void *arg)
 +{
 +  ed25519_keypair_t service_kp;
 +  hs_client_service_authorization_t *auth = NULL;
 +  hs_client_register_auth_status_t status;
 +
 +  (void) arg;
 +
 +  /* We will try to write on disk client credentials. */
 +  MOCK(check_private_dir, mock_check_private_dir);
 +  MOCK(get_options, mock_get_options);
 +  MOCK(write_str_to_file, mock_write_str_to_file);
 +
 +  /* Boggus directory so when we try to write the permanent client
 +   * authorization data to disk, we don't fail. See
 +   * store_permanent_client_auth_credentials() for more details. */
 +  mocked_options.ClientOnionAuthDir = tor_strdup("auth_dir");
 +
 +  hs_init();
 +
 +  /* Generate service keypair */
 +  tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
 +
 +  /* Generate a client authorization object. */
 +  auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
 +
 +  /* Set it up. No flags meaning it is ephemeral. */
 +  curve25519_secret_key_generate(&auth->enc_seckey, 0);
 +  hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
 +  auth->flags = 0;
 +
 +  /* Confirm that there is nothing in the client auth map. It is unallocated
 +   * until we add the first entry. */
 +  tt_assert(!get_hs_client_auths_map());
 +
 +  /* Add an entry to the client auth list. We loose ownership of the auth
 +   * object so nullify it. */
 +  status = hs_client_register_auth_credentials(auth);
 +  auth = NULL;
 +  tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
 +
 +  /* We should have the entry now. */
 +  digest256map_t *client_auths = get_hs_client_auths_map();
 +  tt_assert(client_auths);
 +  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
 +
 +  /* Purge the cache that should remove all ephemeral values. */
 +  purge_ephemeral_client_auth();
 +  tt_int_op(digest256map_size(client_auths), OP_EQ, 0);
 +
 +  /* Now add a new authorization object but permanent. */
 +  /* Generate a client authorization object. */
 +  auth = tor_malloc_zero(sizeof(hs_client_service_authorization_t));
 +  curve25519_secret_key_generate(&auth->enc_seckey, 0);
 +  hs_build_address(&service_kp.pubkey, HS_VERSION_THREE, auth->onion_address);
 +  auth->flags = CLIENT_AUTH_FLAG_IS_PERMANENT;
 +
 +  /* Add an entry to the client auth list. We loose ownership of the auth
 +   * object so nullify it. */
 +  status = hs_client_register_auth_credentials(auth);
 +  auth = NULL;
 +  tt_int_op(status, OP_EQ, REGISTER_SUCCESS);
 +  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
 +
 +  /* Purge again, the entry should still be there. */
 +  purge_ephemeral_client_auth();
 +  tt_int_op(digest256map_size(client_auths), OP_EQ, 1);
 +
 + done:
 +  client_service_authorization_free(auth);
 +  hs_free_all();
 +  tor_free(mocked_options.ClientOnionAuthDir);
 +
 +  UNMOCK(check_private_dir);
 +  UNMOCK(get_options);
 +  UNMOCK(write_str_to_file);
 +}
 +
  struct testcase_t hs_client_tests[] = {
    { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
      TT_FORK, NULL, NULL },
diff --cc src/test/test_hs_service.c
index e33d593d94,c60ab6c930..49c8d29d27
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@@ -1454,10 -1409,10 +1455,10 @@@ test_build_update_descriptors(void *arg
  
    MOCK(get_or_state,
         get_or_state_replacement);
-   MOCK(networkstatus_get_live_consensus,
-        mock_networkstatus_get_live_consensus);
+   MOCK(networkstatus_get_reasonably_live_consensus,
+        mock_networkstatus_get_reasonably_live_consensus);
  
 -  dummy_state = tor_malloc_zero(sizeof(or_state_t));
 +  dummy_state = or_state_new();
  
    ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
                             &mock_ns.valid_after);
@@@ -1685,10 -1634,10 +1686,10 @@@ test_build_descriptors(void *arg
  
    MOCK(get_or_state,
         get_or_state_replacement);
-   MOCK(networkstatus_get_live_consensus,
-        mock_networkstatus_get_live_consensus);
+   MOCK(networkstatus_get_reasonably_live_consensus,
+        mock_networkstatus_get_reasonably_live_consensus);
  
 -  dummy_state = tor_malloc_zero(sizeof(or_state_t));
 +  dummy_state = or_state_new();
  
    ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
                             &mock_ns.valid_after);
@@@ -1786,10 -1715,10 +1787,10 @@@ test_upload_descriptors(void *arg
    hs_init();
    MOCK(get_or_state,
         get_or_state_replacement);
-   MOCK(networkstatus_get_live_consensus,
-        mock_networkstatus_get_live_consensus);
+   MOCK(networkstatus_get_reasonably_live_consensus,
+        mock_networkstatus_get_reasonably_live_consensus);
  
 -  dummy_state = tor_malloc_zero(sizeof(or_state_t));
 +  dummy_state = or_state_new();
  
    ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
                             &mock_ns.valid_after);





More information about the tor-commits mailing list