gnunet-service-revocation.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2013, 2014, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file revocation/gnunet-service-revocation.c
  18. * @brief key revocation service
  19. * @author Christian Grothoff
  20. *
  21. * The purpose of this service is to allow users to permanently revoke
  22. * (compromised) keys. This is done by flooding the network with the
  23. * revocation requests. To reduce the attack potential offered by such
  24. * flooding, revocations must include a proof of work. We use the
  25. * set service for efficiently computing the union of revocations of
  26. * peers that connect.
  27. *
  28. * TODO:
  29. * - optimization: avoid sending revocation back to peer that we got it from;
  30. * - optimization: have randomized delay in sending revocations to other peers
  31. * to make it rare to traverse each link twice (NSE-style)
  32. */
  33. #include "platform.h"
  34. #include <math.h>
  35. #include "gnunet_util_lib.h"
  36. #include "gnunet_block_lib.h"
  37. #include "gnunet_constants.h"
  38. #include "gnunet_protocols.h"
  39. #include "gnunet_signatures.h"
  40. #include "gnunet_statistics_service.h"
  41. #include "gnunet_core_service.h"
  42. #include "gnunet_revocation_service.h"
  43. #include "gnunet_set_service.h"
  44. #include "revocation.h"
  45. #include <gcrypt.h>
  46. /**
  47. * Per-peer information.
  48. */
  49. struct PeerEntry
  50. {
  51. /**
  52. * Queue for sending messages to this peer.
  53. */
  54. struct GNUNET_MQ_Handle *mq;
  55. /**
  56. * What is the identity of the peer?
  57. */
  58. struct GNUNET_PeerIdentity id;
  59. /**
  60. * Tasked used to trigger the set union operation.
  61. */
  62. struct GNUNET_SCHEDULER_Task *transmit_task;
  63. /**
  64. * Handle to active set union operation (over revocation sets).
  65. */
  66. struct GNUNET_SET_OperationHandle *so;
  67. };
  68. /**
  69. * Set from all revocations known to us.
  70. */
  71. static struct GNUNET_SET_Handle *revocation_set;
  72. /**
  73. * Hash map with all revoked keys, maps the hash of the public key
  74. * to the respective `struct RevokeMessage`.
  75. */
  76. static struct GNUNET_CONTAINER_MultiHashMap *revocation_map;
  77. /**
  78. * Handle to our current configuration.
  79. */
  80. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  81. /**
  82. * Handle to the statistics service.
  83. */
  84. static struct GNUNET_STATISTICS_Handle *stats;
  85. /**
  86. * Handle to the core service (for flooding)
  87. */
  88. static struct GNUNET_CORE_Handle *core_api;
  89. /**
  90. * Map of all connected peers.
  91. */
  92. static struct GNUNET_CONTAINER_MultiPeerMap *peers;
  93. /**
  94. * The peer identity of this peer.
  95. */
  96. static struct GNUNET_PeerIdentity my_identity;
  97. /**
  98. * File handle for the revocation database.
  99. */
  100. static struct GNUNET_DISK_FileHandle *revocation_db;
  101. /**
  102. * Handle for us listening to incoming revocation set union requests.
  103. */
  104. static struct GNUNET_SET_ListenHandle *revocation_union_listen_handle;
  105. /**
  106. * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
  107. */
  108. static unsigned long long revocation_work_required;
  109. /**
  110. * Our application ID for set union operations. Must be the
  111. * same for all (compatible) peers.
  112. */
  113. static struct GNUNET_HashCode revocation_set_union_app_id;
  114. /**
  115. * Create a new PeerEntry and add it to the peers multipeermap.
  116. *
  117. * @param peer the peer identity
  118. * @return a pointer to the new PeerEntry
  119. */
  120. static struct PeerEntry *
  121. new_peer_entry(const struct GNUNET_PeerIdentity *peer)
  122. {
  123. struct PeerEntry *peer_entry;
  124. peer_entry = GNUNET_new (struct PeerEntry);
  125. peer_entry->id = *peer;
  126. GNUNET_assert (GNUNET_OK ==
  127. GNUNET_CONTAINER_multipeermap_put (peers,
  128. &peer_entry->id,
  129. peer_entry,
  130. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  131. return peer_entry;
  132. }
  133. /**
  134. * An revoke message has been received, check that it is well-formed.
  135. *
  136. * @param rm the message to verify
  137. * @return #GNUNET_YES if the message is verified
  138. * #GNUNET_NO if the key/signature don't verify
  139. */
  140. static int
  141. verify_revoke_message (const struct RevokeMessage *rm)
  142. {
  143. if (GNUNET_YES !=
  144. GNUNET_REVOCATION_check_pow (&rm->public_key,
  145. rm->proof_of_work,
  146. (unsigned int) revocation_work_required))
  147. {
  148. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  149. "Proof of work invalid!\n");
  150. GNUNET_break_op (0);
  151. return GNUNET_NO;
  152. }
  153. if (GNUNET_OK !=
  154. GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
  155. &rm->purpose,
  156. &rm->signature,
  157. &rm->public_key))
  158. {
  159. GNUNET_break_op (0);
  160. return GNUNET_NO;
  161. }
  162. return GNUNET_YES;
  163. }
  164. /**
  165. * Handle client connecting to the service.
  166. *
  167. * @param cls NULL
  168. * @param client the new client
  169. * @param mq the message queue of @a client
  170. * @return @a client
  171. */
  172. static void *
  173. client_connect_cb (void *cls,
  174. struct GNUNET_SERVICE_Client *client,
  175. struct GNUNET_MQ_Handle *mq)
  176. {
  177. return client;
  178. }
  179. /**
  180. * Handle client connecting to the service.
  181. *
  182. * @param cls NULL
  183. * @param client the new client
  184. * @param app_cls must alias @a client
  185. */
  186. static void
  187. client_disconnect_cb (void *cls,
  188. struct GNUNET_SERVICE_Client *client,
  189. void *app_cls)
  190. {
  191. GNUNET_assert (client == app_cls);
  192. }
  193. /**
  194. * Handle QUERY message from client.
  195. *
  196. * @param cls client who sent the message
  197. * @param qm the message received
  198. */
  199. static void
  200. handle_query_message (void *cls,
  201. const struct QueryMessage *qm)
  202. {
  203. struct GNUNET_SERVICE_Client *client = cls;
  204. struct GNUNET_MQ_Envelope *env;
  205. struct QueryResponseMessage *qrm;
  206. struct GNUNET_HashCode hc;
  207. int res;
  208. GNUNET_CRYPTO_hash (&qm->key,
  209. sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  210. &hc);
  211. res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
  212. &hc);
  213. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  214. (GNUNET_NO == res)
  215. ? "Received revocation check for valid key `%s' from client\n"
  216. : "Received revocation check for revoked key `%s' from client\n",
  217. GNUNET_h2s (&hc));
  218. env = GNUNET_MQ_msg (qrm,
  219. GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
  220. qrm->is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
  221. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  222. env);
  223. GNUNET_SERVICE_client_continue (client);
  224. }
  225. /**
  226. * Flood the given revocation message to all neighbours.
  227. *
  228. * @param cls the `struct RevokeMessage` to flood
  229. * @param target a neighbour
  230. * @param value our `struct PeerEntry` for the neighbour
  231. * @return #GNUNET_OK (continue to iterate)
  232. */
  233. static int
  234. do_flood (void *cls,
  235. const struct GNUNET_PeerIdentity *target,
  236. void *value)
  237. {
  238. const struct RevokeMessage *rm = cls;
  239. struct PeerEntry *pe = value;
  240. struct GNUNET_MQ_Envelope *e;
  241. struct RevokeMessage *cp;
  242. if (NULL == pe->mq)
  243. return GNUNET_OK; /* peer connected to us via SET,
  244. but we have no direct CORE
  245. connection for flooding */
  246. e = GNUNET_MQ_msg (cp,
  247. GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
  248. *cp = *rm;
  249. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  250. "Flooding revocation to `%s'\n",
  251. GNUNET_i2s (target));
  252. GNUNET_MQ_send (pe->mq,
  253. e);
  254. return GNUNET_OK;
  255. }
  256. /**
  257. * Publicize revocation message. Stores the message locally in the
  258. * database and passes it to all connected neighbours (and adds it to
  259. * the set for future connections).
  260. *
  261. * @param rm message to publicize
  262. * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
  263. * #GNUNET_SYSERR if the message was malformed
  264. */
  265. static int
  266. publicize_rm (const struct RevokeMessage *rm)
  267. {
  268. struct RevokeMessage *cp;
  269. struct GNUNET_HashCode hc;
  270. struct GNUNET_SET_Element e;
  271. GNUNET_CRYPTO_hash (&rm->public_key,
  272. sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  273. &hc);
  274. if (GNUNET_YES ==
  275. GNUNET_CONTAINER_multihashmap_contains (revocation_map,
  276. &hc))
  277. {
  278. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  279. "Duplicate revocation received from peer. Ignored.\n");
  280. return GNUNET_OK;
  281. }
  282. if (GNUNET_OK !=
  283. verify_revoke_message (rm))
  284. {
  285. GNUNET_break_op (0);
  286. return GNUNET_SYSERR;
  287. }
  288. /* write to disk */
  289. if (sizeof (struct RevokeMessage) !=
  290. GNUNET_DISK_file_write (revocation_db,
  291. rm,
  292. sizeof (struct RevokeMessage)))
  293. {
  294. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
  295. "write");
  296. return GNUNET_NO;
  297. }
  298. if (GNUNET_OK !=
  299. GNUNET_DISK_file_sync (revocation_db))
  300. {
  301. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
  302. "sync");
  303. return GNUNET_NO;
  304. }
  305. /* keep copy in memory */
  306. cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
  307. GNUNET_break (GNUNET_OK ==
  308. GNUNET_CONTAINER_multihashmap_put (revocation_map,
  309. &hc,
  310. cp,
  311. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  312. /* add to set for future connections */
  313. e.size = htons (rm->header.size);
  314. e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
  315. e.data = rm;
  316. if (GNUNET_OK !=
  317. GNUNET_SET_add_element (revocation_set,
  318. &e,
  319. NULL,
  320. NULL))
  321. {
  322. GNUNET_break (0);
  323. return GNUNET_OK;
  324. }
  325. else
  326. {
  327. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  328. "Added revocation info to SET\n");
  329. }
  330. /* flood to neighbours */
  331. GNUNET_CONTAINER_multipeermap_iterate (peers,
  332. &do_flood,
  333. cp);
  334. return GNUNET_OK;
  335. }
  336. /**
  337. * Handle REVOKE message from client.
  338. *
  339. * @param cls client who sent the message
  340. * @param rm the message received
  341. */
  342. static void
  343. handle_revoke_message (void *cls,
  344. const struct RevokeMessage *rm)
  345. {
  346. struct GNUNET_SERVICE_Client *client = cls;
  347. struct GNUNET_MQ_Envelope *env;
  348. struct RevocationResponseMessage *rrm;
  349. int ret;
  350. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  351. "Received REVOKE message from client\n");
  352. if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
  353. {
  354. GNUNET_break_op (0);
  355. GNUNET_SERVICE_client_drop (client);
  356. return;
  357. }
  358. env = GNUNET_MQ_msg (rrm,
  359. GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
  360. rrm->is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
  361. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  362. env);
  363. GNUNET_SERVICE_client_continue (client);
  364. }
  365. /**
  366. * Core handler for flooded revocation messages.
  367. *
  368. * @param cls closure unused
  369. * @param rm revocation message
  370. */
  371. static void
  372. handle_p2p_revoke (void *cls,
  373. const struct RevokeMessage *rm)
  374. {
  375. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  376. "Received REVOKE message\n");
  377. GNUNET_break_op (GNUNET_SYSERR !=
  378. publicize_rm (rm));
  379. }
  380. /**
  381. * Callback for set operation results. Called for each element in the
  382. * result set. Each element contains a revocation, which we should
  383. * validate and then add to our revocation list (and set).
  384. *
  385. * @param cls closure
  386. * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
  387. * @param current_size current set size
  388. * @param status see `enum GNUNET_SET_Status`
  389. */
  390. static void
  391. add_revocation (void *cls,
  392. const struct GNUNET_SET_Element *element,
  393. uint64_t current_size,
  394. enum GNUNET_SET_Status status)
  395. {
  396. struct PeerEntry *peer_entry = cls;
  397. const struct RevokeMessage *rm;
  398. switch (status)
  399. {
  400. case GNUNET_SET_STATUS_OK:
  401. if (element->size != sizeof (struct RevokeMessage))
  402. {
  403. GNUNET_break_op (0);
  404. return;
  405. }
  406. if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
  407. {
  408. GNUNET_STATISTICS_update (stats,
  409. gettext_noop ("# unsupported revocations received via set union"),
  410. 1,
  411. GNUNET_NO);
  412. return;
  413. }
  414. rm = element->data;
  415. (void) handle_p2p_revoke (NULL,
  416. rm);
  417. GNUNET_STATISTICS_update (stats,
  418. gettext_noop ("# revocation messages received via set union"),
  419. 1, GNUNET_NO);
  420. break;
  421. case GNUNET_SET_STATUS_FAILURE:
  422. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  423. _("Error computing revocation set union with %s\n"),
  424. GNUNET_i2s (&peer_entry->id));
  425. peer_entry->so = NULL;
  426. GNUNET_STATISTICS_update (stats,
  427. gettext_noop ("# revocation set unions failed"),
  428. 1,
  429. GNUNET_NO);
  430. break;
  431. case GNUNET_SET_STATUS_HALF_DONE:
  432. break;
  433. case GNUNET_SET_STATUS_DONE:
  434. peer_entry->so = NULL;
  435. GNUNET_STATISTICS_update (stats,
  436. gettext_noop ("# revocation set unions completed"),
  437. 1,
  438. GNUNET_NO);
  439. break;
  440. default:
  441. GNUNET_break (0);
  442. break;
  443. }
  444. }
  445. /**
  446. * The timeout for performing the set union has expired,
  447. * run the set operation on the revocation certificates.
  448. *
  449. * @param cls NULL
  450. */
  451. static void
  452. transmit_task_cb (void *cls)
  453. {
  454. struct PeerEntry *peer_entry = cls;
  455. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  456. "Starting set exchange with peer `%s'\n",
  457. GNUNET_i2s (&peer_entry->id));
  458. peer_entry->transmit_task = NULL;
  459. GNUNET_assert (NULL == peer_entry->so);
  460. peer_entry->so = GNUNET_SET_prepare (&peer_entry->id,
  461. &revocation_set_union_app_id,
  462. NULL,
  463. GNUNET_SET_RESULT_ADDED,
  464. (struct GNUNET_SET_Option[]) {{ 0 }},
  465. &add_revocation,
  466. peer_entry);
  467. if (GNUNET_OK !=
  468. GNUNET_SET_commit (peer_entry->so,
  469. revocation_set))
  470. {
  471. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  472. _("SET service crashed, terminating revocation service\n"));
  473. GNUNET_SCHEDULER_shutdown ();
  474. return;
  475. }
  476. }
  477. /**
  478. * Method called whenever a peer connects. Sets up the PeerEntry and
  479. * schedules the initial revocation set exchange with this peer.
  480. *
  481. * @param cls closure
  482. * @param peer peer identity this notification is about
  483. */
  484. static void *
  485. handle_core_connect (void *cls,
  486. const struct GNUNET_PeerIdentity *peer,
  487. struct GNUNET_MQ_Handle *mq)
  488. {
  489. struct PeerEntry *peer_entry;
  490. struct GNUNET_HashCode my_hash;
  491. struct GNUNET_HashCode peer_hash;
  492. if (0 == memcmp (peer,
  493. &my_identity,
  494. sizeof (my_identity)))
  495. {
  496. return NULL;
  497. }
  498. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  499. "Peer `%s' connected to us\n",
  500. GNUNET_i2s (peer));
  501. GNUNET_STATISTICS_update (stats,
  502. "# peers connected",
  503. 1,
  504. GNUNET_NO);
  505. peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
  506. peer);
  507. if (NULL != peer_entry)
  508. {
  509. /* This can happen if "core"'s notification is a tad late
  510. and CADET+SET were faster and already produced a
  511. #handle_revocation_union_request() for us to deal
  512. with. This should be rare, but isn't impossible. */
  513. peer_entry->mq = mq;
  514. return peer_entry;
  515. }
  516. peer_entry = new_peer_entry (peer);
  517. peer_entry->mq = mq;
  518. GNUNET_CRYPTO_hash (&my_identity,
  519. sizeof (my_identity),
  520. &my_hash);
  521. GNUNET_CRYPTO_hash (peer,
  522. sizeof (*peer),
  523. &peer_hash);
  524. if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
  525. &peer_hash))
  526. {
  527. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  528. "Starting SET operation with peer `%s'\n",
  529. GNUNET_i2s (peer));
  530. peer_entry->transmit_task =
  531. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  532. &transmit_task_cb,
  533. peer_entry);
  534. }
  535. return peer_entry;
  536. }
  537. /**
  538. * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
  539. * any pending transmission requests to that peer.
  540. *
  541. * @param cls closure
  542. * @param peer peer identity this notification is about
  543. * @param internal_cls our `struct PeerEntry` for this peer
  544. */
  545. static void
  546. handle_core_disconnect (void *cls,
  547. const struct GNUNET_PeerIdentity *peer,
  548. void *internal_cls)
  549. {
  550. struct PeerEntry *peer_entry = internal_cls;
  551. if (0 == memcmp (peer,
  552. &my_identity,
  553. sizeof (my_identity)))
  554. return;
  555. GNUNET_assert (NULL != peer_entry);
  556. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  557. "Peer `%s' disconnected from us\n",
  558. GNUNET_i2s (peer));
  559. GNUNET_assert (GNUNET_YES ==
  560. GNUNET_CONTAINER_multipeermap_remove (peers,
  561. peer,
  562. peer_entry));
  563. if (NULL != peer_entry->transmit_task)
  564. {
  565. GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
  566. peer_entry->transmit_task = NULL;
  567. }
  568. if (NULL != peer_entry->so)
  569. {
  570. GNUNET_SET_operation_cancel (peer_entry->so);
  571. peer_entry->so = NULL;
  572. }
  573. GNUNET_free (peer_entry);
  574. GNUNET_STATISTICS_update (stats,
  575. "# peers connected",
  576. -1,
  577. GNUNET_NO);
  578. }
  579. /**
  580. * Free all values in a hash map.
  581. *
  582. * @param cls NULL
  583. * @param key the key
  584. * @param value value to free
  585. * @return #GNUNET_OK (continue to iterate)
  586. */
  587. static int
  588. free_entry (void *cls,
  589. const struct GNUNET_HashCode *key,
  590. void *value)
  591. {
  592. GNUNET_free (value);
  593. return GNUNET_OK;
  594. }
  595. /**
  596. * Task run during shutdown.
  597. *
  598. * @param cls unused
  599. */
  600. static void
  601. shutdown_task (void *cls)
  602. {
  603. if (NULL != revocation_set)
  604. {
  605. GNUNET_SET_destroy (revocation_set);
  606. revocation_set = NULL;
  607. }
  608. if (NULL != revocation_union_listen_handle)
  609. {
  610. GNUNET_SET_listen_cancel (revocation_union_listen_handle);
  611. revocation_union_listen_handle = NULL;
  612. }
  613. if (NULL != core_api)
  614. {
  615. GNUNET_CORE_disconnect (core_api);
  616. core_api = NULL;
  617. }
  618. if (NULL != stats)
  619. {
  620. GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
  621. stats = NULL;
  622. }
  623. if (NULL != peers)
  624. {
  625. GNUNET_CONTAINER_multipeermap_destroy (peers);
  626. peers = NULL;
  627. }
  628. if (NULL != revocation_db)
  629. {
  630. GNUNET_DISK_file_close (revocation_db);
  631. revocation_db = NULL;
  632. }
  633. GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
  634. &free_entry,
  635. NULL);
  636. GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
  637. }
  638. /**
  639. * Called on core init/fail.
  640. *
  641. * @param cls service closure
  642. * @param identity the public identity of this peer
  643. */
  644. static void
  645. core_init (void *cls,
  646. const struct GNUNET_PeerIdentity *identity)
  647. {
  648. if (NULL == identity)
  649. {
  650. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  651. "Connection to core FAILED!\n");
  652. GNUNET_SCHEDULER_shutdown ();
  653. return;
  654. }
  655. my_identity = *identity;
  656. }
  657. /**
  658. * Called when another peer wants to do a set operation with the
  659. * local peer. If a listen error occurs, the 'request' is NULL.
  660. *
  661. * @param cls closure
  662. * @param other_peer the other peer
  663. * @param context_msg message with application specific information from
  664. * the other peer
  665. * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
  666. * to accept it, otherwise the request will be refused
  667. * Note that we can't just return value from the listen callback,
  668. * as it is also necessary to specify the set we want to do the
  669. * operation with, whith sometimes can be derived from the context
  670. * message. It's necessary to specify the timeout.
  671. */
  672. static void
  673. handle_revocation_union_request (void *cls,
  674. const struct GNUNET_PeerIdentity *other_peer,
  675. const struct GNUNET_MessageHeader *context_msg,
  676. struct GNUNET_SET_Request *request)
  677. {
  678. struct PeerEntry *peer_entry;
  679. if (NULL == request)
  680. {
  681. GNUNET_break (0);
  682. return;
  683. }
  684. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  685. "Received set exchange request from peer `%s'\n",
  686. GNUNET_i2s (other_peer));
  687. peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
  688. other_peer);
  689. if (NULL == peer_entry)
  690. {
  691. peer_entry = new_peer_entry (other_peer);
  692. }
  693. if (NULL != peer_entry->so)
  694. {
  695. GNUNET_break_op (0);
  696. return;
  697. }
  698. peer_entry->so = GNUNET_SET_accept (request,
  699. GNUNET_SET_RESULT_ADDED,
  700. (struct GNUNET_SET_Option[]) {{ 0 }},
  701. &add_revocation,
  702. peer_entry);
  703. if (GNUNET_OK !=
  704. GNUNET_SET_commit (peer_entry->so,
  705. revocation_set))
  706. {
  707. GNUNET_break (0);
  708. GNUNET_SCHEDULER_shutdown ();
  709. return;
  710. }
  711. }
  712. /**
  713. * Handle network size estimate clients.
  714. *
  715. * @param cls closure
  716. * @param server the initialized server
  717. * @param c configuration to use
  718. */
  719. static void
  720. run (void *cls,
  721. const struct GNUNET_CONFIGURATION_Handle *c,
  722. struct GNUNET_SERVICE_Handle *service)
  723. {
  724. struct GNUNET_MQ_MessageHandler core_handlers[] = {
  725. GNUNET_MQ_hd_fixed_size (p2p_revoke,
  726. GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
  727. struct RevokeMessage,
  728. NULL),
  729. GNUNET_MQ_handler_end ()
  730. };
  731. char *fn;
  732. uint64_t left;
  733. struct RevokeMessage *rm;
  734. struct GNUNET_HashCode hc;
  735. GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
  736. strlen ("revocation-set-union-application-id"),
  737. &revocation_set_union_app_id);
  738. if (GNUNET_OK !=
  739. GNUNET_CONFIGURATION_get_value_filename (c,
  740. "REVOCATION",
  741. "DATABASE",
  742. &fn))
  743. {
  744. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  745. "REVOCATION",
  746. "DATABASE");
  747. GNUNET_SCHEDULER_shutdown ();
  748. return;
  749. }
  750. cfg = c;
  751. revocation_map = GNUNET_CONTAINER_multihashmap_create (16,
  752. GNUNET_NO);
  753. if (GNUNET_OK !=
  754. GNUNET_CONFIGURATION_get_value_number (cfg,
  755. "REVOCATION",
  756. "WORKBITS",
  757. &revocation_work_required))
  758. {
  759. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  760. "REVOCATION",
  761. "WORKBITS");
  762. GNUNET_SCHEDULER_shutdown ();
  763. GNUNET_free (fn);
  764. return;
  765. }
  766. if (revocation_work_required >= sizeof (struct GNUNET_HashCode) * 8)
  767. {
  768. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  769. "REVOCATION",
  770. "WORKBITS",
  771. _("Value is too large.\n"));
  772. GNUNET_SCHEDULER_shutdown ();
  773. GNUNET_free (fn);
  774. return;
  775. }
  776. revocation_set = GNUNET_SET_create (cfg,
  777. GNUNET_SET_OPERATION_UNION);
  778. revocation_union_listen_handle
  779. = GNUNET_SET_listen (cfg,
  780. GNUNET_SET_OPERATION_UNION,
  781. &revocation_set_union_app_id,
  782. &handle_revocation_union_request,
  783. NULL);
  784. revocation_db = GNUNET_DISK_file_open (fn,
  785. GNUNET_DISK_OPEN_READWRITE |
  786. GNUNET_DISK_OPEN_CREATE,
  787. GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE |
  788. GNUNET_DISK_PERM_GROUP_READ |
  789. GNUNET_DISK_PERM_OTHER_READ);
  790. if (NULL == revocation_db)
  791. {
  792. GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
  793. "REVOCATION",
  794. "DATABASE",
  795. _("Could not open revocation database file!"));
  796. GNUNET_SCHEDULER_shutdown ();
  797. GNUNET_free (fn);
  798. return;
  799. }
  800. if (GNUNET_OK !=
  801. GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
  802. left = 0;
  803. while (left > sizeof (struct RevokeMessage))
  804. {
  805. rm = GNUNET_new (struct RevokeMessage);
  806. if (sizeof (struct RevokeMessage) !=
  807. GNUNET_DISK_file_read (revocation_db,
  808. rm,
  809. sizeof (struct RevokeMessage)))
  810. {
  811. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
  812. "read",
  813. fn);
  814. GNUNET_free (rm);
  815. GNUNET_SCHEDULER_shutdown ();
  816. GNUNET_free (fn);
  817. return;
  818. }
  819. GNUNET_break (0 == ntohl (rm->reserved));
  820. GNUNET_CRYPTO_hash (&rm->public_key,
  821. sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  822. &hc);
  823. GNUNET_break (GNUNET_OK ==
  824. GNUNET_CONTAINER_multihashmap_put (revocation_map,
  825. &hc,
  826. rm,
  827. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  828. }
  829. GNUNET_free (fn);
  830. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  831. NULL);
  832. peers = GNUNET_CONTAINER_multipeermap_create (128,
  833. GNUNET_YES);
  834. /* Connect to core service and register core handlers */
  835. core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
  836. NULL, /* Closure passed to functions */
  837. &core_init, /* Call core_init once connected */
  838. &handle_core_connect, /* Handle connects */
  839. &handle_core_disconnect, /* Handle disconnects */
  840. core_handlers); /* Register these handlers */
  841. if (NULL == core_api)
  842. {
  843. GNUNET_SCHEDULER_shutdown ();
  844. return;
  845. }
  846. stats = GNUNET_STATISTICS_create ("revocation",
  847. cfg);
  848. }
  849. /**
  850. * Define "main" method using service macro.
  851. */
  852. GNUNET_SERVICE_MAIN
  853. ("revocation",
  854. GNUNET_SERVICE_OPTION_NONE,
  855. &run,
  856. &client_connect_cb,
  857. &client_disconnect_cb,
  858. NULL,
  859. GNUNET_MQ_hd_fixed_size (query_message,
  860. GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
  861. struct QueryMessage,
  862. NULL),
  863. GNUNET_MQ_hd_fixed_size (revoke_message,
  864. GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
  865. struct RevokeMessage,
  866. NULL),
  867. GNUNET_MQ_handler_end ());
  868. #if defined(LINUX) && defined(__GLIBC__)
  869. #include <malloc.h>
  870. /**
  871. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  872. */
  873. void __attribute__ ((constructor))
  874. GNUNET_REVOCATION_memory_init ()
  875. {
  876. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  877. mallopt (M_TOP_PAD, 1 * 1024);
  878. malloc_trim (0);
  879. }
  880. #endif
  881. /* end of gnunet-service-revocation.c */