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