rendparse.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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-2018, 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) < 0) {
  139. log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
  140. tok->args[0]);
  141. goto err;
  142. }
  143. /* Parse descriptor version. */
  144. tok = find_by_keyword(tokens, R_VERSION);
  145. tor_assert(tok->n_args == 1);
  146. result->version =
  147. (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
  148. if (result->version != 2 || !num_ok) {
  149. /* If it's <2, it shouldn't be under this format. If the number
  150. * is greater than 2, we bumped it because we broke backward
  151. * compatibility. See how version numbers in our other formats
  152. * work. */
  153. log_warn(LD_REND, "Unrecognized descriptor version: %s",
  154. escaped(tok->args[0]));
  155. goto err;
  156. }
  157. /* Parse public key. */
  158. tok = find_by_keyword(tokens, R_PERMANENT_KEY);
  159. result->pk = tok->key;
  160. tok->key = NULL; /* Prevent free */
  161. /* Parse secret ID part. */
  162. tok = find_by_keyword(tokens, R_SECRET_ID_PART);
  163. tor_assert(tok->n_args == 1);
  164. if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
  165. strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
  166. log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
  167. goto err;
  168. }
  169. if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
  170. log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
  171. tok->args[0]);
  172. goto err;
  173. }
  174. /* Parse publication time -- up-to-date check is done when storing the
  175. * descriptor. */
  176. tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
  177. tor_assert(tok->n_args == 1);
  178. if (parse_iso_time_(tok->args[0], &result->timestamp,
  179. strict_time_fmt, 0) < 0) {
  180. log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
  181. goto err;
  182. }
  183. /* Parse protocol versions. */
  184. tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
  185. tor_assert(tok->n_args == 1);
  186. versions = smartlist_new();
  187. smartlist_split_string(versions, tok->args[0], ",",
  188. SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  189. for (i = 0; i < smartlist_len(versions); i++) {
  190. version = (int) tor_parse_long(smartlist_get(versions, i),
  191. 10, 0, INT_MAX, &num_ok, NULL);
  192. if (!num_ok) /* It's a string; let's ignore it. */
  193. continue;
  194. if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
  195. /* Avoid undefined left-shift behaviour. */
  196. continue;
  197. result->protocols |= 1 << version;
  198. }
  199. SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
  200. smartlist_free(versions);
  201. /* Parse encrypted introduction points. Don't verify. */
  202. tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
  203. if (tok) {
  204. if (strcmp(tok->object_type, "MESSAGE")) {
  205. log_warn(LD_DIR, "Bad object type: introduction points should be of "
  206. "type MESSAGE");
  207. goto err;
  208. }
  209. *intro_points_encrypted_out = tor_memdup(tok->object_body,
  210. tok->object_size);
  211. *intro_points_encrypted_size_out = tok->object_size;
  212. } else {
  213. *intro_points_encrypted_out = NULL;
  214. *intro_points_encrypted_size_out = 0;
  215. }
  216. /* Parse and verify signature. */
  217. tok = find_by_keyword(tokens, R_SIGNATURE);
  218. if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
  219. "v2 rendezvous service descriptor") < 0)
  220. goto err;
  221. /* Verify that descriptor ID belongs to public key and secret ID part. */
  222. if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
  223. log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
  224. goto err;
  225. }
  226. rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
  227. secret_id_part);
  228. if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
  229. log_warn(LD_REND, "Parsed descriptor ID does not match "
  230. "computed descriptor ID.");
  231. goto err;
  232. }
  233. goto done;
  234. err:
  235. rend_service_descriptor_free(result);
  236. result = NULL;
  237. done:
  238. if (tokens) {
  239. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  240. smartlist_free(tokens);
  241. }
  242. if (area)
  243. memarea_drop_all(area);
  244. *parsed_out = result;
  245. if (result)
  246. return 0;
  247. return -1;
  248. }
  249. /** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
  250. * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
  251. * write the result to a newly allocated string that is pointed to by
  252. * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
  253. * Return 0 if decryption was successful and -1 otherwise. */
  254. int
  255. rend_decrypt_introduction_points(char **ipos_decrypted,
  256. size_t *ipos_decrypted_size,
  257. const char *descriptor_cookie,
  258. const char *ipos_encrypted,
  259. size_t ipos_encrypted_size)
  260. {
  261. tor_assert(ipos_encrypted);
  262. tor_assert(descriptor_cookie);
  263. if (ipos_encrypted_size < 2) {
  264. log_warn(LD_REND, "Size of encrypted introduction points is too "
  265. "small.");
  266. return -1;
  267. }
  268. if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
  269. char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
  270. session_key[CIPHER_KEY_LEN], *dec;
  271. int declen, client_blocks;
  272. size_t pos = 0, len, client_entries_len;
  273. crypto_digest_t *digest;
  274. crypto_cipher_t *cipher;
  275. client_blocks = (int) ipos_encrypted[1];
  276. client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
  277. REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
  278. if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
  279. log_warn(LD_REND, "Size of encrypted introduction points is too "
  280. "small.");
  281. return -1;
  282. }
  283. memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
  284. digest = crypto_digest_new();
  285. crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
  286. crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
  287. crypto_digest_get_digest(digest, client_id,
  288. REND_BASIC_AUTH_CLIENT_ID_LEN);
  289. crypto_digest_free(digest);
  290. for (pos = 2; pos < 2 + client_entries_len;
  291. pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
  292. if (tor_memeq(ipos_encrypted + pos, client_id,
  293. REND_BASIC_AUTH_CLIENT_ID_LEN)) {
  294. /* Attempt to decrypt introduction points. */
  295. cipher = crypto_cipher_new(descriptor_cookie);
  296. if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
  297. + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
  298. CIPHER_KEY_LEN) < 0) {
  299. log_warn(LD_REND, "Could not decrypt session key for client.");
  300. crypto_cipher_free(cipher);
  301. return -1;
  302. }
  303. crypto_cipher_free(cipher);
  304. len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
  305. dec = tor_malloc_zero(len + 1);
  306. declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
  307. ipos_encrypted + 2 + client_entries_len,
  308. ipos_encrypted_size - 2 - client_entries_len);
  309. if (declen < 0) {
  310. log_warn(LD_REND, "Could not decrypt introduction point string.");
  311. tor_free(dec);
  312. return -1;
  313. }
  314. if (fast_memcmpstart(dec, declen, "introduction-point ")) {
  315. log_warn(LD_REND, "Decrypted introduction points don't "
  316. "look like we could parse them.");
  317. tor_free(dec);
  318. continue;
  319. }
  320. *ipos_decrypted = dec;
  321. *ipos_decrypted_size = declen;
  322. return 0;
  323. }
  324. }
  325. log_warn(LD_REND, "Could not decrypt introduction points. Please "
  326. "check your authorization for this service!");
  327. return -1;
  328. } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
  329. char *dec;
  330. int declen;
  331. if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
  332. log_warn(LD_REND, "Size of encrypted introduction points is too "
  333. "small.");
  334. return -1;
  335. }
  336. dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1);
  337. declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
  338. ipos_encrypted_size -
  339. CIPHER_IV_LEN - 1,
  340. ipos_encrypted + 1,
  341. ipos_encrypted_size - 1);
  342. if (declen < 0) {
  343. log_warn(LD_REND, "Decrypting introduction points failed!");
  344. tor_free(dec);
  345. return -1;
  346. }
  347. *ipos_decrypted = dec;
  348. *ipos_decrypted_size = declen;
  349. return 0;
  350. } else {
  351. log_warn(LD_REND, "Unknown authorization type number: %d",
  352. ipos_encrypted[0]);
  353. return -1;
  354. }
  355. }
  356. /** Parse the encoded introduction points in <b>intro_points_encoded</b> of
  357. * length <b>intro_points_encoded_size</b> and write the result to the
  358. * descriptor in <b>parsed</b>; return the number of successfully parsed
  359. * introduction points or -1 in case of a failure. */
  360. int
  361. rend_parse_introduction_points(rend_service_descriptor_t *parsed,
  362. const char *intro_points_encoded,
  363. size_t intro_points_encoded_size)
  364. {
  365. const char *current_ipo, *end_of_intro_points;
  366. smartlist_t *tokens = NULL;
  367. directory_token_t *tok;
  368. rend_intro_point_t *intro;
  369. extend_info_t *info;
  370. int result, num_ok=1;
  371. memarea_t *area = NULL;
  372. tor_assert(parsed);
  373. /** Function may only be invoked once. */
  374. tor_assert(!parsed->intro_nodes);
  375. if (!intro_points_encoded || intro_points_encoded_size == 0) {
  376. log_warn(LD_REND, "Empty or zero size introduction point list");
  377. goto err;
  378. }
  379. /* Consider one intro point after the other. */
  380. current_ipo = intro_points_encoded;
  381. end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
  382. tokens = smartlist_new();
  383. parsed->intro_nodes = smartlist_new();
  384. area = memarea_new();
  385. while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
  386. "introduction-point ")) {
  387. /* Determine end of string. */
  388. const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
  389. "\nintroduction-point ");
  390. if (!eos)
  391. eos = end_of_intro_points;
  392. else
  393. eos = eos+1;
  394. tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
  395. /* Free tokens and clear token list. */
  396. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  397. smartlist_clear(tokens);
  398. memarea_clear(area);
  399. /* Tokenize string. */
  400. if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
  401. log_warn(LD_REND, "Error tokenizing introduction point");
  402. goto err;
  403. }
  404. /* Advance to next introduction point, if available. */
  405. current_ipo = eos;
  406. /* Check minimum allowed length of introduction point. */
  407. if (smartlist_len(tokens) < 5) {
  408. log_warn(LD_REND, "Impossibly short introduction point.");
  409. goto err;
  410. }
  411. /* Allocate new intro point and extend info. */
  412. intro = tor_malloc_zero(sizeof(rend_intro_point_t));
  413. info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
  414. /* Parse identifier. */
  415. tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
  416. if (base32_decode(info->identity_digest, DIGEST_LEN,
  417. tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
  418. log_warn(LD_REND, "Identity digest contains illegal characters: %s",
  419. tok->args[0]);
  420. rend_intro_point_free(intro);
  421. goto err;
  422. }
  423. /* Write identifier to nickname. */
  424. info->nickname[0] = '$';
  425. base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
  426. info->identity_digest, DIGEST_LEN);
  427. /* Parse IP address. */
  428. tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
  429. if (tor_addr_parse(&info->addr, tok->args[0])<0) {
  430. log_warn(LD_REND, "Could not parse introduction point address.");
  431. rend_intro_point_free(intro);
  432. goto err;
  433. }
  434. if (tor_addr_family(&info->addr) != AF_INET) {
  435. log_warn(LD_REND, "Introduction point address was not ipv4.");
  436. rend_intro_point_free(intro);
  437. goto err;
  438. }
  439. /* Parse onion port. */
  440. tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
  441. info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
  442. &num_ok,NULL);
  443. if (!info->port || !num_ok) {
  444. log_warn(LD_REND, "Introduction point onion port %s is invalid",
  445. escaped(tok->args[0]));
  446. rend_intro_point_free(intro);
  447. goto err;
  448. }
  449. /* Parse onion key. */
  450. tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
  451. if (!crypto_pk_public_exponent_ok(tok->key)) {
  452. log_warn(LD_REND,
  453. "Introduction point's onion key had invalid exponent.");
  454. rend_intro_point_free(intro);
  455. goto err;
  456. }
  457. info->onion_key = tok->key;
  458. tok->key = NULL; /* Prevent free */
  459. /* Parse service key. */
  460. tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
  461. if (!crypto_pk_public_exponent_ok(tok->key)) {
  462. log_warn(LD_REND,
  463. "Introduction point key had invalid exponent.");
  464. rend_intro_point_free(intro);
  465. goto err;
  466. }
  467. intro->intro_key = tok->key;
  468. tok->key = NULL; /* Prevent free */
  469. /* Add extend info to list of introduction points. */
  470. smartlist_add(parsed->intro_nodes, intro);
  471. }
  472. result = smartlist_len(parsed->intro_nodes);
  473. goto done;
  474. err:
  475. result = -1;
  476. done:
  477. /* Free tokens and clear token list. */
  478. if (tokens) {
  479. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  480. smartlist_free(tokens);
  481. }
  482. if (area)
  483. memarea_drop_all(area);
  484. return result;
  485. }
  486. /** Parse the content of a client_key file in <b>ckstr</b> and add
  487. * rend_authorized_client_t's for each parsed client to
  488. * <b>parsed_clients</b>. Return the number of parsed clients as result
  489. * or -1 for failure. */
  490. int
  491. rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
  492. {
  493. int result = -1;
  494. smartlist_t *tokens;
  495. directory_token_t *tok;
  496. const char *current_entry = NULL;
  497. memarea_t *area = NULL;
  498. char *err_msg = NULL;
  499. if (!ckstr || strlen(ckstr) == 0)
  500. return -1;
  501. tokens = smartlist_new();
  502. /* Begin parsing with first entry, skipping comments or whitespace at the
  503. * beginning. */
  504. area = memarea_new();
  505. current_entry = eat_whitespace(ckstr);
  506. while (!strcmpstart(current_entry, "client-name ")) {
  507. rend_authorized_client_t *parsed_entry;
  508. /* Determine end of string. */
  509. const char *eos = strstr(current_entry, "\nclient-name ");
  510. if (!eos)
  511. eos = current_entry + strlen(current_entry);
  512. else
  513. eos = eos + 1;
  514. /* Free tokens and clear token list. */
  515. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  516. smartlist_clear(tokens);
  517. memarea_clear(area);
  518. /* Tokenize string. */
  519. if (tokenize_string(area, current_entry, eos, tokens,
  520. client_keys_token_table, 0)) {
  521. log_warn(LD_REND, "Error tokenizing client keys file.");
  522. goto err;
  523. }
  524. /* Advance to next entry, if available. */
  525. current_entry = eos;
  526. /* Check minimum allowed length of token list. */
  527. if (smartlist_len(tokens) < 2) {
  528. log_warn(LD_REND, "Impossibly short client key entry.");
  529. goto err;
  530. }
  531. /* Parse client name. */
  532. tok = find_by_keyword(tokens, C_CLIENT_NAME);
  533. tor_assert(tok == smartlist_get(tokens, 0));
  534. tor_assert(tok->n_args == 1);
  535. if (!rend_valid_client_name(tok->args[0])) {
  536. log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
  537. "between 1 and %d, and valid characters are "
  538. "[A-Za-z0-9+-_].)", tok->args[0], REND_CLIENTNAME_MAX_LEN);
  539. goto err;
  540. }
  541. /* Check if client name is duplicate. */
  542. if (strmap_get(parsed_clients, tok->args[0])) {
  543. log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
  544. "duplicate client name: '%s'. Ignoring.", tok->args[0]);
  545. goto err;
  546. }
  547. parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
  548. parsed_entry->client_name = tor_strdup(tok->args[0]);
  549. strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
  550. /* Parse client key. */
  551. tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
  552. if (tok) {
  553. parsed_entry->client_key = tok->key;
  554. tok->key = NULL; /* Prevent free */
  555. }
  556. /* Parse descriptor cookie. */
  557. tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
  558. tor_assert(tok->n_args == 1);
  559. if (rend_auth_decode_cookie(tok->args[0], parsed_entry->descriptor_cookie,
  560. NULL, &err_msg) < 0) {
  561. tor_assert(err_msg);
  562. log_warn(LD_REND, "%s", err_msg);
  563. tor_free(err_msg);
  564. goto err;
  565. }
  566. }
  567. result = strmap_size(parsed_clients);
  568. goto done;
  569. err:
  570. result = -1;
  571. done:
  572. /* Free tokens and clear token list. */
  573. SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  574. smartlist_free(tokens);
  575. if (area)
  576. memarea_drop_all(area);
  577. return result;
  578. }