-remove debug message
[oweals/gnunet.git] / src / revocation / gnunet-revocation.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013 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-revocation.c
23  * @brief tool for revoking public keys
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_revocation_service.h"
29 #include "gnunet_identity_service.h"
30
31 /**
32  * Pow passes
33  */
34 static unsigned int pow_passes = 1;
35
36 /**
37  * Final status code.
38  */
39 static int ret;
40
41 /**
42  * Was "-p" specified?
43  */
44 static int perform;
45
46 /**
47  * -f option.
48  */
49 static char *filename;
50
51 /**
52  * -R option
53  */
54 static char *revoke_ego;
55
56 /**
57  * -t option.
58  */
59 static char *test_ego;
60
61 /**
62  * -e option.
63  */
64 static unsigned int epochs = 1;
65
66 /**
67  * Handle for revocation query.
68  */
69 static struct GNUNET_REVOCATION_Query *q;
70
71 /**
72  * Handle for revocation.
73  */
74 static struct GNUNET_REVOCATION_Handle *h;
75
76 /**
77  * Handle for our ego lookup.
78  */
79 static struct GNUNET_IDENTITY_EgoLookup *el;
80
81 /**
82  * Our configuration.
83  */
84 static const struct GNUNET_CONFIGURATION_Handle *cfg;
85
86 /**
87  * Number of matching bits required for revocation.
88  */
89 static unsigned long long matching_bits;
90
91 /**
92  * Epoch length
93  */
94 static struct GNUNET_TIME_Relative epoch_duration;
95
96 /**
97  * Task used for proof-of-work calculation.
98  */
99 static struct GNUNET_SCHEDULER_Task *pow_task;
100
101 /**
102  * Proof-of-work object
103  */
104 static struct GNUNET_REVOCATION_PowP proof_of_work;
105
106 /**
107  * Function run if the user aborts with CTRL-C.
108  *
109  * @param cls closure
110  */
111 static void
112 do_shutdown (void *cls)
113 {
114   fprintf (stderr, "%s", _ ("Shutting down...\n"));
115   if (NULL != el)
116   {
117     GNUNET_IDENTITY_ego_lookup_cancel (el);
118     el = NULL;
119   }
120   if (NULL != q)
121   {
122     GNUNET_REVOCATION_query_cancel (q);
123     q = NULL;
124   }
125   if (NULL != h)
126   {
127     GNUNET_REVOCATION_revoke_cancel (h);
128     h = NULL;
129   }
130 }
131
132
133 /**
134  * Print the result from a revocation query.
135  *
136  * @param cls NULL
137  * @param is_valid #GNUNET_YES if the key is still valid, #GNUNET_NO if not, #GNUNET_SYSERR on error
138  */
139 static void
140 print_query_result (void *cls, int is_valid)
141 {
142   q = NULL;
143   switch (is_valid)
144   {
145   case GNUNET_YES:
146     fprintf (stdout, _ ("Key `%s' is valid\n"), test_ego);
147     break;
148
149   case GNUNET_NO:
150     fprintf (stdout, _ ("Key `%s' has been revoked\n"), test_ego);
151     break;
152
153   case GNUNET_SYSERR:
154     fprintf (stdout, "%s", _ ("Internal error\n"));
155     break;
156
157   default:
158     GNUNET_break (0);
159     break;
160   }
161   GNUNET_SCHEDULER_shutdown ();
162 }
163
164
165 /**
166  * Print the result from a revocation request.
167  *
168  * @param cls NULL
169  * @param is_valid #GNUNET_YES if the key is still valid, #GNUNET_NO if not, #GNUNET_SYSERR on error
170  */
171 static void
172 print_revocation_result (void *cls, int is_valid)
173 {
174   h = NULL;
175   switch (is_valid)
176   {
177   case GNUNET_YES:
178     if (NULL != revoke_ego)
179       fprintf (stdout,
180                _ ("Key for ego `%s' is still valid, revocation failed (!)\n"),
181                revoke_ego);
182     else
183       fprintf (stdout, "%s", _ ("Revocation failed (!)\n"));
184     break;
185
186   case GNUNET_NO:
187     if (NULL != revoke_ego)
188       fprintf (stdout,
189                _ ("Key for ego `%s' has been successfully revoked\n"),
190                revoke_ego);
191     else
192       fprintf (stdout, "%s", _ ("Revocation successful.\n"));
193     break;
194
195   case GNUNET_SYSERR:
196     fprintf (stdout,
197              "%s",
198              _ ("Internal error, key revocation might have failed\n"));
199     break;
200
201   default:
202     GNUNET_break (0);
203     break;
204   }
205   GNUNET_SCHEDULER_shutdown ();
206 }
207
208
209 /**
210  * Perform the revocation.
211  */
212 static void
213 perform_revocation ()
214 {
215   h = GNUNET_REVOCATION_revoke (cfg,
216                                 &proof_of_work,
217                                 &print_revocation_result,
218                                 NULL);
219 }
220
221
222 /**
223  * Write the current state of the revocation data
224  * to disk.
225  *
226  * @param rd data to sync
227  */
228 static void
229 sync_pow ()
230 {
231   if ((NULL != filename) &&
232       (sizeof(struct GNUNET_REVOCATION_PowP) !=
233        GNUNET_DISK_fn_write (filename,
234                              &proof_of_work,
235                              sizeof(struct GNUNET_REVOCATION_PowP),
236                              GNUNET_DISK_PERM_USER_READ
237                              | GNUNET_DISK_PERM_USER_WRITE)))
238     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
239 }
240
241
242 /**
243  * Perform the proof-of-work calculation.
244  *
245  * @param cls the `struct RevocationData`
246  */
247 static void
248 calculate_pow_shutdown (void *cls)
249 {
250   struct GNUNET_REVOCATION_PowCalculationHandle *ph = cls;
251   fprintf (stderr, "%s", _ ("Cancelling calculation.\n"));
252   sync_pow ();
253   if (NULL != pow_task)
254   {
255     GNUNET_SCHEDULER_cancel (pow_task);
256     pow_task = NULL;
257   }
258   if (NULL != ph)
259     GNUNET_REVOCATION_pow_stop (ph);
260 }
261
262
263 /**
264  * Perform the proof-of-work calculation.
265  *
266  * @param cls the `struct RevocationData`
267  */
268 static void
269 calculate_pow (void *cls)
270 {
271   struct GNUNET_REVOCATION_PowCalculationHandle *ph = cls;
272
273   /* store temporary results */
274   pow_task = NULL;
275   if (0 == (pow_passes % 128))
276     sync_pow ();
277   /* actually do POW calculation */
278   if (GNUNET_OK == GNUNET_REVOCATION_pow_round (ph))
279   {
280     if ((NULL != filename) &&
281         (sizeof(struct GNUNET_REVOCATION_PowP) !=
282          GNUNET_DISK_fn_write (filename,
283                                &proof_of_work,
284                                sizeof(struct GNUNET_REVOCATION_PowP),
285                                GNUNET_DISK_PERM_USER_READ
286                                | GNUNET_DISK_PERM_USER_WRITE)))
287       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", filename);
288     if (perform)
289     {
290       perform_revocation ();
291     }
292     else
293     {
294       fprintf (stderr, "%s", "\n");
295       fprintf (stderr,
296                _ ("Revocation certificate for `%s' stored in `%s'\n"),
297                revoke_ego,
298                filename);
299       GNUNET_SCHEDULER_shutdown ();
300     }
301     return;
302   }
303   pow_passes++;
304   /**
305    * Otherwise CTRL-C does not work
306    */
307   if (0 == pow_passes % 128)
308     pow_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
309                                              &calculate_pow,
310                                              ph);
311   else
312     pow_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
313                                              &calculate_pow,
314                                              ph);
315
316 }
317
318
319 /**
320  * Function called with the result from the ego lookup.
321  *
322  * @param cls closure
323  * @param ego the ego, NULL if not found
324  */
325 static void
326 ego_callback (void *cls, struct GNUNET_IDENTITY_Ego *ego)
327 {
328   struct GNUNET_CRYPTO_EcdsaPublicKey key;
329   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
330   struct GNUNET_REVOCATION_PowCalculationHandle *ph = NULL;
331
332   el = NULL;
333   if (NULL == ego)
334   {
335     fprintf (stdout, _ ("Ego `%s' not found.\n"), revoke_ego);
336     GNUNET_SCHEDULER_shutdown ();
337     return;
338   }
339   GNUNET_IDENTITY_ego_get_public_key (ego, &key);
340   privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
341   memset (&proof_of_work, 0, sizeof (proof_of_work));
342   if ((NULL != filename) && (GNUNET_YES == GNUNET_DISK_file_test (filename)) &&
343       (sizeof(proof_of_work) ==
344        GNUNET_DISK_fn_read (filename, &proof_of_work, sizeof(proof_of_work))))
345   {
346     if (0 != GNUNET_memcmp (&proof_of_work.key, &key))
347     {
348       fprintf (stderr,
349                _ ("Error: revocation certificate in `%s' is not for `%s'\n"),
350                filename,
351                revoke_ego);
352       return;
353     }
354     if (GNUNET_YES ==
355         GNUNET_REVOCATION_check_pow (&proof_of_work,
356                                      (unsigned int) matching_bits,
357                                      epoch_duration))
358     {
359       fprintf (stderr, "%s", _ ("Revocation certificate ready\n"));
360       if (perform)
361         perform_revocation ();
362       else
363         GNUNET_SCHEDULER_shutdown ();
364       return;
365     }
366     /**
367      * Certificate not yet ready
368      */
369     fprintf (stderr,
370              "%s",
371              _ ("Continuing calculation where left off...\n"));
372     ph = GNUNET_REVOCATION_pow_start (&proof_of_work,
373                                       epochs,
374                                       matching_bits);
375   }
376   fprintf (stderr,
377            "%s",
378            _ ("Revocation certificate not ready, calculating proof of work\n"));
379   if (NULL == ph)
380   {
381     GNUNET_REVOCATION_pow_init (privkey,
382                                 &proof_of_work);
383     ph = GNUNET_REVOCATION_pow_start (&proof_of_work,
384                                       epochs, /* Epochs */
385                                       matching_bits);
386   }
387   pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
388   GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
389 }
390
391
392 /**
393  * Main function that will be run by the scheduler.
394  *
395  * @param cls closure
396  * @param args remaining command-line arguments
397  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
398  * @param c configuration
399  */
400 static void
401 run (void *cls,
402      char *const *args,
403      const char *cfgfile,
404      const struct GNUNET_CONFIGURATION_Handle *c)
405 {
406   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
407
408   cfg = c;
409   if (NULL != test_ego)
410   {
411     if (GNUNET_OK !=
412         GNUNET_CRYPTO_ecdsa_public_key_from_string (test_ego,
413                                                     strlen (test_ego),
414                                                     &pk))
415     {
416       fprintf (stderr, _ ("Public key `%s' malformed\n"), test_ego);
417       return;
418     }
419     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
420     q = GNUNET_REVOCATION_query (cfg, &pk, &print_query_result, NULL);
421     if (NULL != revoke_ego)
422       fprintf (
423         stderr,
424         "%s",
425         _ (
426           "Testing and revoking at the same time is not allowed, only executing test.\n"));
427     return;
428   }
429   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
430                                                           "REVOCATION",
431                                                           "WORKBITS",
432                                                           &matching_bits))
433   {
434     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
435                                "REVOCATION",
436                                "WORKBITS");
437     return;
438   }
439   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
440                                                         "REVOCATION",
441                                                         "EPOCH_DURATION",
442                                                         &epoch_duration))
443   {
444     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
445                                "REVOCATION",
446                                "EPOCH_DURATION");
447     return;
448   }
449
450   if (NULL != revoke_ego)
451   {
452     if (! perform && (NULL == filename))
453     {
454       fprintf (stderr,
455                "%s",
456                _ ("No filename to store revocation certificate given.\n"));
457       return;
458     }
459     /* main code here */
460     el = GNUNET_IDENTITY_ego_lookup (cfg, revoke_ego, &ego_callback, NULL);
461     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
462     return;
463   }
464   if ((NULL != filename) && (perform))
465   {
466     if (sizeof(proof_of_work) != GNUNET_DISK_fn_read (filename,
467                                                       &proof_of_work,
468                                                       sizeof(proof_of_work)))
469     {
470       fprintf (stderr,
471                _ ("Failed to read revocation certificate from `%s'\n"),
472                filename);
473       return;
474     }
475     GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
476     if (GNUNET_YES !=
477         GNUNET_REVOCATION_check_pow (&proof_of_work,
478                                      (unsigned int) matching_bits,
479                                      epoch_duration))
480     {
481       struct GNUNET_REVOCATION_PowCalculationHandle *ph;
482       ph = GNUNET_REVOCATION_pow_start (&proof_of_work,
483                                         epochs, /* Epochs */
484                                         matching_bits);
485
486       pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, ph);
487       GNUNET_SCHEDULER_add_shutdown (&calculate_pow_shutdown, ph);
488       return;
489     }
490     perform_revocation ();
491     return;
492   }
493   fprintf (stderr, "%s", _ ("No action specified. Nothing to do.\n"));
494 }
495
496
497 /**
498  * The main function of gnunet-revocation.
499  *
500  * @param argc number of arguments from the command line
501  * @param argv command line arguments
502  * @return 0 ok, 1 on error
503  */
504 int
505 main (int argc, char *const *argv)
506 {
507   struct GNUNET_GETOPT_CommandLineOption options[] = {
508     GNUNET_GETOPT_option_string ('f',
509                                  "filename",
510                                  "NAME",
511                                  gettext_noop (
512                                    "use NAME for the name of the revocation file"),
513                                  &filename),
514
515     GNUNET_GETOPT_option_string (
516       'R',
517       "revoke",
518       "NAME",
519       gettext_noop (
520         "revoke the private key associated for the the private key associated with the ego NAME "),
521       &revoke_ego),
522
523     GNUNET_GETOPT_option_flag (
524       'p',
525       "perform",
526       gettext_noop (
527         "actually perform revocation, otherwise we just do the precomputation"),
528       &perform),
529
530     GNUNET_GETOPT_option_string ('t',
531                                  "test",
532                                  "KEY",
533                                  gettext_noop (
534                                    "test if the public key KEY has been revoked"),
535                                  &test_ego),
536     GNUNET_GETOPT_option_uint ('e',
537                                "epochs",
538                                "EPOCHS",
539                                gettext_noop (
540                                  "number of epochs to calculate for"),
541                                &epochs),
542
543     GNUNET_GETOPT_OPTION_END
544   };
545
546   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
547     return 2;
548
549   ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
550                                           argv,
551                                           "gnunet-revocation",
552                                           gettext_noop ("help text"),
553                                           options,
554                                           &run,
555                                           NULL))
556         ? ret
557         : 1;
558   GNUNET_free_nz ((void *) argv);
559   return ret;
560 }
561
562
563 /* end of gnunet-revocation.c */