src: for every AGPL3.0 file, add SPDX identifier.
[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       } else {
215         printf ("(%d) %s.%s <- %s\n", i,
216                 iss_key, dc[i].issuer_attribute,
217                 sub_key);
218       }
219       GNUNET_free (iss_key);
220       GNUNET_free (sub_key);
221     }
222     printf("\nCredentials:\n");
223     for (i=0;i<c_count;i++)
224     {
225       iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key);
226       sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key);
227       printf ("%s.%s <- %s\n",
228               iss_key, cred[i].issuer_attribute,
229               sub_key);
230       GNUNET_free (iss_key);
231       GNUNET_free (sub_key);
232
233     }
234     printf ("Successful.\n");
235   }
236
237
238   GNUNET_SCHEDULER_shutdown ();
239 }
240
241 /**
242  * Callback invoked from identity service with ego information.
243  * An @a ego of NULL means the ego was not found.
244  *
245  * @param cls closure with the configuration
246  * @param ego an ego known to identity service, or NULL
247  */
248 static void
249 identity_cb (void *cls,
250              const struct GNUNET_IDENTITY_Ego *ego)
251 {
252   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
253   struct GNUNET_CREDENTIAL_Credential *crd;
254   struct GNUNET_TIME_Absolute etime_abs;
255   struct GNUNET_TIME_Relative etime_rel;
256   char *res;
257
258   el = NULL;
259   if (NULL == ego)
260   {
261     if (NULL != ego_name)
262     {
263       fprintf (stderr,
264                _("Ego `%s' not known to identity service\n"),
265                ego_name);
266     }
267     GNUNET_SCHEDULER_shutdown ();
268     return;
269   }
270
271   if (GNUNET_YES == collect)
272   {
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   } else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration,
304                                                                  &etime_rel))
305   {
306     etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
307   } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration,
308                                                                  &etime_abs))
309   {
310     fprintf (stderr,
311              "%s is not a valid ttl!\n",
312              expiration);
313     GNUNET_SCHEDULER_shutdown ();
314     return;
315   }
316
317
318   privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
319   GNUNET_free_non_null (ego_name);
320   ego_name = NULL;
321   crd = GNUNET_CREDENTIAL_credential_issue (privkey,
322                                             &subject_pkey,
323                                             issuer_attr,
324                                             &etime_abs);
325
326   res = GNUNET_CREDENTIAL_credential_to_string (crd);
327   GNUNET_free (crd);
328   printf ("%s\n", res);
329   GNUNET_SCHEDULER_shutdown ();
330 }
331
332
333
334
335 /**
336  * Main function that will be run.
337  *
338  * @param cls closure
339  * @param args remaining command-line arguments
340  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
341  * @param c configuration
342  */
343 static void
344 run (void *cls,
345      char *const *args,
346      const char *cfgfile,
347      const struct GNUNET_CONFIGURATION_Handle *c)
348 {
349
350   cfg = c;
351
352
353   tt = GNUNET_SCHEDULER_add_delayed (timeout,
354                                      &do_timeout, NULL);
355   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
356
357   if (GNUNET_YES == collect) {
358     if (NULL == issuer_key)
359     {
360       fprintf (stderr,
361                _("Issuer public key not well-formed\n"));
362       GNUNET_SCHEDULER_shutdown ();
363       return;
364
365     }
366
367     credential = GNUNET_CREDENTIAL_connect (cfg);
368
369     if (NULL == credential)
370     {
371       fprintf (stderr,
372                _("Failed to connect to CREDENTIAL\n"));
373       GNUNET_SCHEDULER_shutdown ();
374       return;
375     }
376     if (NULL == issuer_attr)
377     {
378       fprintf (stderr,
379                _("You must provide issuer the attribute\n"));
380       GNUNET_SCHEDULER_shutdown ();
381       return;
382     }
383
384     if (NULL == ego_name)
385     {
386       fprintf (stderr,
387                _("ego required\n"));
388       GNUNET_SCHEDULER_shutdown ();
389       return;
390
391     }
392     el = GNUNET_IDENTITY_ego_lookup (cfg,
393                                      ego_name,
394                                      &identity_cb,
395                                      (void *) cfg);
396     return;
397
398   } 
399
400   if (NULL == subject_key)
401   {
402     fprintf (stderr,
403              _("Subject public key needed\n"));
404     GNUNET_SCHEDULER_shutdown ();
405     return;
406
407   }
408   if (GNUNET_OK !=
409       GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
410                                                   strlen (subject_key),
411                                                   &subject_pkey))
412   {
413     fprintf (stderr,
414              _("Subject public key `%s' is not well-formed\n"),
415              subject_key);
416     GNUNET_SCHEDULER_shutdown ();
417     return;
418   }
419   if (GNUNET_YES == verify) {
420     if (NULL == issuer_key)
421     {
422       fprintf (stderr,
423                _("Issuer public key not well-formed\n"));
424       GNUNET_SCHEDULER_shutdown ();
425       return;
426
427     }
428     if (GNUNET_OK !=
429         GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
430                                                     strlen (issuer_key),
431                                                     &issuer_pkey))
432     {
433       fprintf (stderr,
434                _("Issuer public key `%s' is not well-formed\n"),
435                issuer_key);
436       GNUNET_SCHEDULER_shutdown ();
437       return;
438     }
439     credential = GNUNET_CREDENTIAL_connect (cfg);
440
441     if (NULL == credential)
442     {
443       fprintf (stderr,
444                _("Failed to connect to CREDENTIAL\n"));
445       GNUNET_SCHEDULER_shutdown ();
446       return;
447     }
448     if (NULL == issuer_attr || NULL == subject_credential)
449     {
450       fprintf (stderr,
451                _("You must provide issuer and subject attributes\n"));
452       GNUNET_SCHEDULER_shutdown ();
453       return;
454     }
455
456     //Subject credentials are comma separated
457     char *tmp = GNUNET_strdup (subject_credential);
458     char *tok = strtok (tmp, ",");
459     if (NULL == tok)
460     {
461       fprintf (stderr,
462                "Invalid subject credentials\n");
463       GNUNET_free (tmp);
464       GNUNET_SCHEDULER_shutdown ();
465       return;
466     }
467     int count = 1;
468     int i;
469     while (NULL != (tok = strtok(NULL, ",")))
470       count++;
471     struct GNUNET_CREDENTIAL_Credential credentials[count];
472     struct GNUNET_CREDENTIAL_Credential *cred;
473     GNUNET_free (tmp);
474     tmp = GNUNET_strdup (subject_credential);
475     tok = strtok (tmp, ",");
476     for (i=0;i<count;i++)
477     {
478       cred = GNUNET_CREDENTIAL_credential_from_string (tok);
479       GNUNET_memcpy (&credentials[i],
480                      cred,
481                      sizeof (struct GNUNET_CREDENTIAL_Credential));
482       credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
483       tok = strtok(NULL, ",");
484       GNUNET_free (cred);
485     }
486
487     verify_request = GNUNET_CREDENTIAL_verify(credential,
488                                               &issuer_pkey,
489                                               issuer_attr, //TODO argument
490                                               &subject_pkey,
491                                               count,
492                                               credentials,
493                                               &handle_verify_result,
494                                               NULL);
495     for (i=0;i<count;i++)
496     {
497       GNUNET_free ((char*)credentials[i].issuer_attribute);
498     }
499     GNUNET_free (tmp);
500   } else if (GNUNET_YES == create_cred) {
501     if (NULL == ego_name)
502     {
503       fprintf (stderr,
504                _("Issuer ego required\n"));
505       GNUNET_SCHEDULER_shutdown ();
506       return;
507
508     }
509     el = GNUNET_IDENTITY_ego_lookup (cfg,
510                                      ego_name,
511                                      &identity_cb,
512                                      (void *) cfg);
513     return;
514   } else {
515     fprintf (stderr,
516              _("Please specify name to lookup, subject key and issuer key!\n"));
517     GNUNET_SCHEDULER_shutdown ();
518   }
519   return;
520 }
521
522
523 /**
524  * The main function for gnunet-gns.
525  *
526  * @param argc number of arguments from the command line
527  * @param argv command line arguments
528  * @return 0 ok, 1 on error
529  */
530 int
531 main (int argc, char *const *argv)
532 {
533   struct GNUNET_GETOPT_CommandLineOption options[] = {
534     GNUNET_GETOPT_option_flag ('I',
535                                "issue",
536                                gettext_noop ("create credential"),
537                                &create_cred),
538     GNUNET_GETOPT_option_flag ('V',
539                                "verify",
540                                gettext_noop ("verify credential against attribute"),
541                                &verify),
542     GNUNET_GETOPT_option_string ('s',
543                                  "subject",
544                                  "PKEY",
545                                  gettext_noop ("The public key of the subject to lookup the credential for"),
546                                  &subject_key),
547     GNUNET_GETOPT_option_string ('b',
548                                  "credential",
549                                  "CRED",
550                                  gettext_noop ("The name of the credential presented by the subject"),
551                                  &subject_credential),
552     GNUNET_GETOPT_option_string ('i',
553                                  "issuer",
554                                  "PKEY",
555                                  gettext_noop ("The public key of the authority to verify the credential against"),
556                                  &issuer_key),
557     GNUNET_GETOPT_option_string ('e',
558                                  "ego",
559                                  "EGO",
560                                  gettext_noop ("The ego to use"),
561                                  &ego_name),
562     GNUNET_GETOPT_option_string ('a',
563                                  "attribute",
564                                  "ATTR",
565                                  gettext_noop ("The issuer attribute to verify against or to issue"),
566                                  &issuer_attr),
567     GNUNET_GETOPT_option_string ('T',
568                                  "ttl",
569                                  "EXP",
570                                  gettext_noop ("The time to live for the credential"),
571                                  &expiration),
572     GNUNET_GETOPT_option_flag ('g',
573                                "collect",
574                                gettext_noop ("collect credentials"),
575                                &collect),
576     GNUNET_GETOPT_OPTION_END
577   };
578   int ret;
579
580   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
581   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
582     return 2;
583
584   GNUNET_log_setup ("gnunet-credential", "WARNING", NULL);
585   ret =
586     (GNUNET_OK ==
587      GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
588                          _("GNUnet credential resolver tool"),
589                          options,
590                          &run, NULL)) ? 0 : 1;
591   GNUNET_free ((void*) argv);
592   return ret;
593 }
594
595 /* end of gnunet-credential.c */