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.c1027
1 files changed, 0 insertions, 1027 deletions
diff --git a/src/revocation/gnunet-service-revocation.c b/src/revocation/gnunet-service-revocation.c
deleted file mode 100644
index 5fe0ade98..000000000
--- a/src/revocation/gnunet-service-revocation.c
+++ /dev/null
@@ -1,1027 +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 int
173verify_revoke_message (const struct RevokeMessage *rm)
174{
175 struct GNUNET_REVOCATION_PowP *pow = (struct GNUNET_REVOCATION_PowP *) &rm[1];
176 if (GNUNET_YES != GNUNET_REVOCATION_check_pow (pow,
177 (unsigned
178 int) revocation_work_required,
179 epoch_duration))
180 {
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182 "Proof of work invalid!\n");
183 GNUNET_break_op (0);
184 return GNUNET_NO;
185 }
186 return GNUNET_YES;
187}
188
189
190/**
191 * Handle client connecting to the service.
192 *
193 * @param cls NULL
194 * @param client the new client
195 * @param mq the message queue of @a client
196 * @return @a client
197 */
198static void *
199client_connect_cb (void *cls,
200 struct GNUNET_SERVICE_Client *client,
201 struct GNUNET_MQ_Handle *mq)
202{
203 return client;
204}
205
206
207/**
208 * Handle client connecting to the service.
209 *
210 * @param cls NULL
211 * @param client the new client
212 * @param app_cls must alias @a client
213 */
214static void
215client_disconnect_cb (void *cls,
216 struct GNUNET_SERVICE_Client *client,
217 void *app_cls)
218{
219 GNUNET_assert (client == app_cls);
220}
221
222
223/**
224 * Handle QUERY message from client.
225 *
226 * @param cls client who sent the message
227 * @param qm the message received
228 */
229static void
230handle_query_message (void *cls,
231 const struct QueryMessage *qm)
232{
233 struct GNUNET_SERVICE_Client *client = cls;
234 struct GNUNET_MQ_Envelope *env;
235 struct QueryResponseMessage *qrm;
236 struct GNUNET_HashCode hc;
237 int res;
238
239 GNUNET_CRYPTO_hash (&qm->key,
240 sizeof(struct GNUNET_IDENTITY_PublicKey),
241 &hc);
242 res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
243 &hc);
244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245 (GNUNET_NO == res)
246 ? "Received revocation check for valid key `%s' from client\n"
247 : "Received revocation check for revoked key `%s' from client\n",
248 GNUNET_h2s (&hc));
249 env = GNUNET_MQ_msg (qrm,
250 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
251 qrm->is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
252 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
253 env);
254 GNUNET_SERVICE_client_continue (client);
255}
256
257
258/**
259 * Flood the given revocation message to all neighbours.
260 *
261 * @param cls the `struct RevokeMessage` to flood
262 * @param target a neighbour
263 * @param value our `struct PeerEntry` for the neighbour
264 * @return #GNUNET_OK (continue to iterate)
265 */
266static int
267do_flood (void *cls,
268 const struct GNUNET_PeerIdentity *target,
269 void *value)
270{
271 const struct RevokeMessage *rm = cls;
272 struct PeerEntry *pe = value;
273 struct GNUNET_MQ_Envelope *e;
274 struct RevokeMessage *cp;
275
276 if (NULL == pe->mq)
277 return GNUNET_OK; /* peer connected to us via SET,
278 but we have no direct CORE
279 connection for flooding */
280 e = GNUNET_MQ_msg_extra (cp,
281 htonl (rm->pow_size),
282 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
283 *cp = *rm;
284 memcpy (&cp[1], &rm[1], htonl (rm->pow_size));
285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286 "Flooding revocation to `%s'\n",
287 GNUNET_i2s (target));
288 GNUNET_MQ_send (pe->mq,
289 e);
290 return GNUNET_OK;
291}
292
293
294/**
295 * Publicize revocation message. Stores the message locally in the
296 * database and passes it to all connected neighbours (and adds it to
297 * the set for future connections).
298 *
299 * @param rm message to publicize
300 * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
301 * #GNUNET_SYSERR if the message was malformed
302 */
303static int
304publicize_rm (const struct RevokeMessage *rm)
305{
306 struct RevokeMessage *cp;
307 struct GNUNET_HashCode hc;
308 struct GNUNET_SETU_Element e;
309 ssize_t pklen;
310 const struct GNUNET_IDENTITY_PublicKey *pk;
311
312 struct GNUNET_REVOCATION_PowP *pow = (struct GNUNET_REVOCATION_PowP *) &rm[1];
313 pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1];
314 pklen = GNUNET_IDENTITY_key_get_length (pk);
315 if (0 > pklen)
316 {
317 GNUNET_break_op (0);
318 return GNUNET_SYSERR;
319 }
320 GNUNET_CRYPTO_hash (pk,
321 pklen,
322 &hc);
323 if (GNUNET_YES ==
324 GNUNET_CONTAINER_multihashmap_contains (revocation_map,
325 &hc))
326 {
327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328 "Duplicate revocation received from peer. Ignored.\n");
329 return GNUNET_OK;
330 }
331 if (GNUNET_OK !=
332 verify_revoke_message (rm))
333 {
334 GNUNET_break_op (0);
335 return GNUNET_SYSERR;
336 }
337 /* write to disk */
338 if (sizeof(struct RevokeMessage) !=
339 GNUNET_DISK_file_write (revocation_db,
340 rm,
341 sizeof(struct RevokeMessage)))
342 {
343 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
344 "write");
345 return GNUNET_NO;
346 }
347 if (GNUNET_OK !=
348 GNUNET_DISK_file_sync (revocation_db))
349 {
350 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
351 "sync");
352 return GNUNET_NO;
353 }
354 /* keep copy in memory */
355 cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
356 GNUNET_break (GNUNET_OK ==
357 GNUNET_CONTAINER_multihashmap_put (revocation_map,
358 &hc,
359 cp,
360 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
361 /* add to set for future connections */
362 e.size = htons (rm->header.size);
363 e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
364 e.data = rm;
365 if (GNUNET_OK !=
366 GNUNET_SETU_add_element (revocation_set,
367 &e,
368 NULL,
369 NULL))
370 {
371 GNUNET_break (0);
372 return GNUNET_OK;
373 }
374 else
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Added revocation info to SET\n");
378 }
379 /* flood to neighbours */
380 GNUNET_CONTAINER_multipeermap_iterate (peers,
381 &do_flood,
382 cp);
383 return GNUNET_OK;
384}
385
386
387static int
388check_revoke_message (void *cls,
389 const struct RevokeMessage *rm)
390{
391 uint16_t size;
392
393 size = ntohs (rm->header.size);
394 if (size <= sizeof(struct RevokeMessage) ||
395 (size > UINT16_MAX))
396 {
397 GNUNET_break (0);
398 return GNUNET_SYSERR;
399 }
400 return GNUNET_OK;
401
402}
403
404
405/**
406 * Handle REVOKE message from client.
407 *
408 * @param cls client who sent the message
409 * @param rm the message received
410 */
411static void
412handle_revoke_message (void *cls,
413 const struct RevokeMessage *rm)
414{
415 struct GNUNET_SERVICE_Client *client = cls;
416 struct GNUNET_MQ_Envelope *env;
417 struct RevocationResponseMessage *rrm;
418 int ret;
419
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Received REVOKE message from client\n");
422 if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
423 {
424 GNUNET_break_op (0);
425 GNUNET_SERVICE_client_drop (client);
426 return;
427 }
428 env = GNUNET_MQ_msg (rrm,
429 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
430 rrm->is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
431 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
432 env);
433 GNUNET_SERVICE_client_continue (client);
434}
435
436
437static int
438check_p2p_revoke (void *cls,
439 const struct RevokeMessage *rm)
440{
441 uint16_t size;
442
443 size = ntohs (rm->header.size);
444 if (size <= sizeof(struct RevokeMessage))
445 {
446 GNUNET_break (0);
447 return GNUNET_SYSERR;
448 }
449 return GNUNET_OK;
450
451}
452
453
454/**
455 * Core handler for flooded revocation messages.
456 *
457 * @param cls closure unused
458 * @param rm revocation message
459 */
460static void
461handle_p2p_revoke (void *cls,
462 const struct RevokeMessage *rm)
463{
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 "Received REVOKE message\n");
466 GNUNET_break_op (GNUNET_SYSERR !=
467 publicize_rm (rm));
468}
469
470
471/**
472 * Callback for set operation results. Called for each element in the
473 * result set. Each element contains a revocation, which we should
474 * validate and then add to our revocation list (and set).
475 *
476 * @param cls closure
477 * @param element a result element, only valid if status is #GNUNET_SETU_STATUS_OK
478 * @param current_size current set size
479 * @param status see `enum GNUNET_SETU_Status`
480 */
481static void
482add_revocation (void *cls,
483 const struct GNUNET_SETU_Element *element,
484 uint64_t current_size,
485 enum GNUNET_SETU_Status status)
486{
487 struct PeerEntry *peer_entry = cls;
488 const struct RevokeMessage *rm;
489
490 switch (status)
491 {
492 case GNUNET_SETU_STATUS_ADD_LOCAL:
493 if (element->size != sizeof(struct RevokeMessage))
494 {
495 GNUNET_break_op (0);
496 return;
497 }
498 if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
499 {
500 GNUNET_STATISTICS_update (stats,
501 gettext_noop (
502 "# unsupported revocations received via set union"),
503 1,
504 GNUNET_NO);
505 return;
506 }
507 rm = element->data;
508 (void) handle_p2p_revoke (NULL,
509 rm);
510 GNUNET_STATISTICS_update (stats,
511 gettext_noop (
512 "# revocation messages received via set union"),
513 1, GNUNET_NO);
514 break;
515 case GNUNET_SETU_STATUS_FAILURE:
516 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
517 _ ("Error computing revocation set union with %s\n"),
518 GNUNET_i2s (&peer_entry->id));
519 peer_entry->so = NULL;
520 GNUNET_STATISTICS_update (stats,
521 gettext_noop ("# revocation set unions failed"),
522 1,
523 GNUNET_NO);
524 break;
525 case GNUNET_SETU_STATUS_DONE:
526 peer_entry->so = NULL;
527 GNUNET_STATISTICS_update (stats,
528 gettext_noop (
529 "# revocation set unions completed"),
530 1,
531 GNUNET_NO);
532 break;
533 default:
534 GNUNET_break (0);
535 break;
536 }
537}
538
539
540/**
541 * The timeout for performing the set union has expired,
542 * run the set operation on the revocation certificates.
543 *
544 * @param cls NULL
545 */
546static void
547transmit_task_cb (void *cls)
548{
549 struct PeerEntry *peer_entry = cls;
550
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Starting set exchange with peer `%s'\n",
553 GNUNET_i2s (&peer_entry->id));
554 peer_entry->transmit_task = NULL;
555 GNUNET_assert (NULL == peer_entry->so);
556 peer_entry->so = GNUNET_SETU_prepare (&peer_entry->id,
557 &revocation_set_union_app_id,
558 NULL,
559 (struct GNUNET_SETU_Option[]) { { 0 } },
560 &add_revocation,
561 peer_entry);
562 if (GNUNET_OK !=
563 GNUNET_SETU_commit (peer_entry->so,
564 revocation_set))
565 {
566 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
567 _ ("SET service crashed, terminating revocation service\n"));
568 GNUNET_SCHEDULER_shutdown ();
569 return;
570 }
571}
572
573
574/**
575 * Method called whenever a peer connects. Sets up the PeerEntry and
576 * schedules the initial revocation set exchange with this peer.
577 *
578 * @param cls closure
579 * @param peer peer identity this notification is about
580 */
581static void *
582handle_core_connect (void *cls,
583 const struct GNUNET_PeerIdentity *peer,
584 struct GNUNET_MQ_Handle *mq)
585{
586 struct PeerEntry *peer_entry;
587 struct GNUNET_HashCode my_hash;
588 struct GNUNET_HashCode peer_hash;
589
590 if (0 == GNUNET_memcmp (peer,
591 &my_identity))
592 {
593 return NULL;
594 }
595
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 "Peer `%s' connected to us\n",
598 GNUNET_i2s (peer));
599 GNUNET_STATISTICS_update (stats,
600 "# peers connected",
601 1,
602 GNUNET_NO);
603 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
604 peer);
605 if (NULL != peer_entry)
606 {
607 /* This can happen if "core"'s notification is a tad late
608 and CADET+SET were faster and already produced a
609 #handle_revocation_union_request() for us to deal
610 with. This should be rare, but isn't impossible. */
611 peer_entry->mq = mq;
612 return peer_entry;
613 }
614 peer_entry = new_peer_entry (peer);
615 peer_entry->mq = mq;
616 GNUNET_CRYPTO_hash (&my_identity,
617 sizeof(my_identity),
618 &my_hash);
619 GNUNET_CRYPTO_hash (peer,
620 sizeof(*peer),
621 &peer_hash);
622 if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
623 &peer_hash))
624 {
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "Starting SET operation with peer `%s'\n",
627 GNUNET_i2s (peer));
628 peer_entry->transmit_task =
629 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
630 &transmit_task_cb,
631 peer_entry);
632 }
633 return peer_entry;
634}
635
636
637/**
638 * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
639 * any pending transmission requests to that peer.
640 *
641 * @param cls closure
642 * @param peer peer identity this notification is about
643 * @param internal_cls our `struct PeerEntry` for this peer
644 */
645static void
646handle_core_disconnect (void *cls,
647 const struct GNUNET_PeerIdentity *peer,
648 void *internal_cls)
649{
650 struct PeerEntry *peer_entry = internal_cls;
651
652 if (0 == GNUNET_memcmp (peer,
653 &my_identity))
654 return;
655 GNUNET_assert (NULL != peer_entry);
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657 "Peer `%s' disconnected from us\n",
658 GNUNET_i2s (peer));
659 GNUNET_assert (GNUNET_YES ==
660 GNUNET_CONTAINER_multipeermap_remove (peers,
661 peer,
662 peer_entry));
663 if (NULL != peer_entry->transmit_task)
664 {
665 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
666 peer_entry->transmit_task = NULL;
667 }
668 if (NULL != peer_entry->so)
669 {
670 GNUNET_SETU_operation_cancel (peer_entry->so);
671 peer_entry->so = NULL;
672 }
673 GNUNET_free (peer_entry);
674 GNUNET_STATISTICS_update (stats,
675 "# peers connected",
676 -1,
677 GNUNET_NO);
678}
679
680
681/**
682 * Free all values in a hash map.
683 *
684 * @param cls NULL
685 * @param key the key
686 * @param value value to free
687 * @return #GNUNET_OK (continue to iterate)
688 */
689static int
690free_entry (void *cls,
691 const struct GNUNET_HashCode *key,
692 void *value)
693{
694 GNUNET_free (value);
695 return GNUNET_OK;
696}
697
698
699/**
700 * Task run during shutdown.
701 *
702 * @param cls unused
703 */
704static void
705shutdown_task (void *cls)
706{
707 if (NULL != revocation_set)
708 {
709 GNUNET_SETU_destroy (revocation_set);
710 revocation_set = NULL;
711 }
712 if (NULL != revocation_union_listen_handle)
713 {
714 GNUNET_SETU_listen_cancel (revocation_union_listen_handle);
715 revocation_union_listen_handle = NULL;
716 }
717 if (NULL != core_api)
718 {
719 GNUNET_CORE_disconnect (core_api);
720 core_api = NULL;
721 }
722 if (NULL != stats)
723 {
724 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
725 stats = NULL;
726 }
727 if (NULL != peers)
728 {
729 GNUNET_CONTAINER_multipeermap_destroy (peers);
730 peers = NULL;
731 }
732 if (NULL != revocation_db)
733 {
734 GNUNET_DISK_file_close (revocation_db);
735 revocation_db = NULL;
736 }
737 GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
738 &free_entry,
739 NULL);
740 GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
741}
742
743
744/**
745 * Called on core init/fail.
746 *
747 * @param cls service closure
748 * @param identity the public identity of this peer
749 */
750static void
751core_init (void *cls,
752 const struct GNUNET_PeerIdentity *identity)
753{
754 if (NULL == identity)
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "Connection to core FAILED!\n");
758 GNUNET_SCHEDULER_shutdown ();
759 return;
760 }
761 my_identity = *identity;
762}
763
764
765/**
766 * Called when another peer wants to do a set operation with the
767 * local peer. If a listen error occurs, the 'request' is NULL.
768 *
769 * @param cls closure
770 * @param other_peer the other peer
771 * @param context_msg message with application specific information from
772 * the other peer
773 * @param request request from the other peer (never NULL), use GNUNET_SETU_accept()
774 * to accept it, otherwise the request will be refused
775 * Note that we can't just return value from the listen callback,
776 * as it is also necessary to specify the set we want to do the
777 * operation with, which sometimes can be derived from the context
778 * message. It's necessary to specify the timeout.
779 */
780static void
781handle_revocation_union_request (void *cls,
782 const struct GNUNET_PeerIdentity *other_peer,
783 const struct GNUNET_MessageHeader *context_msg,
784 struct GNUNET_SETU_Request *request)
785{
786 struct PeerEntry *peer_entry;
787
788 if (NULL == request)
789 {
790 GNUNET_break (0);
791 return;
792 }
793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
794 "Received set exchange request from peer `%s'\n",
795 GNUNET_i2s (other_peer));
796 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
797 other_peer);
798 if (NULL == peer_entry)
799 {
800 peer_entry = new_peer_entry (other_peer);
801 }
802 if (NULL != peer_entry->so)
803 {
804 GNUNET_break_op (0);
805 return;
806 }
807 peer_entry->so = GNUNET_SETU_accept (request,
808 (struct GNUNET_SETU_Option[]) { { 0 } },
809 &add_revocation,
810 peer_entry);
811 if (GNUNET_OK !=
812 GNUNET_SETU_commit (peer_entry->so,
813 revocation_set))
814 {
815 GNUNET_break (0);
816 GNUNET_SCHEDULER_shutdown ();
817 return;
818 }
819}
820
821
822/**
823 * Handle network size estimate clients.
824 *
825 * @param cls closure
826 * @param server the initialized server
827 * @param c configuration to use
828 */
829static void
830run (void *cls,
831 const struct GNUNET_CONFIGURATION_Handle *c,
832 struct GNUNET_SERVICE_Handle *service)
833{
834 struct GNUNET_MQ_MessageHandler core_handlers[] = {
835 GNUNET_MQ_hd_var_size (p2p_revoke,
836 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
837 struct RevokeMessage,
838 NULL),
839 GNUNET_MQ_handler_end ()
840 };
841 char *fn;
842 uint64_t left;
843 struct RevokeMessage *rm;
844 struct GNUNET_HashCode hc;
845 const struct GNUNET_IDENTITY_PublicKey *pk;
846
847 GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
848 strlen ("revocation-set-union-application-id"),
849 &revocation_set_union_app_id);
850 if (GNUNET_OK !=
851 GNUNET_CONFIGURATION_get_value_filename (c,
852 "REVOCATION",
853 "DATABASE",
854 &fn))
855 {
856 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
857 "REVOCATION",
858 "DATABASE");
859 GNUNET_SCHEDULER_shutdown ();
860 return;
861 }
862 cfg = c;
863 revocation_map = GNUNET_CONTAINER_multihashmap_create (16,
864 GNUNET_NO);
865 if (GNUNET_OK !=
866 GNUNET_CONFIGURATION_get_value_number (cfg,
867 "REVOCATION",
868 "WORKBITS",
869 &revocation_work_required))
870 {
871 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
872 "REVOCATION",
873 "WORKBITS");
874 GNUNET_SCHEDULER_shutdown ();
875 GNUNET_free (fn);
876 return;
877 }
878 if (revocation_work_required >= sizeof(struct GNUNET_HashCode) * 8)
879 {
880 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
881 "REVOCATION",
882 "WORKBITS",
883 _ ("Value is too large.\n"));
884 GNUNET_SCHEDULER_shutdown ();
885 GNUNET_free (fn);
886 return;
887 }
888 if (GNUNET_OK !=
889 GNUNET_CONFIGURATION_get_value_time (cfg,
890 "REVOCATION",
891 "EPOCH_DURATION",
892 &epoch_duration))
893 {
894 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
895 "REVOCATION",
896 "EPOCH_DURATION");
897 GNUNET_SCHEDULER_shutdown ();
898 GNUNET_free (fn);
899 return;
900 }
901
902 revocation_set = GNUNET_SETU_create (cfg);
903 revocation_union_listen_handle
904 = GNUNET_SETU_listen (cfg,
905 &revocation_set_union_app_id,
906 &handle_revocation_union_request,
907 NULL);
908 revocation_db = GNUNET_DISK_file_open (fn,
909 GNUNET_DISK_OPEN_READWRITE
910 | GNUNET_DISK_OPEN_CREATE,
911 GNUNET_DISK_PERM_USER_READ
912 | GNUNET_DISK_PERM_USER_WRITE
913 | GNUNET_DISK_PERM_GROUP_READ
914 | GNUNET_DISK_PERM_OTHER_READ);
915 if (NULL == revocation_db)
916 {
917 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
918 "REVOCATION",
919 "DATABASE",
920 _ ("Could not open revocation database file!"));
921 GNUNET_SCHEDULER_shutdown ();
922 GNUNET_free (fn);
923 return;
924 }
925 if (GNUNET_OK !=
926 GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
927 left = 0;
928 while (left > sizeof(struct RevokeMessage))
929 {
930 rm = GNUNET_new (struct RevokeMessage);
931 if (sizeof(struct RevokeMessage) !=
932 GNUNET_DISK_file_read (revocation_db,
933 rm,
934 sizeof(struct RevokeMessage)))
935 {
936 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
937 "read",
938 fn);
939 GNUNET_free (rm);
940 GNUNET_SCHEDULER_shutdown ();
941 GNUNET_free (fn);
942 return;
943 }
944 struct GNUNET_REVOCATION_PowP *pow = (struct
945 GNUNET_REVOCATION_PowP *) &rm[1];
946 ssize_t ksize;
947 pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1];
948 ksize = GNUNET_IDENTITY_key_get_length (pk);
949 if (0 > ksize)
950 {
951 GNUNET_break_op (0);
952 GNUNET_free (rm);
953 GNUNET_free (fn);
954 return;
955 }
956 GNUNET_CRYPTO_hash (pk,
957 ksize,
958 &hc);
959 GNUNET_break (GNUNET_OK ==
960 GNUNET_CONTAINER_multihashmap_put (revocation_map,
961 &hc,
962 rm,
963 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
964 }
965 GNUNET_free (fn);
966
967 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
968 NULL);
969 peers = GNUNET_CONTAINER_multipeermap_create (128,
970 GNUNET_YES);
971 /* Connect to core service and register core handlers */
972 core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
973 NULL, /* Closure passed to functions */
974 &core_init, /* Call core_init once connected */
975 &handle_core_connect, /* Handle connects */
976 &handle_core_disconnect, /* Handle disconnects */
977 core_handlers); /* Register these handlers */
978 if (NULL == core_api)
979 {
980 GNUNET_SCHEDULER_shutdown ();
981 return;
982 }
983 stats = GNUNET_STATISTICS_create ("revocation",
984 cfg);
985}
986
987
988/**
989 * Define "main" method using service macro.
990 */
991GNUNET_SERVICE_MAIN
992 ("revocation",
993 GNUNET_SERVICE_OPTION_NONE,
994 &run,
995 &client_connect_cb,
996 &client_disconnect_cb,
997 NULL,
998 GNUNET_MQ_hd_fixed_size (query_message,
999 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
1000 struct QueryMessage,
1001 NULL),
1002 GNUNET_MQ_hd_var_size (revoke_message,
1003 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
1004 struct RevokeMessage,
1005 NULL),
1006 GNUNET_MQ_handler_end ());
1007
1008
1009#if defined(__linux__) && defined(__GLIBC__)
1010#include <malloc.h>
1011
1012/**
1013 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1014 */
1015void __attribute__ ((constructor))
1016GNUNET_REVOCATION_memory_init ()
1017{
1018 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1019 mallopt (M_TOP_PAD, 1 * 1024);
1020 malloc_trim (0);
1021}
1022
1023
1024#endif
1025
1026
1027/* end of gnunet-service-revocation.c */