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