LCOV - code coverage report
Current view: top level - test - test_hs_control.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 452 453 99.8 %
Date: 2021-11-24 03:28:48 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : /**
       5             :  * \file test_hs_control.c
       6             :  * \brief Unit tests for hidden service control port event and command.
       7             :  **/
       8             : 
       9             : #define CONTROL_EVENTS_PRIVATE
      10             : #define CONTROL_CMD_PRIVATE
      11             : #define HS_CLIENT_PRIVATE
      12             : #define HS_SERVICE_PRIVATE
      13             : 
      14             : #include "core/or/or.h"
      15             : #include "test/test.h"
      16             : #include "test/test_helpers.h"
      17             : #include "core/mainloop/connection.h"
      18             : #include "feature/control/control.h"
      19             : #include "feature/control/control_cmd.h"
      20             : #include "feature/control/control_events.h"
      21             : #include "feature/control/control_fmt.h"
      22             : #include "feature/control/control_connection_st.h"
      23             : #include "app/config/config.h"
      24             : #include "feature/hs/hs_common.h"
      25             : #include "feature/hs/hs_client.h"
      26             : #include "feature/hs/hs_control.h"
      27             : #include "feature/nodelist/nodelist.h"
      28             : 
      29             : #include "feature/nodelist/node_st.h"
      30             : #include "feature/nodelist/routerstatus_st.h"
      31             : #include "lib/container/smartlist.h"
      32             : #include "lib/crypt_ops/crypto_format.h"
      33             : 
      34             : #ifdef HAVE_SYS_STAT_H
      35             : #include <sys/stat.h>
      36             : #endif
      37             : 
      38             : #ifdef _WIN32
      39             : /* For mkdir() */
      40             : #include <direct.h>
      41             : #else
      42             : #include <dirent.h>
      43             : #endif /* defined(_WIN32) */
      44             : 
      45             : /* mock ID digest and longname for node that's in nodelist */
      46             : #define HSDIR_EXIST_ID \
      47             :   "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \
      48             :   "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
      49             : #define STR_HSDIR_EXIST_LONGNAME \
      50             :   "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir"
      51             : #define STR_HSDIR_NONE_EXIST_LONGNAME \
      52             :   "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
      53             : 
      54             : /* Helper global variable for hidden service descriptor event test.
      55             :  * It's used as a pointer to dynamically created message buffer in
      56             :  * send_control_event_string_replacement function, which mocks
      57             :  * send_control_event_string function.
      58             :  *
      59             :  * Always free it after use! */
      60             : static char *received_msg = NULL;
      61             : 
      62             : /** Mock function for send_control_event_string
      63             :  */
      64             : static void
      65           6 : queue_control_event_string_replacement(uint16_t event, char *msg)
      66             : {
      67           6 :   (void) event;
      68           6 :   tor_free(received_msg);
      69           6 :   received_msg = msg;
      70           6 : }
      71             : 
      72             : /** Mock function for node_describe_longname_by_id, it returns either
      73             :  * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME
      74             :  */
      75             : static const char *
      76           5 : node_describe_longname_by_id_replacement(const char *id_digest)
      77             : {
      78           5 :   if (!strcmp(id_digest, HSDIR_EXIST_ID)) {
      79             :     return STR_HSDIR_EXIST_LONGNAME;
      80             :   } else {
      81           0 :     return STR_HSDIR_NONE_EXIST_LONGNAME;
      82             :   }
      83             : }
      84             : 
      85             : /* HSDir fetch index is a series of 'D' */
      86             : #define HSDIR_INDEX_FETCH_HEX \
      87             :   "4343434343434343434343434343434343434343434343434343434343434343"
      88             : #define HSDIR_INDEX_STORE_HEX \
      89             :   "4444444444444444444444444444444444444444444444444444444444444444"
      90             : 
      91             : static const node_t *
      92           1 : mock_node_get_by_id(const char *digest)
      93             : {
      94           1 :   static node_t node;
      95           1 :   memcpy(node.identity, digest, DIGEST_LEN);
      96           1 :   memset(node.hsdir_index.fetch, 'C', DIGEST256_LEN);
      97           1 :   memset(node.hsdir_index.store_first, 'D', DIGEST256_LEN);
      98           1 :   return &node;
      99             : }
     100             : 
     101             : static void
     102           1 : test_hs_desc_event(void *arg)
     103             : {
     104           1 :   int ret;
     105           1 :   char *expected_msg = NULL;
     106           1 :   char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
     107           1 :   ed25519_keypair_t identity_kp;
     108           1 :   ed25519_public_key_t blinded_pk;
     109           1 :   char base64_blinded_pk[ED25519_BASE64_LEN + 1];
     110           1 :   routerstatus_t hsdir_rs;
     111           1 :   hs_ident_dir_conn_t ident;
     112             : 
     113           1 :   (void) arg;
     114           1 :   MOCK(queue_control_event_string,
     115             :        queue_control_event_string_replacement);
     116           1 :   MOCK(node_describe_longname_by_id,
     117             :        node_describe_longname_by_id_replacement);
     118           1 :   MOCK(node_get_by_id, mock_node_get_by_id);
     119             : 
     120             :   /* Setup what we need for this test. */
     121           1 :   ed25519_keypair_generate(&identity_kp, 0);
     122           1 :   hs_build_address(&identity_kp.pubkey, HS_VERSION_THREE, onion_address);
     123           1 :   ret = hs_address_is_valid(onion_address);
     124           1 :   tt_int_op(ret, OP_EQ, 1);
     125           1 :   memset(&blinded_pk, 'B', sizeof(blinded_pk));
     126           1 :   memset(&hsdir_rs, 0, sizeof(hsdir_rs));
     127           1 :   memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN);
     128           1 :   ed25519_public_to_base64(base64_blinded_pk, &blinded_pk);
     129           1 :   memcpy(&ident.identity_pk, &identity_kp.pubkey,
     130             :          sizeof(ed25519_public_key_t));
     131           1 :   memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk));
     132             : 
     133             :   /* HS_DESC REQUESTED ... */
     134           1 :   hs_control_desc_event_requested(&identity_kp.pubkey, base64_blinded_pk,
     135             :                                   &hsdir_rs);
     136           1 :   tor_asprintf(&expected_msg, "650 HS_DESC REQUESTED %s NO_AUTH "
     137             :                STR_HSDIR_EXIST_LONGNAME " %s HSDIR_INDEX="
     138             :                HSDIR_INDEX_FETCH_HEX "\r\n",
     139             :                onion_address, base64_blinded_pk);
     140           1 :   tt_assert(received_msg);
     141           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     142           1 :   tor_free(received_msg);
     143           1 :   tor_free(expected_msg);
     144             : 
     145             :   /* HS_DESC CREATED... */
     146           1 :   hs_control_desc_event_created(onion_address, &blinded_pk);
     147           1 :   tor_asprintf(&expected_msg, "650 HS_DESC CREATED %s UNKNOWN "
     148             :                               "UNKNOWN %s\r\n",
     149             :                onion_address, base64_blinded_pk);
     150           1 :   tt_assert(received_msg);
     151           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     152           1 :   tor_free(received_msg);
     153           1 :   tor_free(expected_msg);
     154             : 
     155             :   /* HS_DESC UPLOAD... */
     156           1 :   uint8_t hsdir_index_store[DIGEST256_LEN];
     157           1 :   memset(hsdir_index_store, 'D', sizeof(hsdir_index_store));
     158           1 :   hs_control_desc_event_upload(onion_address, HSDIR_EXIST_ID,
     159             :                                &blinded_pk, hsdir_index_store);
     160           1 :   tor_asprintf(&expected_msg, "650 HS_DESC UPLOAD %s UNKNOWN "
     161             :                               STR_HSDIR_EXIST_LONGNAME " %s "
     162             :                               "HSDIR_INDEX=" HSDIR_INDEX_STORE_HEX "\r\n",
     163             :                onion_address, base64_blinded_pk);
     164           1 :   tt_assert(received_msg);
     165           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     166           1 :   tor_free(received_msg);
     167           1 :   tor_free(expected_msg);
     168             : 
     169             :   /* HS_DESC FAILED... */
     170           1 :   hs_control_desc_event_failed(&ident, HSDIR_EXIST_ID, "BAD_DESC");
     171           1 :   tor_asprintf(&expected_msg, "650 HS_DESC FAILED %s NO_AUTH "
     172             :                               STR_HSDIR_EXIST_LONGNAME " %s "
     173             :                               "REASON=BAD_DESC\r\n",
     174             :                onion_address, base64_blinded_pk);
     175           1 :   tt_assert(received_msg);
     176           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     177           1 :   tor_free(received_msg);
     178           1 :   tor_free(expected_msg);
     179             : 
     180             :   /* HS_DESC RECEIVED... */
     181           1 :   hs_control_desc_event_received(&ident, HSDIR_EXIST_ID);
     182           1 :   tor_asprintf(&expected_msg, "650 HS_DESC RECEIVED %s NO_AUTH "
     183             :                               STR_HSDIR_EXIST_LONGNAME " %s\r\n",
     184             :                onion_address, base64_blinded_pk);
     185           1 :   tt_assert(received_msg);
     186           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     187           1 :   tor_free(received_msg);
     188           1 :   tor_free(expected_msg);
     189             : 
     190             :   /* HS_DESC UPLOADED... */
     191           1 :   hs_control_desc_event_uploaded(&ident, HSDIR_EXIST_ID);
     192           1 :   tor_asprintf(&expected_msg, "650 HS_DESC UPLOADED %s UNKNOWN "
     193             :                               STR_HSDIR_EXIST_LONGNAME "\r\n",
     194             :                onion_address);
     195           1 :   tt_assert(received_msg);
     196           1 :   tt_str_op(received_msg, OP_EQ, expected_msg);
     197           1 :   tor_free(received_msg);
     198           1 :   tor_free(expected_msg);
     199             : 
     200           1 :  done:
     201           1 :   UNMOCK(queue_control_event_string);
     202           1 :   UNMOCK(node_describe_longname_by_id);
     203           1 :   UNMOCK(node_get_by_id);
     204           1 :   tor_free(received_msg);
     205           1 :   tor_free(expected_msg);
     206           1 : }
     207             : 
     208             : /** Test that we can correctly add, remove and view client auth credentials
     209             :  *  using the control port. */
     210             : static void
     211           1 : test_hs_control_good_onion_client_auth_add(void *arg)
     212             : {
     213           1 :   (void) arg;
     214             : 
     215           1 :   MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
     216             : 
     217           1 :   int retval;
     218           1 :   ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4,
     219             :                        service_identity_pk_jam;
     220           1 :   control_connection_t conn;
     221           1 :   char *args = NULL;
     222           1 :   char *cp1 = NULL;
     223           1 :   size_t sz;
     224             : 
     225           1 :   hs_init();
     226             : 
     227             :   { /* Setup the control conn */
     228           1 :     memset(&conn, 0, sizeof(control_connection_t));
     229           1 :     TO_CONN(&conn)->outbuf = buf_new();
     230           1 :     conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
     231             :   }
     232             : 
     233             :   { /* Setup the services */
     234           1 :     retval = hs_parse_address(
     235             :                  "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
     236             :                  &service_identity_pk_2fv,
     237             :                  NULL, NULL);
     238           1 :     tt_int_op(retval, OP_EQ, 0);
     239             : 
     240           1 :     retval = hs_parse_address(
     241             :                  "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd",
     242             :                  &service_identity_pk_jt4,
     243             :                  NULL, NULL);
     244           1 :     tt_int_op(retval, OP_EQ, 0);
     245             : 
     246           1 :     retval = hs_parse_address(
     247             :                  "jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd",
     248             :                  &service_identity_pk_jam,
     249             :                  NULL, NULL);
     250           1 :     tt_int_op(retval, OP_EQ, 0);
     251             :   }
     252             : 
     253           1 :   digest256map_t *client_auths = get_hs_client_auths_map();
     254           1 :   tt_assert(!client_auths);
     255             : 
     256             :   /* Register first service */
     257           1 :   args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
     258             :                     "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= ");
     259             : 
     260           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     261           1 :   tt_int_op(retval, OP_EQ, 0);
     262             : 
     263             :   /* Check contents */
     264           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     265           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     266             : 
     267           1 :   tor_free(cp1);
     268           1 :   tor_free(args);
     269             : 
     270             :   /* Register second service (even with an unrecognized argument) */
     271           1 :   args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
     272             :            "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA= DropSound=No");
     273             : 
     274           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     275           1 :   tt_int_op(retval, OP_EQ, 0);
     276             : 
     277             :   /* Check contents */
     278           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     279           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     280           1 :   tor_free(cp1);
     281           1 :   tor_free(args);
     282             : 
     283             :   /* Register second service (even with an unrecognized argument) */
     284           1 :   args = tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd "
     285             :            "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= "
     286             :            "ClientName=MeganNicole ");
     287             : 
     288           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     289           1 :   tt_int_op(retval, OP_EQ, 0);
     290             : 
     291             :   /* Check contents */
     292           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     293           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     294           1 :   tor_free(cp1);
     295             : 
     296           1 :   client_auths = get_hs_client_auths_map();
     297           1 :   tt_assert(client_auths);
     298           1 :   tt_uint_op(digest256map_size(client_auths), OP_EQ, 3);
     299             : 
     300           1 :   hs_client_service_authorization_t *client_2fv =
     301           1 :     digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
     302           1 :   tt_assert(client_2fv);
     303           1 :   tt_int_op(client_2fv->flags, OP_EQ, 0);
     304             : 
     305           1 :   hs_client_service_authorization_t *client_jt4 =
     306           1 :     digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
     307           1 :   tt_assert(client_jt4);
     308           1 :   tt_int_op(client_jt4->flags, OP_EQ, 0);
     309             : 
     310           1 :   hs_client_service_authorization_t *client_jam =
     311           1 :     digest256map_get(client_auths, service_identity_pk_jam.pubkey);
     312           1 :   tt_assert(client_jam);
     313           1 :   tt_int_op(client_jam->flags, OP_EQ, 0);
     314             : 
     315             :   /* Now let's VIEW the auth credentials */
     316           1 :   tor_free(conn.current_cmd);
     317           1 :   conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
     318             : 
     319             :   /* First go with no arguments, so that we view all the credentials */
     320           1 :   tor_free(args);
     321           1 :   args = tor_strdup("");
     322             : 
     323             : #define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n"   \
     324             :   "250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "  \
     325             :     "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n"   \
     326             :   "250-CLIENT jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " \
     327             :     "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " \
     328             :     "ClientName=MeganNicole\r\n" \
     329             :   "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
     330             :     "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n"             \
     331             :   "250 OK\r\n"
     332             : 
     333           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     334           1 :   tt_int_op(retval, OP_EQ, 0);
     335           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     336           1 :   tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NO_ADDR);
     337           1 :   tor_free(cp1);
     338             : 
     339             :   /* Now specify an HS addr, and see that we only view those creds */
     340           1 :   tor_free(args);
     341           2 :   args =
     342           1 :     tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
     343             : 
     344             : #define VIEW_CORRECT_REPLY_JT4 "250-ONION_CLIENT_AUTH_VIEW " \
     345             :     "jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\r\n"   \
     346             :   "250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
     347             :     "x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \
     348             :   "250 OK\r\n"
     349             : 
     350           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     351           1 :   tt_int_op(retval, OP_EQ, 0);
     352           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     353           1 :   tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_JT4);
     354           1 :   tor_free(cp1);
     355             : 
     356             :   /* Now try to REMOVE the auth credentials */
     357           1 :   tor_free(conn.current_cmd);
     358           1 :   conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
     359             : 
     360             :   /* First try with a wrong addr */
     361           1 :   tor_free(args);
     362           1 :   args = tor_strdup("thatsok");
     363             : 
     364           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     365           1 :   tt_int_op(retval, OP_EQ, 0);
     366           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     367           1 :   tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"thatsok\"\r\n");
     368           1 :   tor_free(cp1);
     369             : 
     370           1 :   client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
     371           1 :   tt_assert(client_jt4);
     372             : 
     373             :   /* Now actually remove them. */
     374           1 :   tor_free(args);
     375           1 :   args =tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd");
     376             : 
     377           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     378           1 :   tt_int_op(retval, OP_EQ, 0);
     379           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     380           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     381           1 :   tor_free(cp1);
     382             : 
     383           1 :   client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
     384           1 :   tt_assert(!client_jt4);
     385             : 
     386             :   /* Now try another time (we should get 'already removed' msg) */
     387           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     388           1 :   tt_int_op(retval, OP_EQ, 0);
     389           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     390           1 :   tt_str_op(cp1, OP_EQ, "251 No credentials for "
     391             :            "\"jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd\"\r\n");
     392           1 :   tor_free(cp1);
     393             : 
     394           1 :   client_jt4 = digest256map_get(client_auths, service_identity_pk_jt4.pubkey);
     395           1 :   tt_assert(!client_jt4);
     396             : 
     397             :   /* Now also remove the other one */
     398           1 :   tor_free(args);
     399           2 :   args =
     400           1 :     tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
     401             : 
     402           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     403           1 :   tt_int_op(retval, OP_EQ, 0);
     404           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     405           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     406           1 :   tor_free(cp1);
     407             : 
     408             :   /* Now also remove the other one */
     409           1 :   tor_free(args);
     410           2 :   args =
     411           1 :     tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd");
     412             : 
     413           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     414           1 :   tt_int_op(retval, OP_EQ, 0);
     415           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     416           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     417           1 :   tor_free(cp1);
     418             : 
     419             :   /* Finally, do another VIEW and see that we get nothing. */
     420           1 :   tor_free(conn.current_cmd);
     421           1 :   conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
     422           1 :   tor_free(args);
     423           1 :   args = tor_strdup("");
     424             : 
     425             : #define VIEW_CORRECT_REPLY_NOTHING "250-ONION_CLIENT_AUTH_VIEW\r\n250 OK\r\n"
     426             : 
     427           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     428           1 :   tt_int_op(retval, OP_EQ, 0);
     429           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     430           1 :   tt_str_op(cp1, OP_EQ, VIEW_CORRECT_REPLY_NOTHING);
     431           1 :   tor_free(cp1);
     432             : 
     433             :   /* And a final VIEW with a wrong HS addr */
     434           1 :   tor_free(args);
     435           1 :   args = tor_strdup("house");
     436             : 
     437           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     438           1 :   tt_int_op(retval, OP_EQ, 0);
     439           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     440           1 :   tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n");
     441             : 
     442           1 :  done:
     443           1 :   tor_free(args);
     444           1 :   tor_free(cp1);
     445           1 :   buf_free(TO_CONN(&conn)->outbuf);
     446           1 :   tor_free(conn.current_cmd);
     447           1 :   hs_client_free_all();
     448           1 : }
     449             : 
     450             : /** Test some error cases of ONION_CLIENT_AUTH_ADD */
     451             : static void
     452           1 : test_hs_control_bad_onion_client_auth_add(void *arg)
     453             : {
     454           1 :   (void) arg;
     455             : 
     456           1 :   MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
     457             : 
     458           1 :   int retval;
     459           1 :   control_connection_t conn;
     460           1 :   char *cp1 = NULL;
     461           1 :   size_t sz;
     462           1 :   char *args = NULL;
     463             : 
     464           1 :   hs_init();
     465             : 
     466             :   { /* Setup the control conn */
     467           1 :     memset(&conn, 0, sizeof(control_connection_t));
     468           1 :     TO_CONN(&conn)->outbuf = buf_new();
     469           1 :     conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
     470             :   }
     471             : 
     472           1 :   digest256map_t *client_auths = get_hs_client_auths_map();
     473           1 :   tt_assert(!client_auths);
     474             : 
     475             :   /* Register first service */
     476           1 :   args = tor_strdup(
     477             :                 "badaddr x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=");
     478             : 
     479           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     480           1 :   tt_int_op(retval, OP_EQ, 0);
     481             : 
     482             :   /* Check contents */
     483           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     484           1 :   tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"badaddr\"\r\n");
     485             : 
     486           1 :   tor_free(cp1);
     487           1 :   tor_free(args);
     488             : 
     489             :   /* Register second service (even with an unrecognized argument) */
     490           1 :   args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
     491             :                     "love:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=");
     492             : 
     493           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     494           1 :   tt_int_op(retval, OP_EQ, 0);
     495             : 
     496             :   /* Check contents */
     497           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     498           1 :   tt_str_op(cp1, OP_EQ, "552 Unrecognized key type \"love\"\r\n");
     499             : 
     500           1 :   tor_free(cp1);
     501           1 :   tor_free(args);
     502             : 
     503             :   /* Register second service (even with an unrecognized argument) */
     504           1 :   args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
     505             :                     "x25519:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEK");
     506             : 
     507           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     508           1 :   tt_int_op(retval, OP_EQ, 0);
     509             : 
     510             :   /* Check contents */
     511           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     512           1 :   tt_str_op(cp1, OP_EQ, "512 Failed to decode x25519 private key\r\n");
     513             : 
     514           1 :   tor_free(cp1);
     515           1 :   tor_free(args);
     516             : 
     517             :   /* Register with an all zero client key */
     518           1 :   args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
     519             :                     "x25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
     520           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     521           1 :   tt_int_op(retval, OP_EQ, 0);
     522             : 
     523             :   /* Check contents */
     524           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     525           1 :   tt_str_op(cp1, OP_EQ, "553 Invalid private key \"AAAAAAAAAAAAAAAAAAAA"
     526             :                         "AAAAAAAAAAAAAAAAAAAAAAA=\"\r\n");
     527             : 
     528           1 :   client_auths = get_hs_client_auths_map();
     529           1 :   tt_assert(!client_auths);
     530             : 
     531           1 :  done:
     532           1 :   tor_free(args);
     533           1 :   tor_free(cp1);
     534           1 :   buf_free(TO_CONN(&conn)->outbuf);
     535           1 :   tor_free(conn.current_cmd);
     536           1 :   hs_client_free_all();
     537           1 : }
     538             : 
     539             : /** Test that we can correctly add permanent client auth credentials using the
     540             :  *  control port. */
     541             : static void
     542           1 : test_hs_control_store_permanent_creds(void *arg)
     543             : {
     544           1 :   (void) arg;
     545             : 
     546           1 :   MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
     547             : 
     548           1 :   int retval;
     549           1 :   ed25519_public_key_t service_identity_pk_2fv;
     550           1 :   control_connection_t conn;
     551           1 :   char *args = NULL;
     552           1 :   char *cp1 = NULL;
     553           1 :   char *creds_file_str = NULL;
     554           1 :   char *creds_fname = NULL;
     555             : 
     556           1 :   size_t sz;
     557             : 
     558           1 :   hs_init();
     559             : 
     560             :   { /* Setup the control conn */
     561           1 :     memset(&conn, 0, sizeof(control_connection_t));
     562           1 :     TO_CONN(&conn)->outbuf = buf_new();
     563           1 :     conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_ADD");
     564             :   }
     565             : 
     566             :   { /* Setup the services */
     567           1 :     retval = hs_parse_address(
     568             :                  "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd",
     569             :                  &service_identity_pk_2fv,
     570             :                  NULL, NULL);
     571           1 :     tt_int_op(retval, OP_EQ, 0);
     572             :   }
     573             : 
     574           1 :   digest256map_t *client_auths = get_hs_client_auths_map();
     575           1 :   tt_assert(!client_auths);
     576             : 
     577             :   /* Try registering first service with no ClientOnionAuthDir set */
     578           1 :   args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
     579             :                     "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
     580             :                     "Flags=Permanent");
     581             : 
     582           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     583           1 :   tt_int_op(retval, OP_EQ, 0);
     584             : 
     585             :   /* Check control port response. This one should fail. */
     586           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     587           1 :   tt_str_op(cp1, OP_EQ, "553 Unable to store creds for "
     588             :         "\"2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd\"\r\n");
     589             : 
     590             :   { /* Setup ClientOnionAuthDir */
     591           1 :     int ret;
     592           1 :     char *perm_creds_dir = tor_strdup(get_fname("permanent_credentials"));
     593           1 :     get_options_mutable()->ClientOnionAuthDir = perm_creds_dir;
     594             : 
     595             :     #ifdef _WIN32
     596             :       ret = mkdir(perm_creds_dir);
     597             :     #else
     598           1 :       ret = mkdir(perm_creds_dir, 0700);
     599             :     #endif
     600           1 :     tt_int_op(ret, OP_EQ, 0);
     601             :   }
     602             : 
     603           1 :   tor_free(args);
     604           1 :   tor_free(cp1);
     605             : 
     606             :   /* Try the control port command again. This time it should work! */
     607           1 :   args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
     608             :                     "x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ= "
     609             :                     "Flags=Permanent");
     610           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     611           1 :   tt_int_op(retval, OP_EQ, 0);
     612             : 
     613             :   /* Check control port response */
     614           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     615           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     616             : 
     617             :   /* Check file contents! */
     618           1 :   creds_fname = tor_strdup(get_fname("permanent_credentials/"
     619             :      "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd.auth_private"));
     620           1 :   creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
     621             : 
     622           1 :   tt_assert(creds_file_str);
     623           1 :   tt_str_op(creds_file_str, OP_EQ,
     624             :          "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
     625             :          /* base32 representation of the base64 iJ1t... key above */
     626             :          "x25519:rcow3dfavmyanyqvhwnvnmfdqw34ydtrgv7jnelmqs4wi4uuxrca");
     627             : 
     628           1 :   tor_free(args);
     629           1 :   tor_free(cp1);
     630             : 
     631             :   /* Overwrite the credentials and check that they got overwrited. */
     632           1 :   args = tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd "
     633             :                     "x25519:UDRvZLvcJo0QRLvDfkpgbtsqbkhIUQZyeo2FNBrgS18= "
     634             :                     "Flags=Permanent");
     635           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     636           1 :   tt_int_op(retval, OP_EQ, 0);
     637             : 
     638             :   /* Check control port response: we replaced! */
     639           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     640           1 :   tt_str_op(cp1, OP_EQ, "251 Client for onion existed and replaced\r\n");
     641             : 
     642           1 :   tor_free(creds_file_str);
     643             : 
     644             :   /* Check creds file contents again. See that the key got updated */
     645           1 :   creds_file_str = read_file_to_str(creds_fname, RFTS_BIN, NULL);
     646           1 :   tt_assert(creds_file_str);
     647           1 :   tt_str_op(creds_file_str, OP_EQ,
     648             :          "2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd:descriptor:"
     649             :          /* base32 representation of the base64 UDRv... key above */
     650             :          "x25519:ka2g6zf33qti2ecexpbx4stan3nsu3sijbiqm4t2rwctigxajnpq");
     651             : 
     652             :   /* Now for our next act!!! Actually get the HS client subsystem to parse the
     653             :    * whole directory and make sure that it extracted the right credential! */
     654           1 :   hs_config_client_authorization(get_options(), 0);
     655             : 
     656           1 :   client_auths = get_hs_client_auths_map();
     657           1 :   tt_assert(client_auths);
     658           1 :   tt_uint_op(digest256map_size(client_auths), OP_EQ, 1);
     659             : 
     660           1 :   hs_client_service_authorization_t *client_2fv =
     661           1 :     digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
     662           1 :   tt_assert(client_2fv);
     663           1 :   tt_int_op(client_2fv->flags, OP_EQ, CLIENT_AUTH_FLAG_IS_PERMANENT);
     664           1 :   tt_str_op(hex_str((char*)client_2fv->enc_seckey.secret_key, 32), OP_EQ,
     665             :            "50346F64BBDC268D1044BBC37E4A606EDB2A6E48485106727A8D85341AE04B5F");
     666             : 
     667             :   /* And now for the final act! Use the REMOVE control port command to remove
     668             :      the credential, and ensure that the file has also been removed! */
     669           1 :   tor_free(conn.current_cmd);
     670           1 :   tor_free(cp1);
     671           1 :   tor_free(args);
     672             : 
     673             :   /* Ensure that the creds file exists */
     674           1 :   tt_int_op(file_status(creds_fname), OP_EQ, FN_FILE);
     675             : 
     676             :   /* Do the REMOVE */
     677           1 :   conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_REMOVE");
     678           1 :   args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
     679           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     680           1 :   tt_int_op(retval, OP_EQ, 0);
     681           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     682           1 :   tt_str_op(cp1, OP_EQ, "250 OK\r\n");
     683             : 
     684             :   /* Ensure that the file has been removed and the map is empty */
     685           1 :   tt_int_op(file_status(creds_fname), OP_EQ, FN_NOENT);
     686           1 :   tt_uint_op(digest256map_size(client_auths), OP_EQ, 0);
     687             : 
     688           1 :  done:
     689           1 :   tor_free(get_options_mutable()->ClientOnionAuthDir);
     690           1 :   tor_free(args);
     691           1 :   tor_free(cp1);
     692           1 :   buf_free(TO_CONN(&conn)->outbuf);
     693           1 :   tor_free(conn.current_cmd);
     694           1 :   tor_free(creds_fname);
     695           1 :   tor_free(creds_file_str);
     696           1 :   hs_client_free_all();
     697           1 : }
     698             : 
     699             : /** Test that ADD_ONION properly handles an attacker passing it a bad private
     700             :  *  key. */
     701             : static void
     702           1 : test_hs_control_add_onion_with_bad_pubkey(void *arg)
     703             : {
     704           1 :   (void) arg;
     705             : 
     706           1 :   MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
     707             : 
     708           1 :   int retval;
     709           1 :   control_connection_t conn;
     710           1 :   char *args = NULL;
     711           1 :   char *cp1 = NULL;
     712           1 :   size_t sz;
     713             : 
     714           1 :   hs_init();
     715             : 
     716             :   { /* Setup the control conn */
     717           1 :     memset(&conn, 0, sizeof(control_connection_t));
     718           1 :     TO_CONN(&conn)->outbuf = buf_new();
     719           1 :     conn.current_cmd = tor_strdup("ADD_ONION");
     720             :   }
     721             : 
     722           1 :   args = tor_strdup("ED25519-V3:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     723             :                     "AAAAAAAAAAAAAAAAAAAAAAA"
     724             :                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
     725             :                     "Port=9735,127.0.0.1 Flags=DiscardPK");
     726             : 
     727           1 :   retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
     728           1 :   tt_int_op(retval, OP_EQ, 0);
     729             : 
     730             :   /* Check control port response */
     731           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     732           1 :   tt_str_op(cp1, OP_EQ, "551 Failed to generate onion address\r\n");
     733             : 
     734           1 :  done:
     735           1 :   tor_free(args);
     736           1 :   tor_free(cp1);
     737           1 :   buf_free(TO_CONN(&conn)->outbuf);
     738           1 :   tor_free(conn.current_cmd);
     739           1 : }
     740             : 
     741             : /** Test that we can add the service via the control port. */
     742             : static void
     743           1 : test_hs_control_add_auth_onion_service(void *arg)
     744             : {
     745           1 :   control_connection_t conn;
     746           1 :   char *args = NULL, *cp1 = NULL;
     747           1 :   size_t sz;
     748             : 
     749           1 :   (void) arg;
     750             : 
     751           1 :   hs_init();
     752             : 
     753           1 :   memset(&conn, 0, sizeof(control_connection_t));
     754           1 :   TO_CONN(&conn)->outbuf = buf_new();
     755           1 :   conn.current_cmd = tor_strdup("ADD_ONION");
     756           1 :   args = tor_strdup("ED25519-V3:KLMQ4CLKwlDCHuMPn8j3od33cU5LhnrLNoZh7CWChl3VkY"
     757             :     "pNAkeP5dGW8xeKR9HxQBWQ/w7Kr12lA/U8Pd/oxw== "
     758             :     "ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja "
     759             :     "Flags=V3Auth Port=9735,127.0.0.1");
     760           1 :   handle_control_command(&conn, (uint32_t) strlen(args), args);
     761           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     762           1 :   tt_str_op(cp1, OP_EQ,
     763             :    "250-ServiceID=n35etu3yjxrqjpntmfziom5sjwspoydchmelc4xleoy4jk2u4lziz2yd\r\n"
     764             :    "250-ClientAuthV3=dz4q5xqlb4ldnbs72iarrml4ephk3du4i7o2cgiva5lwr6wkquja\r\n"
     765             :    "250 OK\r\n");
     766           1 :   tor_free(args);
     767           1 :   tor_free(cp1);
     768             : 
     769           1 :   args = tor_strdup("ED25519-V3:iIU8EBi71qE7G6UTsROU1kWN0JMrRP/YukC0Xk5WLGyil3"
     770             :     "gm4u3wEBXr+/TaCpXS+65Pcdqz+PG+4+oWHLN05A== "
     771             :     "ClientAuthV3=dummy Flags=V3Auth Port=9735,127.0.0.1");
     772           1 :   handle_control_command(&conn, (uint32_t) strlen(args), args);
     773           1 :   cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
     774           1 :   tt_str_op(cp1, OP_EQ, "512 Cannot decode v3 client auth key\r\n");
     775             : 
     776           1 :  done:
     777           1 :   tor_free(args);
     778           1 :   tor_free(cp1);
     779           1 :   tor_free(conn.current_cmd);
     780           1 :   buf_free(TO_CONN(&conn)->outbuf);
     781           2 :   SMARTLIST_FOREACH(conn.ephemeral_onion_services, char *,
     782             :                     service, tor_free(service));
     783           1 :   smartlist_free(conn.ephemeral_onion_services);
     784           1 :   hs_client_free_all();
     785           1 : }
     786             : 
     787             : /** Test that add_onion_helper_add_service can add the service. */
     788             : static void
     789           1 : test_hs_control_add_onion_helper_add_service(void *arg)
     790             : {
     791           1 :   int hs_version_good, hs_version_bad;
     792           1 :   add_onion_secret_key_t sk_good, sk_bad;
     793           1 :   ed25519_public_key_t pk_good, pk_bad;
     794           1 :   char *key_new_blob_good = NULL, *key_new_blob_bad = NULL;
     795           1 :   const char *key_new_alg_good = NULL, *key_new_alg_bad = NULL;
     796           1 :   hs_service_authorized_client_t *client_good, *client_bad;
     797           1 :   smartlist_t *list_good, *list_bad;
     798           1 :   hs_service_ht *global_map;
     799           1 :   hs_port_config_t *portcfg;
     800           1 :   smartlist_t *portcfgs;
     801           1 :   char *address_out_good, *address_out_bad;
     802           1 :   hs_service_t *service_good = NULL;
     803           1 :   hs_service_t *service_bad = NULL;
     804             : 
     805           1 :   (void) arg;
     806             : 
     807           1 :   hs_init();
     808           1 :   global_map = get_hs_service_map();
     809             : 
     810           1 :   portcfg = hs_parse_port_config("8080", ",", NULL);
     811           1 :   portcfgs = smartlist_new();
     812           1 :   smartlist_add(portcfgs, portcfg);
     813             : 
     814           1 :   memset(&sk_good, 0, sizeof(sk_good));
     815           1 :   memset(&sk_bad, 0, sizeof(sk_bad));
     816             : 
     817           1 :   add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_good,
     818             :                          &key_new_blob_good, &sk_good, &hs_version_good, NULL);
     819           1 :   add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg_bad,
     820             :                          &key_new_blob_bad, &sk_bad, &hs_version_bad, NULL);
     821             : 
     822           1 :   ed25519_public_key_generate(&pk_good, sk_good.v3);
     823           1 :   ed25519_public_key_generate(&pk_bad, sk_bad.v3);
     824             : 
     825           1 :   client_good = parse_authorized_client_key(
     826             :             "N2NU7BSRL6YODZCYPN4CREB54TYLKGIE2KYOQWLFYC23ZJVCE5DQ", LOG_INFO);
     827           1 :   client_bad = parse_authorized_client_key("dummy", LOG_INFO);
     828             : 
     829           1 :   list_good = smartlist_new();
     830           1 :   smartlist_add(list_good, client_good);
     831             : 
     832           1 :   add_onion_helper_add_service(HS_VERSION_THREE, &sk_good, portcfgs, 1, 1,
     833             :                                list_good, &address_out_good);
     834             : 
     835           1 :   service_good = find_service(global_map, &pk_good);
     836           1 :   tt_int_op(smartlist_len(service_good->config.clients), OP_EQ, 1);
     837             : 
     838           1 :   remove_service(global_map, service_good);
     839           1 :   hs_service_free(service_good);
     840             : 
     841           1 :   list_bad = smartlist_new();
     842           1 :   smartlist_add(list_bad, client_bad);
     843             : 
     844           1 :   portcfg = hs_parse_port_config("8080", ",", NULL);
     845           1 :   portcfgs = smartlist_new();
     846           1 :   smartlist_add(portcfgs, portcfg);
     847             : 
     848           1 :   add_onion_helper_add_service(HS_VERSION_THREE, &sk_bad, portcfgs, 1, 1,
     849             :                                list_bad, &address_out_bad);
     850             : 
     851           1 :   service_bad = find_service(global_map, &pk_bad);
     852             : 
     853           1 :   tt_int_op(smartlist_len(service_bad->config.clients), OP_EQ, 0);
     854             : 
     855           1 :  done:
     856           1 :   tor_free(key_new_blob_good);
     857           1 :   tor_free(key_new_blob_bad);
     858           1 :   tor_free(address_out_good);
     859           1 :   tor_free(address_out_bad);
     860             : 
     861           1 :   hs_service_free(service_good);
     862           1 :   hs_service_free(service_bad);
     863           1 : }
     864             : 
     865             : struct testcase_t hs_control_tests[] = {
     866             :   { "hs_desc_event", test_hs_desc_event, TT_FORK,
     867             :     NULL, NULL },
     868             :   { "hs_control_good_onion_client_auth_add",
     869             :     test_hs_control_good_onion_client_auth_add, TT_FORK,
     870             :     NULL, NULL },
     871             :   { "hs_control_bad_onion_client_auth_add",
     872             :     test_hs_control_bad_onion_client_auth_add, TT_FORK,
     873             :     NULL, NULL },
     874             :   { "hs_control_store_permanent_creds",
     875             :     test_hs_control_store_permanent_creds, TT_FORK, NULL, NULL },
     876             :   { "hs_control_add_onion_with_bad_pubkey",
     877             :     test_hs_control_add_onion_with_bad_pubkey, TT_FORK, NULL, NULL },
     878             :   { "hs_control_add_auth_onion_service",
     879             :     test_hs_control_add_auth_onion_service, TT_FORK, NULL, NULL},
     880             :   { "hs_control_add_onion_helper_add_service",
     881             :     test_hs_control_add_onion_helper_add_service, TT_FORK, NULL, NULL},
     882             : 
     883             :   END_OF_TESTCASES
     884             : };

Generated by: LCOV version 1.14