rendparse.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. /* Copyright (c) 2001 Matej Pfajfar.
  2. * Copyright (c) 2001-2004, Roger Dingledine.
  3. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  4. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. /**
  7. * \file rendparse.c
  8. * \brief Code to parse and validate v2 hidden service descriptors.
  9. **/
  10. #include "core/or/or.h"
  11. #include "feature/dirparse/parsecommon.h"
  12. #include "feature/dirparse/sigcommon.h"
  13. #include "feature/rend/rendcommon.h"
  14. #include "feature/rend/rendparse.h"
  15. #include "lib/memarea/memarea.h"
  16. #include "core/or/extend_info_st.h"
  17. #include "feature/rend/rend_authorized_client_st.h"
  18. #include "feature/rend/rend_intro_point_st.h"
  19. #include "feature/rend/rend_service_descriptor_st.h"
  20. /** List of tokens recognized in rendezvous service descriptors */
  21. static token_rule_t desc_token_table[] = {
  22. T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
  23. EQ(1), NO_OBJ),
  24. T1("version", R_VERSION, EQ(1), NO_OBJ),
  25. T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
  26. T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
  27. T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
  28. T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
  29. T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
  30. T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
  31. END_OF_TABLE
  32. };
  33. /** List of tokens recognized in the (encrypted) list of introduction points of
  34. * rendezvous service descriptors */
  35. static token_rule_t ipo_token_table[] = {
  36. T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
  37. T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
  38. T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
  39. T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
  40. T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
  41. END_OF_TABLE
  42. };
  43. /** List of tokens recognized in the (possibly encrypted) list of introduction
  44. * points of rendezvous service descriptors */
  45. static token_rule_t client_keys_token_table[] = {
  46. T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
  47. T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
  48. T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
  49. END_OF_TABLE
  50. };
  51. /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
  52. * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
  53. * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
  54. * encrypted introduction points to the newly allocated
  55. * *<b>intro_points_encrypted_out</b>, their encrypted size to
  56. * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
  57. * to *<b>encoded_size_out</b>, and a pointer to the possibly next
  58. * descriptor to *<b>next_out</b>; return 0 for success (including validation)
  59. * and -1 for failure.
  60. *
  61. * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
  62. * be strict about time formats.
  63. */
  64. int
  65. rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
  66. char *desc_id_out,
  67. char **intro_points_encrypted_out,
  68. size_t *intro_points_encrypted_size_out,
  69. size_t *encoded_size_out,
  70. const char **next_out, const char *desc,
  71. int as_hsdir)
  72. {
  73. rend_service_descriptor_t *result =
  74. tor_malloc_zero(sizeof(rend_service_descriptor_t));
  75. char desc_hash[DIGEST_LEN];
  76. const char *eos;
  77. smartlist_t *tokens = smartlist_new();
  78. directory_token_t *tok;
  79. char secret_id_part[DIGEST_LEN];
  80. int i, version, num_ok=1;
  81. smartlist_t *versions;
  82. char public_key_hash[DIGEST_LEN];
  83. char test_desc_id[DIGEST_LEN];
  84. memarea_t *area = NULL;
  85. const int strict_time_fmt = as_hsdir;
  86. tor_assert(desc);
  87. /* Check if desc starts correctly. */
  88. if (strcmpstart(desc, "rendezvous-service-descriptor ")) {
  89. log_info(LD_REND, "Descriptor does not start correctly.");
  90. goto err;
  91. }
  92. /* Compute descriptor hash for later validation. */
  93. if (router_get_hash_impl(desc, strlen(desc), desc_hash,
  94. "rendezvous-service-descriptor ",
  95. "\nsignature", '\n', DIGEST_SHA1) < 0) {
  96. log_warn(LD_REND, "Couldn't compute descriptor hash.");
  97. goto err;
  98. }
  99. /* Determine end of string. */
  100. eos = strstr(desc, "\nrendezvous-service-descriptor ");
  101. if (!eos)
  102. eos = desc + strlen(desc);
  103. else
  104. eos = eos + 1;
  105. /* Check length. */
  106. if (eos-desc > REND_DESC_MAX_SIZE) {
  107. /* XXXX+ If we are parsing this descriptor as a server, this
  108. * should be a protocol warning. */
  109. log_warn(LD_REND, "Descriptor length is %d which exceeds "
  110. "maximum rendezvous descriptor size of %d bytes.",
  111. (int)(eos-desc), REND_DESC_MAX_SIZE);
  112. goto err;
  113. }
  114. /* Tokenize descriptor. */
  115. area = memarea_new();
  116. if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
  117. log_warn(LD_REND, "Error tokenizing descriptor.");
  118. goto err;
  119. }
  120. /* Set next to next descriptor, if available. */
  121. *next_out = eos;
  122. /* Set length of encoded descriptor. */
  123. *encoded_size_out = eos - desc;
  124. /* Check min allowed length of token list. */
  125. if (smartlist_len(tokens) < 7) {
  126. log_warn(LD_REND, "Impossibly short descriptor.");
  127. goto err;
  128. }
  129. /* Parse base32-encoded descriptor ID. */
  130. tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
  131. tor_assert(tok == smartlist_get(tokens, 0));
  132. tor_assert(tok->n_args == 1);
  133. if (!rend_valid_descriptor_id(tok->args[0])) {
  134. log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
  135. goto err;
  136. }
  137. if (base32_decode(desc_id_out, DIGEST_LEN,
  138. tok->args[0], REND_DESC_ID_V2_LEN_BASE32) != DIGEST_LEN) {
  139. log_warn(LD_REND,
  140. "Descriptor ID has wrong length or illegal characters: %s",
  141. tok->args[0]);
  142. goto err;
  143. }
  144. /* Parse descriptor version. */
  145. tok = find_by_keyword(tokens, R_VERSION);
  146. tor_assert(tok->n_args == 1);
  147. result->version =
  148. (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
  149. if (result->version != 2 || !num_ok) {
  150. /* If it's <2, it shouldn't be under this format. If the number
  151. * is greater than 2, we bumped it because we broke backward
  152. * compatibility. See how version numbers in our other formats
  153. * work. */
  154. log_warn(LD_REND, "Unrecognized descriptor version: %s",
  155. escaped(tok->args[0]));
  156. goto err;
  157. }
  158. /* Parse public key. */
  159. tok = find_by_keyword(tokens, R_PERMANENT_KEY);
  160. result->pk = tok->key;
  161. tok->key = NULL; /* Prevent free */
  162. /* Parse secret ID part. */
  163. tok = find_by_keyword(tokens, R_SECRET_ID_PART);
  164. tor_assert(tok->n_args == 1);
  165. if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
  166. strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
  167. log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
  168. goto err;
  169. }
  170. if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) !=
  171. DIGEST_LEN) {
  172. log_warn(LD_REND,
  173. "Secret ID part has wrong length or illegal characters: %s",
  174. tok->args[0]);
  175. goto err;
  176. }
  177. /* Parse publication time -- up-to-date check is done when storing the
  178. * descriptor. */
  179. tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
  180. tor_assert(tok->n_args == 1);
  181. if (parse_iso_time_(tok->args[0], &result->timestamp,
  182. strict_time_fmt, 0) < 0) {
  183. log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
  184. goto err;
  185. }
  186. /* Parse protocol versions. */
  187. tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
  188. tor_assert(tok->n_args == 1);
  189. versions = smartlist_new();
  190. smartlist_split_string(versions, tok->args[0], ",",
  191. SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  192. for (i = 0; i < smartlist_len(versions); i++) {
  193. version = (int) tor_parse_long(smartlist_get(versions, i),
  194. 10, 0, INT_MAX, &num_ok, NULL);
  195. if (!num_ok) /* It's a string; let's ignore it. */
  196. continue;
  197. if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
  198. /* Avoid undefined left-shift behaviour. */
  199. continue;
  200. result->protocols |= 1 << version;
  201. }
  202. SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
  203. smartlist_free(versions);
  204. /* Parse encrypted introduction points. Don't verify. */
  205. tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
  206. if (tok) {
  207. if (strcmp(tok->object_type, "MESSAGE")) {
  208. log_warn(LD_DIR, "Bad object type: introduction points should be of "
  209. "type MESSAGE");
  210. goto err;
  211. }
  212. *intro_points_encrypted_out = tor_memdup(tok->object_body,
  213. tok->object_size);
  214. *intro_points_encrypted_size_out = tok->object_size;
  215. } else {
  216. *intro_points_encrypted_out = NULL;
  217. *intro_points_encrypted_size_out = 0;
  218. }
  219. /* Parse and verify signature. */
  220. tok = find_by_keyword(tokens, R_SIGNATURE);
  221. if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
  222. "v2 rendezvous service descriptor") < 0)
  223. goto err;
  224. /* Verify that descriptor ID belongs to public key and secret ID part. */
  225. if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
  226. log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
  227. goto err;
  228. }
  229. rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
  230. secret_id_part);
  231. if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
  232. log_warn(LD_REND, "Parsed descriptor ID does not match "
  233. "computed descriptor ID.");
  234. goto err;
  235. }
  236. goto done;
  237. err:
  238. rend_service_descriptor_free(result);
  239. result = NULL;
  240. done:
  241. if (tokens) {
  242. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  243. smartlist_free(tokens);
  244. }
  245. if (area)
  246. memarea_drop_all(area);
  247. *parsed_out = result;
  248. if (result)
  249. return 0;
  250. return -1;
  251. }
  252. /** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
  253. * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
  254. * write the result to a newly allocated string that is pointed to by
  255. * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
  256. * Return 0 if decryption was successful and -1 otherwise. */
  257. int
  258. rend_decrypt_introduction_points(char **ipos_decrypted,
  259. size_t *ipos_decrypted_size,
  260. const char *descriptor_cookie,
  261. const char *ipos_encrypted,
  262. size_t ipos_encrypted_size)
  263. {
  264. tor_assert(ipos_encrypted);
  265. tor_assert(descriptor_cookie);
  266. if (ipos_encrypted_size < 2) {
  267. log_warn(LD_REND, "Size of encrypted introduction points is too "
  268. "small.");
  269. return -1;
  270. }
  271. if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
  272. char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
  273. session_key[CIPHER_KEY_LEN], *dec;
  274. int declen, client_blocks;
  275. size_t pos = 0, len, client_entries_len;
  276. crypto_digest_t *digest;
  277. crypto_cipher_t *cipher;
  278. client_blocks = (int) ipos_encrypted[1];
  279. client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
  280. REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
  281. if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
  282. log_warn(LD_REND, "Size of encrypted introduction points is too "
  283. "small.");
  284. return -1;
  285. }
  286. memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
  287. digest = crypto_digest_new();
  288. crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
  289. crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
  290. crypto_digest_get_digest(digest, client_id,
  291. REND_BASIC_AUTH_CLIENT_ID_LEN);
  292. crypto_digest_free(digest);
  293. for (pos = 2; pos < 2 + client_entries_len;
  294. pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
  295. if (tor_memeq(ipos_encrypted + pos, client_id,
  296. REND_BASIC_AUTH_CLIENT_ID_LEN)) {
  297. /* Attempt to decrypt introduction points. */
  298. cipher = crypto_cipher_new(descriptor_cookie);
  299. if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
  300. + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
  301. CIPHER_KEY_LEN) < 0) {
  302. log_warn(LD_REND, "Could not decrypt session key for client.");
  303. crypto_cipher_free(cipher);
  304. return -1;
  305. }
  306. crypto_cipher_free(cipher);
  307. len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
  308. dec = tor_malloc_zero(len + 1);
  309. declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
  310. ipos_encrypted + 2 + client_entries_len,
  311. ipos_encrypted_size - 2 - client_entries_len);
  312. if (declen < 0) {
  313. log_warn(LD_REND, "Could not decrypt introduction point string.");
  314. tor_free(dec);
  315. return -1;
  316. }
  317. if (fast_memcmpstart(dec, declen, "introduction-point ")) {
  318. log_warn(LD_REND, "Decrypted introduction points don't "
  319. "look like we could parse them.");
  320. tor_free(dec);
  321. continue;
  322. }
  323. *ipos_decrypted = dec;
  324. *ipos_decrypted_size = declen;
  325. return 0;
  326. }
  327. }
  328. log_warn(LD_REND, "Could not decrypt introduction points. Please "
  329. "check your authorization for this service!");
  330. return -1;
  331. } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
  332. char *dec;
  333. int declen;
  334. if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
  335. log_warn(LD_REND, "Size of encrypted introduction points is too "
  336. "small.");
  337. return -1;
  338. }
  339. dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1);
  340. declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
  341. ipos_encrypted_size -
  342. CIPHER_IV_LEN - 1,
  343. ipos_encrypted + 1,
  344. ipos_encrypted_size - 1);
  345. if (declen < 0) {
  346. log_warn(LD_REND, "Decrypting introduction points failed!");
  347. tor_free(dec);
  348. return -1;
  349. }
  350. *ipos_decrypted = dec;
  351. *ipos_decrypted_size = declen;
  352. return 0;
  353. } else {
  354. log_warn(LD_REND, "Unknown authorization type number: %d",
  355. ipos_encrypted[0]);
  356. return -1;
  357. }
  358. }
  359. /** Parse the encoded introduction points in <b>intro_points_encoded</b> of
  360. * length <b>intro_points_encoded_size</b> and write the result to the
  361. * descriptor in <b>parsed</b>; return the number of successfully parsed
  362. * introduction points or -1 in case of a failure. */
  363. int
  364. rend_parse_introduction_points(rend_service_descriptor_t *parsed,
  365. const char *intro_points_encoded,
  366. size_t intro_points_encoded_size)
  367. {
  368. const char *current_ipo, *end_of_intro_points;
  369. smartlist_t *tokens = NULL;
  370. directory_token_t *tok;
  371. rend_intro_point_t *intro;
  372. extend_info_t *info;
  373. int result, num_ok=1;
  374. memarea_t *area = NULL;
  375. tor_assert(parsed);
  376. /** Function may only be invoked once. */
  377. tor_assert(!parsed->intro_nodes);
  378. if (!intro_points_encoded || intro_points_encoded_size == 0) {
  379. log_warn(LD_REND, "Empty or zero size introduction point list");
  380. goto err;
  381. }
  382. /* Consider one intro point after the other. */
  383. current_ipo = intro_points_encoded;
  384. end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
  385. tokens = smartlist_new();
  386. parsed->intro_nodes = smartlist_new();
  387. area = memarea_new();
  388. while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
  389. "introduction-point ")) {
  390. /* Determine end of string. */
  391. const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
  392. "\nintroduction-point ");
  393. if (!eos)
  394. eos = end_of_intro_points;
  395. else
  396. eos = eos+1;
  397. tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
  398. /* Free tokens and clear token list. */
  399. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  400. smartlist_clear(tokens);
  401. memarea_clear(area);
  402. /* Tokenize string. */
  403. if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
  404. log_warn(LD_REND, "Error tokenizing introduction point");
  405. goto err;
  406. }
  407. /* Advance to next introduction point, if available. */
  408. current_ipo = eos;
  409. /* Check minimum allowed length of introduction point. */
  410. if (smartlist_len(tokens) < 5) {
  411. log_warn(LD_REND, "Impossibly short introduction point.");
  412. goto err;
  413. }
  414. /* Allocate new intro point and extend info. */
  415. intro = tor_malloc_zero(sizeof(rend_intro_point_t));
  416. info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
  417. /* Parse identifier. */
  418. tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
  419. if (base32_decode(info->identity_digest, DIGEST_LEN,
  420. tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) !=
  421. DIGEST_LEN) {
  422. log_warn(LD_REND,
  423. "Identity digest has wrong length or illegal characters: %s",
  424. tok->args[0]);
  425. rend_intro_point_free(intro);
  426. goto err;
  427. }
  428. /* Write identifier to nickname. */
  429. info->nickname[0] = '$';
  430. base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
  431. info->identity_digest, DIGEST_LEN);
  432. /* Parse IP address. */
  433. tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
  434. if (tor_addr_parse(&info->addr, tok->args[0])<0) {
  435. log_warn(LD_REND, "Could not parse introduction point address.");
  436. rend_intro_point_free(intro);
  437. goto err;
  438. }
  439. if (tor_addr_family(&info->addr) != AF_INET) {
  440. log_warn(LD_REND, "Introduction point address was not ipv4.");
  441. rend_intro_point_free(intro);
  442. goto err;
  443. }
  444. /* Parse onion port. */
  445. tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
  446. info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
  447. &num_ok,NULL);
  448. if (!info->port || !num_ok) {
  449. log_warn(LD_REND, "Introduction point onion port %s is invalid",
  450. escaped(tok->args[0]));
  451. rend_intro_point_free(intro);
  452. goto err;
  453. }
  454. /* Parse onion key. */
  455. tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
  456. if (!crypto_pk_public_exponent_ok(tok->key)) {
  457. log_warn(LD_REND,
  458. "Introduction point's onion key had invalid exponent.");
  459. rend_intro_point_free(intro);
  460. goto err;
  461. }
  462. info->onion_key = tok->key;
  463. tok->key = NULL; /* Prevent free */
  464. /* Parse service key. */
  465. tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
  466. if (!crypto_pk_public_exponent_ok(tok->key)) {
  467. log_warn(LD_REND,
  468. "Introduction point key had invalid exponent.");
  469. rend_intro_point_free(intro);
  470. goto err;
  471. }
  472. intro->intro_key = tok->key;
  473. tok->key = NULL; /* Prevent free */
  474. /* Add extend info to list of introduction points. */
  475. smartlist_add(parsed->intro_nodes, intro);
  476. }
  477. result = smartlist_len(parsed->intro_nodes);
  478. goto done;
  479. err:
  480. result = -1;
  481. done:
  482. /* Free tokens and clear token list. */
  483. if (tokens) {
  484. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  485. smartlist_free(tokens);
  486. }
  487. if (area)
  488. memarea_drop_all(area);
  489. return result;
  490. }
  491. /** Parse the content of a client_key file in <b>ckstr</b> and add
  492. * rend_authorized_client_t's for each parsed client to
  493. * <b>parsed_clients</b>. Return the number of parsed clients as result
  494. * or -1 for failure. */
  495. int
  496. rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
  497. {
  498. int result = -1;
  499. smartlist_t *tokens;
  500. directory_token_t *tok;
  501. const char *current_entry = NULL;
  502. memarea_t *area = NULL;
  503. char *err_msg = NULL;
  504. if (!ckstr || strlen(ckstr) == 0)
  505. return -1;
  506. tokens = smartlist_new();
  507. /* Begin parsing with first entry, skipping comments or whitespace at the
  508. * beginning. */
  509. area = memarea_new();
  510. current_entry = eat_whitespace(ckstr);
  511. while (!strcmpstart(current_entry, "client-name ")) {
  512. rend_authorized_client_t *parsed_entry;
  513. /* Determine end of string. */
  514. const char *eos = strstr(current_entry, "\nclient-name ");
  515. if (!eos)
  516. eos = current_entry + strlen(current_entry);
  517. else
  518. eos = eos + 1;
  519. /* Free tokens and clear token list. */
  520. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  521. smartlist_clear(tokens);
  522. memarea_clear(area);
  523. /* Tokenize string. */
  524. if (tokenize_string(area, current_entry, eos, tokens,
  525. client_keys_token_table, 0)) {
  526. log_warn(LD_REND, "Error tokenizing client keys file.");
  527. goto err;
  528. }
  529. /* Advance to next entry, if available. */
  530. current_entry = eos;
  531. /* Check minimum allowed length of token list. */
  532. if (smartlist_len(tokens) < 2) {
  533. log_warn(LD_REND, "Impossibly short client key entry.");
  534. goto err;
  535. }
  536. /* Parse client name. */
  537. tok = find_by_keyword(tokens, C_CLIENT_NAME);
  538. tor_assert(tok == smartlist_get(tokens, 0));
  539. tor_assert(tok->n_args == 1);
  540. if (!rend_valid_client_name(tok->args[0])) {
  541. log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
  542. "between 1 and %d, and valid characters are "
  543. "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
  544. goto err;
  545. }
  546. /* Check if client name is duplicate. */
  547. if (strmap_get(parsed_clients, tok->args[0])) {
  548. log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
  549. "duplicate client name: '%s'. Ignoring.", tok->args[0]);
  550. goto err;
  551. }
  552. parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
  553. parsed_entry->client_name = tor_strdup(tok->args[0]);
  554. strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
  555. /* Parse client key. */
  556. tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
  557. if (tok) {
  558. parsed_entry->client_key = tok->key;
  559. tok->key = NULL; /* Prevent free */
  560. }
  561. /* Parse descriptor cookie. */
  562. tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
  563. tor_assert(tok->n_args == 1);
  564. if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
  565. NULL, &err_msg) < 0) {
  566. tor_assert(err_msg);
  567. log_warn(LD_REND, "%s", err_msg);
  568. tor_free(err_msg);
  569. goto err;
  570. }
  571. }
  572. result = strmap_size(parsed_clients);
  573. goto done;
  574. err:
  575. result = -1;
  576. done:
  577. /* Free tokens and clear token list. */
  578. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  579. smartlist_free(tokens);
  580. if (area)
  581. memarea_drop_all(area);
  582. return result;
  583. }