uncrustify as demanded.
[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               _("Please specify name to lookup, subject key and issuer key!\n"));
518       GNUNET_SCHEDULER_shutdown();
519     }
520   return;
521 }
522
523
524 /**
525  * The main function for gnunet-gns.
526  *
527  * @param argc number of arguments from the command line
528  * @param argv command line arguments
529  * @return 0 ok, 1 on error
530  */
531 int
532 main(int argc, char *const *argv)
533 {
534   struct GNUNET_GETOPT_CommandLineOption options[] = {
535     GNUNET_GETOPT_option_flag('I',
536                               "issue",
537                               gettext_noop("create credential"),
538                               &create_cred),
539     GNUNET_GETOPT_option_flag('V',
540                               "verify",
541                               gettext_noop("verify credential against attribute"),
542                               &verify),
543     GNUNET_GETOPT_option_string('s',
544                                 "subject",
545                                 "PKEY",
546                                 gettext_noop("The public key of the subject to lookup the credential for"),
547                                 &subject_key),
548     GNUNET_GETOPT_option_string('b',
549                                 "credential",
550                                 "CRED",
551                                 gettext_noop("The name of the credential presented by the subject"),
552                                 &subject_credential),
553     GNUNET_GETOPT_option_string('i',
554                                 "issuer",
555                                 "PKEY",
556                                 gettext_noop("The public key of the authority to verify the credential against"),
557                                 &issuer_key),
558     GNUNET_GETOPT_option_string('e',
559                                 "ego",
560                                 "EGO",
561                                 gettext_noop("The ego to use"),
562                                 &ego_name),
563     GNUNET_GETOPT_option_string('a',
564                                 "attribute",
565                                 "ATTR",
566                                 gettext_noop("The issuer attribute to verify against or to issue"),
567                                 &issuer_attr),
568     GNUNET_GETOPT_option_string('T',
569                                 "ttl",
570                                 "EXP",
571                                 gettext_noop("The time to live for the credential"),
572                                 &expiration),
573     GNUNET_GETOPT_option_flag('g',
574                               "collect",
575                               gettext_noop("collect credentials"),
576                               &collect),
577     GNUNET_GETOPT_OPTION_END
578   };
579   int ret;
580
581   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
582   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args(argc, argv, &argc, &argv))
583     return 2;
584
585   GNUNET_log_setup("gnunet-credential", "WARNING", NULL);
586   ret =
587     (GNUNET_OK ==
588      GNUNET_PROGRAM_run(argc, argv, "gnunet-credential",
589                         _("GNUnet credential resolver tool"),
590                         options,
591                         &run, NULL)) ? 0 : 1;
592   GNUNET_free((void*)argv);
593   return ret;
594 }
595
596 /* end of gnunet-credential.c */