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