global reindent, now with uncrustify hook enabled
[oweals/gnunet.git] / src / credential / gnunet-credential.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012-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  * @file gnunet-credential.c
22  * @brief command line tool to access command line Credential service
23  * @author Martin Schanzenbach
24  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_credential_service.h>
28 #include <gnunet_gnsrecord_lib.h>
29 #include "credential_misc.h"
30 #include "credential_serialization.h"
31
32 /**
33  * Configuration we are using.
34  */
35 static const struct GNUNET_CONFIGURATION_Handle *cfg;
36
37 /**
38  * EgoLookup
39  */
40 static struct GNUNET_IDENTITY_EgoLookup *el;
41
42 /**
43  * Handle to Credential service.
44  */
45 static struct GNUNET_CREDENTIAL_Handle *credential;
46
47 /**
48  * Desired timeout for the lookup (default is no timeout).
49  */
50 static struct GNUNET_TIME_Relative timeout;
51
52 /**
53  * Handle to verify request
54  */
55 static struct GNUNET_CREDENTIAL_Request *verify_request;
56
57 /**
58  * Handle to collect request
59  */
60 static struct GNUNET_CREDENTIAL_Request *collect_request;
61
62 /**
63  * Task scheduled to handle timeout.
64  */
65 static struct GNUNET_SCHEDULER_Task *tt;
66
67 /**
68  * Subject pubkey string
69  */
70 static char *subject_key;
71
72 /**
73  * Subject credential string
74  */
75 static char *subject_credential;
76
77 /**
78  * Credential TTL
79  */
80 static char *expiration;
81
82 /**
83  * Subject key
84  */
85 struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
86
87 /**
88  * Issuer key
89  */
90 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
91
92
93 /**
94  * Issuer pubkey string
95  */
96 static char *issuer_key;
97
98 /**
99  * ego
100  */
101 static char *ego_name;
102
103 /**
104  * Issuer attribute
105  */
106 static char *issuer_attr;
107
108 /**
109  * Verify mode
110  */
111 static int verify;
112
113 /**
114  * Issue mode
115  */
116 static int create_cred;
117
118 /**
119  * Collect mode
120  */
121 static int collect;
122
123 /**
124  * Task run on shutdown.  Cleans up everything.
125  *
126  * @param cls unused
127  */
128 static void
129 do_shutdown (void *cls)
130 {
131   if (NULL != verify_request)
132   {
133     GNUNET_CREDENTIAL_request_cancel (verify_request);
134     verify_request = NULL;
135   }
136   if (NULL != credential)
137   {
138     GNUNET_CREDENTIAL_disconnect (credential);
139     credential = NULL;
140   }
141   if (NULL != tt)
142   {
143     GNUNET_SCHEDULER_cancel (tt);
144     tt = NULL;
145   }
146 }
147
148
149 /**
150  * Task run on timeout. Triggers shutdown.
151  *
152  * @param cls unused
153  */
154 static void
155 do_timeout (void *cls)
156 {
157   tt = NULL;
158   GNUNET_SCHEDULER_shutdown ();
159 }
160
161 static void
162 handle_collect_result (void *cls,
163                        unsigned int d_count,
164                        struct GNUNET_CREDENTIAL_Delegation *dc,
165                        unsigned int c_count,
166                        struct GNUNET_CREDENTIAL_Credential *cred)
167 {
168   int i;
169   char*line;
170
171   verify_request = NULL;
172   if (NULL != cred)
173   {
174     for (i = 0; i < c_count; i++)
175     {
176       line = GNUNET_CREDENTIAL_credential_to_string (&cred[i]);
177       printf ("%s\n",
178               line);
179       GNUNET_free (line);
180     }
181   }
182
183
184   GNUNET_SCHEDULER_shutdown ();
185 }
186
187
188 static void
189 handle_verify_result (void *cls,
190                       unsigned int d_count,
191                       struct GNUNET_CREDENTIAL_Delegation *dc,
192                       unsigned int c_count,
193                       struct GNUNET_CREDENTIAL_Credential *cred)
194 {
195   int i;
196   char*iss_key;
197   char*sub_key;
198
199   verify_request = NULL;
200   if (NULL == cred)
201     printf ("Failed.\n");
202   else
203   {
204     printf ("Delegation Chain:\n");
205     for (i = 0; i < d_count; i++)
206     {
207       iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key);
208       sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key);
209       if (0 != dc[i].subject_attribute_len)
210       {
211         printf ("(%d) %s.%s <- %s.%s\n", i,
212                 iss_key, dc[i].issuer_attribute,
213                 sub_key, dc[i].subject_attribute);
214       }
215       else
216       {
217         printf ("(%d) %s.%s <- %s\n", i,
218                 iss_key, dc[i].issuer_attribute,
219                 sub_key);
220       }
221       GNUNET_free (iss_key);
222       GNUNET_free (sub_key);
223     }
224     printf ("\nCredentials:\n");
225     for (i = 0; i < c_count; i++)
226     {
227       iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key);
228       sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key);
229       printf ("%s.%s <- %s\n",
230               iss_key, cred[i].issuer_attribute,
231               sub_key);
232       GNUNET_free (iss_key);
233       GNUNET_free (sub_key);
234     }
235     printf ("Successful.\n");
236   }
237
238
239   GNUNET_SCHEDULER_shutdown ();
240 }
241
242 /**
243  * Callback invoked from identity service with ego information.
244  * An @a ego of NULL means the ego was not found.
245  *
246  * @param cls closure with the configuration
247  * @param ego an ego known to identity service, or NULL
248  */
249 static void
250 identity_cb (void *cls,
251              const struct GNUNET_IDENTITY_Ego *ego)
252 {
253   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
254   struct GNUNET_CREDENTIAL_Credential *crd;
255   struct GNUNET_TIME_Absolute etime_abs;
256   struct GNUNET_TIME_Relative etime_rel;
257   char *res;
258
259   el = NULL;
260   if (NULL == ego)
261   {
262     if (NULL != ego_name)
263     {
264       fprintf (stderr,
265                _ ("Ego `%s' not known to identity service\n"),
266                ego_name);
267     }
268     GNUNET_SCHEDULER_shutdown ();
269     return;
270   }
271
272   if (GNUNET_YES == collect)
273   {
274     if (GNUNET_OK !=
275         GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
276                                                     strlen (issuer_key),
277                                                     &issuer_pkey))
278     {
279       fprintf (stderr,
280                _ ("Issuer public key `%s' is not well-formed\n"),
281                issuer_key);
282       GNUNET_SCHEDULER_shutdown ();
283     }
284     privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
285
286     collect_request = GNUNET_CREDENTIAL_collect (credential,
287                                                  &issuer_pkey,
288                                                  issuer_attr,  // TODO argument
289                                                  privkey,
290                                                  &handle_collect_result,
291                                                  NULL);
292     return;
293   }
294
295   // Else issue
296
297   if (NULL == expiration)
298   {
299     fprintf (stderr,
300              "Please specify a TTL\n");
301     GNUNET_SCHEDULER_shutdown ();
302     return;
303   }
304   else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration,
305                                                                &etime_rel))
306   {
307     etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
308   }
309   else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration,
310                                                                &etime_abs))
311   {
312     fprintf (stderr,
313              "%s is not a valid ttl!\n",
314              expiration);
315     GNUNET_SCHEDULER_shutdown ();
316     return;
317   }
318
319
320   privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
321   GNUNET_free_non_null (ego_name);
322   ego_name = NULL;
323   crd = GNUNET_CREDENTIAL_credential_issue (privkey,
324                                             &subject_pkey,
325                                             issuer_attr,
326                                             &etime_abs);
327
328   res = GNUNET_CREDENTIAL_credential_to_string (crd);
329   GNUNET_free (crd);
330   printf ("%s\n", res);
331   GNUNET_SCHEDULER_shutdown ();
332 }
333
334
335
336
337 /**
338  * Main function that will be run.
339  *
340  * @param cls closure
341  * @param args remaining command-line arguments
342  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
343  * @param c configuration
344  */
345 static void
346 run (void *cls,
347      char *const *args,
348      const char *cfgfile,
349      const struct GNUNET_CONFIGURATION_Handle *c)
350 {
351   cfg = c;
352
353
354   tt = GNUNET_SCHEDULER_add_delayed (timeout,
355                                      &do_timeout, NULL);
356   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
357
358   if (GNUNET_YES == collect)
359   {
360     if (NULL == issuer_key)
361     {
362       fprintf (stderr,
363                _ ("Issuer public key not well-formed\n"));
364       GNUNET_SCHEDULER_shutdown ();
365       return;
366     }
367
368     credential = GNUNET_CREDENTIAL_connect (cfg);
369
370     if (NULL == credential)
371     {
372       fprintf (stderr,
373                _ ("Failed to connect to CREDENTIAL\n"));
374       GNUNET_SCHEDULER_shutdown ();
375       return;
376     }
377     if (NULL == issuer_attr)
378     {
379       fprintf (stderr,
380                _ ("You must provide issuer the attribute\n"));
381       GNUNET_SCHEDULER_shutdown ();
382       return;
383     }
384
385     if (NULL == ego_name)
386     {
387       fprintf (stderr,
388                _ ("ego required\n"));
389       GNUNET_SCHEDULER_shutdown ();
390       return;
391     }
392     el = GNUNET_IDENTITY_ego_lookup (cfg,
393                                      ego_name,
394                                      &identity_cb,
395                                      (void *) cfg);
396     return;
397   }
398
399   if (NULL == subject_key)
400   {
401     fprintf (stderr,
402              _ ("Subject public key needed\n"));
403     GNUNET_SCHEDULER_shutdown ();
404     return;
405   }
406   if (GNUNET_OK !=
407       GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
408                                                   strlen (subject_key),
409                                                   &subject_pkey))
410   {
411     fprintf (stderr,
412              _ ("Subject public key `%s' is not well-formed\n"),
413              subject_key);
414     GNUNET_SCHEDULER_shutdown ();
415     return;
416   }
417   if (GNUNET_YES == verify)
418   {
419     if (NULL == issuer_key)
420     {
421       fprintf (stderr,
422                _ ("Issuer public key not well-formed\n"));
423       GNUNET_SCHEDULER_shutdown ();
424       return;
425     }
426     if (GNUNET_OK !=
427         GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
428                                                     strlen (issuer_key),
429                                                     &issuer_pkey))
430     {
431       fprintf (stderr,
432                _ ("Issuer public key `%s' is not well-formed\n"),
433                issuer_key);
434       GNUNET_SCHEDULER_shutdown ();
435       return;
436     }
437     credential = GNUNET_CREDENTIAL_connect (cfg);
438
439     if (NULL == credential)
440     {
441       fprintf (stderr,
442                _ ("Failed to connect to CREDENTIAL\n"));
443       GNUNET_SCHEDULER_shutdown ();
444       return;
445     }
446     if ((NULL == issuer_attr) ||(NULL == subject_credential) )
447     {
448       fprintf (stderr,
449                _ ("You must provide issuer and subject attributes\n"));
450       GNUNET_SCHEDULER_shutdown ();
451       return;
452     }
453
454     // Subject credentials are comma separated
455     char *tmp = GNUNET_strdup (subject_credential);
456     char *tok = strtok (tmp, ",");
457     if (NULL == tok)
458     {
459       fprintf (stderr,
460                "Invalid subject credentials\n");
461       GNUNET_free (tmp);
462       GNUNET_SCHEDULER_shutdown ();
463       return;
464     }
465     int count = 1;
466     int i;
467     while (NULL != (tok = strtok (NULL, ",")))
468       count++;
469     struct GNUNET_CREDENTIAL_Credential credentials[count];
470     struct GNUNET_CREDENTIAL_Credential *cred;
471     GNUNET_free (tmp);
472     tmp = GNUNET_strdup (subject_credential);
473     tok = strtok (tmp, ",");
474     for (i = 0; i < count; i++)
475     {
476       cred = GNUNET_CREDENTIAL_credential_from_string (tok);
477       GNUNET_memcpy (&credentials[i],
478                      cred,
479                      sizeof(struct GNUNET_CREDENTIAL_Credential));
480       credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
481       tok = strtok (NULL, ",");
482       GNUNET_free (cred);
483     }
484
485     verify_request = GNUNET_CREDENTIAL_verify (credential,
486                                                &issuer_pkey,
487                                                issuer_attr,  // TODO argument
488                                                &subject_pkey,
489                                                count,
490                                                credentials,
491                                                &handle_verify_result,
492                                                NULL);
493     for (i = 0; i < count; i++)
494     {
495       GNUNET_free ((char*) credentials[i].issuer_attribute);
496     }
497     GNUNET_free (tmp);
498   }
499   else if (GNUNET_YES == create_cred)
500   {
501     if (NULL == ego_name)
502     {
503       fprintf (stderr,
504                _ ("Issuer ego required\n"));
505       GNUNET_SCHEDULER_shutdown ();
506       return;
507     }
508     el = GNUNET_IDENTITY_ego_lookup (cfg,
509                                      ego_name,
510                                      &identity_cb,
511                                      (void *) cfg);
512     return;
513   }
514   else
515   {
516     fprintf (stderr,
517              _ (
518                "Please specify name to lookup, subject key and issuer key!\n"));
519     GNUNET_SCHEDULER_shutdown ();
520   }
521   return;
522 }
523
524
525 /**
526  * The main function for gnunet-gns.
527  *
528  * @param argc number of arguments from the command line
529  * @param argv command line arguments
530  * @return 0 ok, 1 on error
531  */
532 int
533 main (int argc, char *const *argv)
534 {
535   struct GNUNET_GETOPT_CommandLineOption options[] = {
536     GNUNET_GETOPT_option_flag ('I',
537                                "issue",
538                                gettext_noop ("create credential"),
539                                &create_cred),
540     GNUNET_GETOPT_option_flag ('V',
541                                "verify",
542                                gettext_noop (
543                                  "verify credential against attribute"),
544                                &verify),
545     GNUNET_GETOPT_option_string ('s',
546                                  "subject",
547                                  "PKEY",
548                                  gettext_noop (
549                                    "The public key of the subject to lookup the credential for"),
550                                  &subject_key),
551     GNUNET_GETOPT_option_string ('b',
552                                  "credential",
553                                  "CRED",
554                                  gettext_noop (
555                                    "The name of the credential presented by the subject"),
556                                  &subject_credential),
557     GNUNET_GETOPT_option_string ('i',
558                                  "issuer",
559                                  "PKEY",
560                                  gettext_noop (
561                                    "The public key of the authority to verify the credential against"),
562                                  &issuer_key),
563     GNUNET_GETOPT_option_string ('e',
564                                  "ego",
565                                  "EGO",
566                                  gettext_noop ("The ego to use"),
567                                  &ego_name),
568     GNUNET_GETOPT_option_string ('a',
569                                  "attribute",
570                                  "ATTR",
571                                  gettext_noop (
572                                    "The issuer attribute to verify against or to issue"),
573                                  &issuer_attr),
574     GNUNET_GETOPT_option_string ('T',
575                                  "ttl",
576                                  "EXP",
577                                  gettext_noop (
578                                    "The time to live for the credential"),
579                                  &expiration),
580     GNUNET_GETOPT_option_flag ('g',
581                                "collect",
582                                gettext_noop ("collect credentials"),
583                                &collect),
584     GNUNET_GETOPT_OPTION_END
585   };
586   int ret;
587
588   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
589   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
590     return 2;
591
592   GNUNET_log_setup ("gnunet-credential", "WARNING", NULL);
593   ret =
594     (GNUNET_OK ==
595      GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
596                          _ ("GNUnet credential resolver tool"),
597                          options,
598                          &run, NULL)) ? 0 : 1;
599   GNUNET_free ((void*) argv);
600   return ret;
601 }
602
603 /* end of gnunet-credential.c */