diff options
Diffstat (limited to 'src/credential/gnunet-credential.c')
-rw-r--r-- | src/credential/gnunet-credential.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/src/credential/gnunet-credential.c b/src/credential/gnunet-credential.c new file mode 100644 index 000000000..03f959b95 --- /dev/null +++ b/src/credential/gnunet-credential.c | |||
@@ -0,0 +1,588 @@ | |||
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 */ | ||