03f959b95f7306382e5519bdcbab9055a5ad02a3
[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
6      it under the terms of the GNU General Public License 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 License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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     }
375     if (NULL == issuer_attr)
376     {
377       fprintf (stderr,
378                _("You must provide issuer the attribute\n"));
379       GNUNET_SCHEDULER_shutdown ();
380     }
381
382     if (NULL == ego_name)
383     {
384       fprintf (stderr,
385                _("ego required\n"));
386       GNUNET_SCHEDULER_shutdown ();
387       return;
388
389     }
390     el = GNUNET_IDENTITY_ego_lookup (cfg,
391                                      ego_name,
392                                      &identity_cb,
393                                      (void *) cfg);
394     return;
395
396   } 
397
398   if (NULL == subject_key)
399   {
400     fprintf (stderr,
401              _("Subject public key needed\n"));
402     GNUNET_SCHEDULER_shutdown ();
403     return;
404
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     if (NULL == issuer_key)
419     {
420       fprintf (stderr,
421                _("Issuer public key not well-formed\n"));
422       GNUNET_SCHEDULER_shutdown ();
423       return;
424
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     }
436     credential = GNUNET_CREDENTIAL_connect (cfg);
437
438     if (NULL == credential)
439     {
440       fprintf (stderr,
441                _("Failed to connect to CREDENTIAL\n"));
442       GNUNET_SCHEDULER_shutdown ();
443     }
444     if (NULL == issuer_attr || NULL == subject_credential)
445     {
446       fprintf (stderr,
447                _("You must provide issuer and subject attributes\n"));
448       GNUNET_SCHEDULER_shutdown ();
449     }
450
451     //Subject credentials are comma separated
452     char *tmp = GNUNET_strdup (subject_credential);
453     char *tok = strtok (tmp, ",");
454     if (NULL == tok)
455     {
456       fprintf (stderr,
457                "Invalid subject credentials\n");
458       GNUNET_free (tmp);
459       GNUNET_SCHEDULER_shutdown ();
460     }
461     int count = 1;
462     int i;
463     while (NULL != (tok = strtok(NULL, ",")))
464       count++;
465     struct GNUNET_CREDENTIAL_Credential credentials[count];
466     struct GNUNET_CREDENTIAL_Credential *cred;
467     GNUNET_free (tmp);
468     tmp = GNUNET_strdup (subject_credential);
469     tok = strtok (tmp, ",");
470     for (i=0;i<count;i++)
471     {
472       cred = GNUNET_CREDENTIAL_credential_from_string (tok);
473       GNUNET_memcpy (&credentials[i],
474                      cred,
475                      sizeof (struct GNUNET_CREDENTIAL_Credential));
476       credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
477       tok = strtok(NULL, ",");
478       GNUNET_free (cred);
479     }
480
481     verify_request = GNUNET_CREDENTIAL_verify(credential,
482                                               &issuer_pkey,
483                                               issuer_attr, //TODO argument
484                                               &subject_pkey,
485                                               count,
486                                               credentials,
487                                               &handle_verify_result,
488                                               NULL);
489     for (i=0;i<count;i++)
490     {
491       GNUNET_free ((char*)credentials[i].issuer_attribute);
492     }
493   } else if (GNUNET_YES == create_cred) {
494     if (NULL == ego_name)
495     {
496       fprintf (stderr,
497                _("Issuer ego required\n"));
498       GNUNET_SCHEDULER_shutdown ();
499       return;
500
501     }
502     el = GNUNET_IDENTITY_ego_lookup (cfg,
503                                      ego_name,
504                                      &identity_cb,
505                                      (void *) cfg);
506     return;
507   } else {
508     fprintf (stderr,
509              _("Please specify name to lookup, subject key and issuer key!\n"));
510     GNUNET_SCHEDULER_shutdown ();
511   }
512   return;
513 }
514
515
516 /**
517  * The main function for gnunet-gns.
518  *
519  * @param argc number of arguments from the command line
520  * @param argv command line arguments
521  * @return 0 ok, 1 on error
522  */
523 int
524 main (int argc, char *const *argv)
525 {
526   struct GNUNET_GETOPT_CommandLineOption options[] = {
527     GNUNET_GETOPT_option_flag ('I',
528                                "issue",
529                                gettext_noop ("create credential"),
530                                &create_cred),
531     GNUNET_GETOPT_option_flag ('V',
532                                "verify",
533                                gettext_noop ("verify credential against attribute"),
534                                &verify),
535     GNUNET_GETOPT_option_string ('s',
536                                  "subject",
537                                  "PKEY",
538                                  gettext_noop ("The public key of the subject to lookup the credential for"),
539                                  &subject_key),
540     GNUNET_GETOPT_option_string ('b',
541                                  "credential",
542                                  "CRED",
543                                  gettext_noop ("The name of the credential presented by the subject"),
544                                  &subject_credential),
545     GNUNET_GETOPT_option_string ('i',
546                                  "issuer",
547                                  "PKEY",
548                                  gettext_noop ("The public key of the authority to verify the credential against"),
549                                  &issuer_key),
550     GNUNET_GETOPT_option_string ('e',
551                                  "ego",
552                                  "EGO",
553                                  gettext_noop ("The ego to use"),
554                                  &ego_name),
555     GNUNET_GETOPT_option_string ('a',
556                                  "attribute",
557                                  "ATTR",
558                                  gettext_noop ("The issuer attribute to verify against or to issue"),
559                                  &issuer_attr),
560     GNUNET_GETOPT_option_string ('T',
561                                  "ttl",
562                                  "EXP",
563                                  gettext_noop ("The time to live for the credential"),
564                                  &expiration),
565     GNUNET_GETOPT_option_flag ('g',
566                                "collect",
567                                gettext_noop ("collect credentials"),
568                                &collect),
569     GNUNET_GETOPT_OPTION_END
570   };
571   int ret;
572
573   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
574   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
575     return 2;
576
577   GNUNET_log_setup ("gnunet-credential", "WARNING", NULL);
578   ret =
579     (GNUNET_OK ==
580      GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
581                          _("GNUnet credential resolver tool"),
582                          options,
583                          &run, NULL)) ? 0 : 1;
584   GNUNET_free ((void*) argv);
585   return ret;
586 }
587
588 /* end of gnunet-credential.c */