-ensure external symbols have proper prefix for conversation service
[oweals/gnunet.git] / src / revocation / gnunet-service-revocation.c
1 /*
2   This file is part of GNUnet.
3   (C) 2013 Christian Grothoff (and other contributing authors)
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public Licerevocation as published
7   by the Free Software Foundation; either version 3, or (at your
8   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   General Public Licerevocation for more details.
14
15   You should have received a copy of the GNU General Public Licerevocation
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
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  * - load revocations from disk
35  * - store revocations to disk
36  * - handle p2p revocations
37  * - handle p2p connect (trigger SET union)
38  * - handle client revoke message
39  * - handle client query message
40  */
41 #include "platform.h"
42 #include <math.h>
43 #include "gnunet_util_lib.h"
44 #include "gnunet_constants.h"
45 #include "gnunet_protocols.h"
46 #include "gnunet_signatures.h"
47 #include "gnunet_statistics_service.h"
48 #include "gnunet_core_service.h"
49 #include "gnunet_revocation_service.h"
50 #include "gnunet_set_service.h"
51 #include "revocation.h"
52 #include <gcrypt.h>
53
54
55 /**
56  * Per-peer information.
57  */
58 struct PeerEntry
59 {
60
61   /**
62    * Core handle for sending messages to this peer.
63    */
64   struct GNUNET_CORE_TransmitHandle *th;
65
66   /**
67    * What is the identity of the peer?
68    */
69   struct GNUNET_PeerIdentity id;
70
71   /**
72    * Task scheduled to send message to this peer.
73    */
74   GNUNET_SCHEDULER_TaskIdentifier transmit_task;
75
76 };
77
78
79 /**
80  * Set from all revocations known to us.
81  */
82 static struct GNUNET_SET_Handle *revocation_set;
83
84 /**
85  * Handle to our current configuration.
86  */
87 static const struct GNUNET_CONFIGURATION_Handle *cfg;
88
89 /**
90  * Handle to the statistics service.
91  */
92 static struct GNUNET_STATISTICS_Handle *stats;
93
94 /**
95  * Handle to the core service (for flooding)
96  */
97 static struct GNUNET_CORE_Handle *coreAPI;
98
99 /**
100  * Map of all connected peers.
101  */
102 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
103
104 /**
105  * The peer identity of this peer.
106  */
107 static struct GNUNET_PeerIdentity my_identity;
108
109 /**
110  * Handle to this serivce's server.
111  */
112 static struct GNUNET_SERVER_Handle *srv;
113
114 /**
115  * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
116  */
117 static unsigned long long revocation_work_required;
118
119
120 /**
121  * An revoke message has been received, check that it is well-formed.
122  *
123  * @param rm the message to verify
124  * @return #GNUNET_YES if the message is verified
125  *         #GNUNET_NO if the key/signature don't verify
126  */
127 static int
128 verify_revoke_message (const struct GNUNET_REVOCATION_RevokeMessage *rm)
129 {
130   if (GNUNET_YES !=
131       GNUNET_REVOCATION_check_pow (&rm->public_key,
132                                    rm->proof_of_work,
133                                    (unsigned int) revocation_work_required))
134   {
135     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
136                 "Proof of work invalid: %llu!\n",
137                 (unsigned long long)
138                 GNUNET_ntohll (rm->proof_of_work));
139     GNUNET_break_op (0);
140     return GNUNET_NO;
141   }
142   if (GNUNET_OK !=
143       GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
144                                 &rm->purpose,
145                                 &rm->signature,
146                                 &rm->public_key))
147   {
148     GNUNET_break_op (0);
149     return GNUNET_NO;
150   }
151   return GNUNET_YES;
152 }
153
154
155 /**
156  * Handle QUERY message from client.
157  *
158  * @param cls unused
159  * @param client who sent the message
160  * @param message the message received
161  */
162 static void
163 handle_query_message (void *cls, 
164                       struct GNUNET_SERVER_Client *client,
165                       const struct GNUNET_MessageHeader *message)
166 {
167   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
168               "Received QUERY message from client\n");
169   GNUNET_break (0);
170   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
171 }
172
173
174 /**
175  * Handle REVOKE message from client.
176  *
177  * @param cls unused
178  * @param client who sent the message
179  * @param message the message received
180  */
181 static void
182 handle_revoke_message (void *cls, 
183                       struct GNUNET_SERVER_Client *client,
184                       const struct GNUNET_MessageHeader *message)
185 {
186   const struct GNUNET_REVOCATION_RevokeMessage *rm;
187
188   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
189               "Received REVOKE message from client\n");
190   rm = (const struct GNUNET_REVOCATION_RevokeMessage *) message;
191   if (GNUNET_OK != 
192       verify_revoke_message (rm))
193   {
194     GNUNET_break (0);
195     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
196   }
197   GNUNET_break (0); // FIXME: TBD
198   GNUNET_SERVER_receive_done (client, GNUNET_OK);
199 }
200
201
202 /**
203  * Core handler for flooded revocation messages.
204  *
205  * @param cls closure unused
206  * @param message message
207  * @param peer peer identity this message is from (ignored)
208  */
209 static int
210 handle_p2p_revoke_message (void *cls, 
211                            const struct GNUNET_PeerIdentity *peer,
212                            const struct GNUNET_MessageHeader *message)
213 {
214   const struct GNUNET_REVOCATION_RevokeMessage *rm;
215
216
217   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
218               "Received REVOKE message from peer\n");
219   rm = (const struct GNUNET_REVOCATION_RevokeMessage *) message;
220   if (GNUNET_OK != 
221       verify_revoke_message (rm))
222   {
223     GNUNET_break_op (0);
224     return GNUNET_SYSERR;
225   }
226   GNUNET_break (0); // FIXME: TBD
227
228 #if 0
229   /* flood to rest */
230   GNUNET_CONTAINER_multipeermap_iterate (peers, 
231                                          &do_flood,
232                                          &ctx);
233 #endif
234   return GNUNET_OK;
235 }
236
237
238 /**
239  * Method called whenever a peer connects. Sets up the PeerEntry and
240  * schedules the initial revocation set exchange with this peer.
241  *
242  * @param cls closure
243  * @param peer peer identity this notification is about
244  */
245 static void
246 handle_core_connect (void *cls,
247                      const struct GNUNET_PeerIdentity *peer)
248 {
249   struct PeerEntry *peer_entry;
250
251   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
252               GNUNET_i2s (peer));
253   peer_entry = GNUNET_new (struct PeerEntry);
254   peer_entry->id = *peer;
255   GNUNET_assert (GNUNET_OK ==
256                  GNUNET_CONTAINER_multipeermap_put (peers, peer,
257                                                     peer_entry,
258                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
259 #if 0
260   peer_entry->transmit_task =
261       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
262                                     peer_entry);
263 #endif
264   GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
265 }
266
267
268 /**
269  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
270  * any pending transmission requests to that peer.
271  *
272  * @param cls closure
273  * @param peer peer identity this notification is about
274  */
275 static void
276 handle_core_disconnect (void *cls, 
277                         const struct GNUNET_PeerIdentity *peer)
278 {
279   struct PeerEntry *pos;
280
281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282               "Peer `%s' disconnected from us\n",
283               GNUNET_i2s (peer));
284   pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
285   if (NULL == pos)
286   {
287     GNUNET_break (0);
288     return;
289   }
290   GNUNET_assert (GNUNET_YES ==
291                  GNUNET_CONTAINER_multipeermap_remove (peers, peer,
292                                                        pos));
293 #if 0
294   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) 
295   {
296     GNUNET_SCHEDULER_cancel (pos->transmit_task);
297     pos->transmit_task = GNUNET_SCHEDULER_NO_TASK;
298   }
299   if (NULL != pos->th)
300   {
301     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
302     pos->th = NULL;
303   }
304 #endif
305   GNUNET_free (pos);
306   GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
307 }
308
309
310 /**
311  * Task run during shutdown.
312  *
313  * @param cls unused
314  * @param tc unused
315  */
316 static void
317 shutdown_task (void *cls,
318                const struct GNUNET_SCHEDULER_TaskContext *tc)
319 {
320   if (NULL != revocation_set)
321   {
322     GNUNET_SET_destroy (revocation_set);
323     revocation_set = NULL;
324   }
325   if (NULL != coreAPI)
326   {
327     GNUNET_CORE_disconnect (coreAPI);
328     coreAPI = NULL;
329   }
330   if (NULL != stats)
331   {
332     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
333     stats = NULL;
334   }
335   if (NULL != peers)
336   {
337     GNUNET_CONTAINER_multipeermap_destroy (peers);
338     peers = NULL;
339   }
340 }
341
342
343 /**
344  * Called on core init/fail.
345  *
346  * @param cls service closure
347  * @param identity the public identity of this peer
348  */
349 static void
350 core_init (void *cls, 
351            const struct GNUNET_PeerIdentity *identity)
352 {
353   if (NULL == identity)
354   {
355     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
356                 "Connection to core FAILED!\n");
357     GNUNET_SCHEDULER_shutdown ();
358     return;
359   }
360   my_identity = *identity;
361 }
362
363
364 /**
365  * Handle network size estimate clients.
366  *
367  * @param cls closure
368  * @param server the initialized server
369  * @param c configuration to use
370  */
371 static void
372 run (void *cls, 
373      struct GNUNET_SERVER_Handle *server,
374      const struct GNUNET_CONFIGURATION_Handle *c)
375 {
376   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
377     {&handle_query_message, NULL, GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
378      sizeof (struct GNUNET_REVOCATION_QueryMessage)},
379     {&handle_revoke_message, NULL, GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
380      sizeof (struct GNUNET_REVOCATION_RevokeMessage)},
381     {NULL, NULL, 0, 0}
382   };
383   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
384     {&handle_p2p_revoke_message, GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
385      sizeof (struct GNUNET_REVOCATION_RevokeMessage)},
386     {NULL, 0, 0}
387   };
388
389   cfg = c;
390   srv = server;  
391   if (GNUNET_OK !=
392       GNUNET_CONFIGURATION_get_value_number (cfg, "REVOCATION", "WORKBITS",
393                                              &revocation_work_required))
394   {
395     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
396                                "REVOCATION",
397                                "WORKBITS");
398     GNUNET_SCHEDULER_shutdown ();
399     return;
400   }
401   if (revocation_work_required >= sizeof (struct GNUNET_HashCode) * 8)
402   {
403     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
404                                "REVOCATION",
405                                "WORKBITS",
406                                _("Value is too large.\n"));
407     GNUNET_SCHEDULER_shutdown ();
408     return;
409   }
410   revocation_set = GNUNET_SET_create (cfg,
411                                       GNUNET_SET_OPERATION_UNION);
412   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
413                                 NULL);
414   peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
415   GNUNET_SERVER_add_handlers (srv, handlers);
416    /* Connect to core service and register core handlers */
417   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
418                                  NULL,       /* Closure passed to functions */
419                                  &core_init,    /* Call core_init once connected */
420                                  &handle_core_connect,  /* Handle connects */
421                                  &handle_core_disconnect,       /* Handle disconnects */
422                                  NULL,  /* Don't want notified about all incoming messages */
423                                  GNUNET_NO,     /* For header only inbound notification */
424                                  NULL,  /* Don't want notified about all outbound messages */
425                                  GNUNET_NO,     /* For header only outbound notification */
426                                  core_handlers);        /* Register these handlers */
427   if (NULL == coreAPI)
428   {
429     GNUNET_SCHEDULER_shutdown ();
430     return;
431   }
432   stats = GNUNET_STATISTICS_create ("revocation", cfg);
433 }
434
435
436 /**
437  * The main function for the network size estimation service.
438  *
439  * @param argc number of arguments from the command line
440  * @param argv command line arguments
441  * @return 0 ok, 1 on error
442  */
443 int
444 main (int argc, 
445       char *const *argv)
446 {
447   return (GNUNET_OK ==
448           GNUNET_SERVICE_run (argc, argv, "revocation", GNUNET_SERVICE_OPTION_NONE,
449                               &run, NULL)) ? 0 : 1;
450 }
451
452
453 #ifdef LINUX
454 #include <malloc.h>
455
456 /**
457  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
458  */
459 void __attribute__ ((constructor)) 
460 GNUNET_ARM_memory_init ()
461 {
462   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
463   mallopt (M_TOP_PAD, 1 * 1024);
464   malloc_trim (0);
465 }
466 #endif
467
468
469
470 /* end of gnunet-service-revocation.c */