diff options
Diffstat (limited to 'src/credential/gnunet-credential.c')
-rw-r--r-- | src/credential/gnunet-credential.c | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/src/credential/gnunet-credential.c b/src/credential/gnunet-credential.c new file mode 100644 index 000000000..fb7bdb7f8 --- /dev/null +++ b/src/credential/gnunet-credential.c | |||
@@ -0,0 +1,587 @@ | |||
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 Adnan Husain | ||
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 uint32_t verify; | ||
112 | |||
113 | /** | ||
114 | * Issue mode | ||
115 | */ | ||
116 | static uint32_t create_cred; | ||
117 | |||
118 | /** | ||
119 | * Collect mode | ||
120 | */ | ||
121 | static uint32_t 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_verify_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 | /** | ||
162 | * Function called with the result of a Credential lookup. | ||
163 | * | ||
164 | * @param cls the 'const char *' name that was resolved | ||
165 | * @param cd_count number of records returned | ||
166 | * @param cd array of @a cd_count records with the results | ||
167 | */ | ||
168 | static void | ||
169 | handle_collect_result (void *cls, | ||
170 | unsigned int d_count, | ||
171 | struct GNUNET_CREDENTIAL_Delegation *dc, | ||
172 | unsigned int c_count, | ||
173 | struct GNUNET_CREDENTIAL_Credential *cred) | ||
174 | { | ||
175 | int i; | ||
176 | char* line; | ||
177 | |||
178 | verify_request = NULL; | ||
179 | if (NULL != cred) | ||
180 | { | ||
181 | for (i=0;i<c_count;i++) | ||
182 | { | ||
183 | line = GNUNET_CREDENTIAL_credential_to_string (&cred[i]); | ||
184 | printf ("%s\n", | ||
185 | line); | ||
186 | GNUNET_free (line); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | |||
191 | GNUNET_SCHEDULER_shutdown (); | ||
192 | } | ||
193 | |||
194 | |||
195 | /** | ||
196 | * Function called with the result of a Credential lookup. | ||
197 | * | ||
198 | * @param cls the 'const char *' name that was resolved | ||
199 | * @param cd_count number of records returned | ||
200 | * @param cd array of @a cd_count records with the results | ||
201 | */ | ||
202 | static void | ||
203 | handle_verify_result (void *cls, | ||
204 | unsigned int d_count, | ||
205 | struct GNUNET_CREDENTIAL_Delegation *dc, | ||
206 | unsigned int c_count, | ||
207 | struct GNUNET_CREDENTIAL_Credential *cred) | ||
208 | { | ||
209 | int i; | ||
210 | char* iss_key; | ||
211 | char* sub_key; | ||
212 | |||
213 | verify_request = NULL; | ||
214 | if (NULL == cred) | ||
215 | printf ("Failed.\n"); | ||
216 | else | ||
217 | { | ||
218 | printf("Delegation Chain:\n"); | ||
219 | for (i=0;i<d_count;i++) | ||
220 | { | ||
221 | iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key); | ||
222 | sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key); | ||
223 | if (0 != dc[i].subject_attribute_len) | ||
224 | { | ||
225 | printf ("(%d) %s.%s <- %s.%s\n", i, | ||
226 | iss_key, dc[i].issuer_attribute, | ||
227 | sub_key, dc[i].subject_attribute); | ||
228 | } else { | ||
229 | printf ("(%d) %s.%s <- %s\n", i, | ||
230 | iss_key, dc[i].issuer_attribute, | ||
231 | sub_key); | ||
232 | } | ||
233 | GNUNET_free (iss_key); | ||
234 | GNUNET_free (sub_key); | ||
235 | } | ||
236 | printf("\nCredentials:\n"); | ||
237 | for (i=0;i<c_count;i++) | ||
238 | { | ||
239 | iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key); | ||
240 | sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key); | ||
241 | printf ("%s.%s <- %s\n", | ||
242 | iss_key, cred[i].issuer_attribute, | ||
243 | sub_key); | ||
244 | GNUNET_free (iss_key); | ||
245 | GNUNET_free (sub_key); | ||
246 | |||
247 | } | ||
248 | printf ("Successful.\n"); | ||
249 | } | ||
250 | |||
251 | |||
252 | GNUNET_SCHEDULER_shutdown (); | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * Callback invoked from identity service with ego information. | ||
257 | * An @a ego of NULL means the ego was not found. | ||
258 | * | ||
259 | * @param cls closure with the configuration | ||
260 | * @param ego an ego known to identity service, or NULL | ||
261 | */ | ||
262 | static void | ||
263 | identity_cb (void *cls, | ||
264 | const struct GNUNET_IDENTITY_Ego *ego) | ||
265 | { | ||
266 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; | ||
267 | struct GNUNET_CREDENTIAL_Credential *crd; | ||
268 | struct GNUNET_TIME_Absolute etime_abs; | ||
269 | struct GNUNET_TIME_Relative etime_rel; | ||
270 | char *res; | ||
271 | |||
272 | el = NULL; | ||
273 | if (NULL == ego) | ||
274 | { | ||
275 | if (NULL != ego_name) | ||
276 | { | ||
277 | fprintf (stderr, | ||
278 | _("Ego `%s' not known to identity service\n"), | ||
279 | ego_name); | ||
280 | } | ||
281 | GNUNET_SCHEDULER_shutdown (); | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | if (GNUNET_YES == collect) | ||
286 | { | ||
287 | |||
288 | if (GNUNET_OK != | ||
289 | GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key, | ||
290 | strlen (issuer_key), | ||
291 | &issuer_pkey)) | ||
292 | { | ||
293 | fprintf (stderr, | ||
294 | _("Issuer public key `%s' is not well-formed\n"), | ||
295 | issuer_key); | ||
296 | GNUNET_SCHEDULER_shutdown (); | ||
297 | } | ||
298 | privkey = GNUNET_IDENTITY_ego_get_private_key (ego); | ||
299 | |||
300 | collect_request = GNUNET_CREDENTIAL_collect(credential, | ||
301 | &issuer_pkey, | ||
302 | issuer_attr, //TODO argument | ||
303 | privkey, | ||
304 | &handle_collect_result, | ||
305 | NULL); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | //Else issue | ||
310 | |||
311 | if (NULL == expiration) | ||
312 | { | ||
313 | fprintf (stderr, | ||
314 | "Please specify a TTL\n"); | ||
315 | GNUNET_SCHEDULER_shutdown (); | ||
316 | return; | ||
317 | } else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration, | ||
318 | &etime_rel)) | ||
319 | { | ||
320 | etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel); | ||
321 | } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration, | ||
322 | &etime_abs)) | ||
323 | { | ||
324 | fprintf (stderr, | ||
325 | "%s is not a valid ttl!\n", | ||
326 | expiration); | ||
327 | GNUNET_SCHEDULER_shutdown (); | ||
328 | return; | ||
329 | } | ||
330 | |||
331 | |||
332 | privkey = GNUNET_IDENTITY_ego_get_private_key (ego); | ||
333 | GNUNET_free_non_null (ego_name); | ||
334 | ego_name = NULL; | ||
335 | crd = GNUNET_CREDENTIAL_credential_issue (privkey, | ||
336 | &subject_pkey, | ||
337 | issuer_attr, | ||
338 | &etime_abs); | ||
339 | |||
340 | res = GNUNET_CREDENTIAL_credential_to_string (crd); | ||
341 | GNUNET_free (crd); | ||
342 | printf ("%s\n", res); | ||
343 | GNUNET_SCHEDULER_shutdown (); | ||
344 | } | ||
345 | |||
346 | |||
347 | |||
348 | |||
349 | /** | ||
350 | * Main function that will be run. | ||
351 | * | ||
352 | * @param cls closure | ||
353 | * @param args remaining command-line arguments | ||
354 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
355 | * @param c configuration | ||
356 | */ | ||
357 | static void | ||
358 | run (void *cls, | ||
359 | char *const *args, | ||
360 | const char *cfgfile, | ||
361 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
362 | { | ||
363 | |||
364 | cfg = c; | ||
365 | |||
366 | |||
367 | tt = GNUNET_SCHEDULER_add_delayed (timeout, | ||
368 | &do_timeout, NULL); | ||
369 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
370 | |||
371 | if (GNUNET_YES == collect) { | ||
372 | if (NULL == issuer_key) | ||
373 | { | ||
374 | fprintf (stderr, | ||
375 | _("Issuer public key not well-formed\n")); | ||
376 | GNUNET_SCHEDULER_shutdown (); | ||
377 | return; | ||
378 | |||
379 | } | ||
380 | |||
381 | credential = GNUNET_CREDENTIAL_connect (cfg); | ||
382 | |||
383 | if (NULL == credential) | ||
384 | { | ||
385 | fprintf (stderr, | ||
386 | _("Failed to connect to CREDENTIAL\n")); | ||
387 | GNUNET_SCHEDULER_shutdown (); | ||
388 | } | ||
389 | if (NULL == issuer_attr) | ||
390 | { | ||
391 | fprintf (stderr, | ||
392 | _("You must provide issuer the attribute\n")); | ||
393 | GNUNET_SCHEDULER_shutdown (); | ||
394 | } | ||
395 | |||
396 | if (NULL == ego_name) | ||
397 | { | ||
398 | fprintf (stderr, | ||
399 | _("ego required\n")); | ||
400 | GNUNET_SCHEDULER_shutdown (); | ||
401 | return; | ||
402 | |||
403 | } | ||
404 | el = GNUNET_IDENTITY_ego_lookup (cfg, | ||
405 | ego_name, | ||
406 | &identity_cb, | ||
407 | (void *) cfg); | ||
408 | return; | ||
409 | |||
410 | } | ||
411 | |||
412 | if (NULL == subject_key) | ||
413 | { | ||
414 | fprintf (stderr, | ||
415 | _("Subject public key needed\n")); | ||
416 | GNUNET_SCHEDULER_shutdown (); | ||
417 | return; | ||
418 | |||
419 | } | ||
420 | if (GNUNET_OK != | ||
421 | GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key, | ||
422 | strlen (subject_key), | ||
423 | &subject_pkey)) | ||
424 | { | ||
425 | fprintf (stderr, | ||
426 | _("Subject public key `%s' is not well-formed\n"), | ||
427 | subject_key); | ||
428 | GNUNET_SCHEDULER_shutdown (); | ||
429 | return; | ||
430 | } | ||
431 | if (GNUNET_YES == verify) { | ||
432 | if (NULL == issuer_key) | ||
433 | { | ||
434 | fprintf (stderr, | ||
435 | _("Issuer public key not well-formed\n")); | ||
436 | GNUNET_SCHEDULER_shutdown (); | ||
437 | return; | ||
438 | |||
439 | } | ||
440 | if (GNUNET_OK != | ||
441 | GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key, | ||
442 | strlen (issuer_key), | ||
443 | &issuer_pkey)) | ||
444 | { | ||
445 | fprintf (stderr, | ||
446 | _("Issuer public key `%s' is not well-formed\n"), | ||
447 | issuer_key); | ||
448 | GNUNET_SCHEDULER_shutdown (); | ||
449 | } | ||
450 | credential = GNUNET_CREDENTIAL_connect (cfg); | ||
451 | |||
452 | if (NULL == credential) | ||
453 | { | ||
454 | fprintf (stderr, | ||
455 | _("Failed to connect to CREDENTIAL\n")); | ||
456 | GNUNET_SCHEDULER_shutdown (); | ||
457 | } | ||
458 | if (NULL == issuer_attr || NULL == subject_credential) | ||
459 | { | ||
460 | fprintf (stderr, | ||
461 | _("You must provide issuer and subject attributes\n")); | ||
462 | GNUNET_SCHEDULER_shutdown (); | ||
463 | } | ||
464 | |||
465 | //Subject credentials are comma separated | ||
466 | char *tmp = GNUNET_strdup (subject_credential); | ||
467 | char *tok = strtok (tmp, ","); | ||
468 | if (NULL == tok) | ||
469 | { | ||
470 | fprintf (stderr, | ||
471 | "Invalid subject credentials\n"); | ||
472 | GNUNET_free (tmp); | ||
473 | GNUNET_SCHEDULER_shutdown (); | ||
474 | } | ||
475 | int count = 1; | ||
476 | int i; | ||
477 | while (NULL != (tok = strtok(NULL, ","))) | ||
478 | count++; | ||
479 | struct GNUNET_CREDENTIAL_Credential credentials[count]; | ||
480 | struct GNUNET_CREDENTIAL_Credential *cred; | ||
481 | GNUNET_free (tmp); | ||
482 | tmp = GNUNET_strdup (subject_credential); | ||
483 | tok = strtok (tmp, ","); | ||
484 | for (i=0;i<count;i++) | ||
485 | { | ||
486 | cred = GNUNET_CREDENTIAL_credential_from_string (tok); | ||
487 | GNUNET_memcpy (&credentials[i], | ||
488 | cred, | ||
489 | sizeof (struct GNUNET_CREDENTIAL_Credential)); | ||
490 | credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute); | ||
491 | tok = strtok(NULL, ","); | ||
492 | GNUNET_free (cred); | ||
493 | } | ||
494 | |||
495 | verify_request = GNUNET_CREDENTIAL_verify(credential, | ||
496 | &issuer_pkey, | ||
497 | issuer_attr, //TODO argument | ||
498 | &subject_pkey, | ||
499 | count, | ||
500 | credentials, | ||
501 | &handle_verify_result, | ||
502 | NULL); | ||
503 | for (i=0;i<count;i++) | ||
504 | { | ||
505 | GNUNET_free ((char*)credentials[i].issuer_attribute); | ||
506 | } | ||
507 | } else if (GNUNET_YES == create_cred) { | ||
508 | if (NULL == ego_name) | ||
509 | { | ||
510 | fprintf (stderr, | ||
511 | _("Issuer ego required\n")); | ||
512 | GNUNET_SCHEDULER_shutdown (); | ||
513 | return; | ||
514 | |||
515 | } | ||
516 | el = GNUNET_IDENTITY_ego_lookup (cfg, | ||
517 | ego_name, | ||
518 | &identity_cb, | ||
519 | (void *) cfg); | ||
520 | return; | ||
521 | } else { | ||
522 | fprintf (stderr, | ||
523 | _("Please specify name to lookup, subject key and issuer key!\n")); | ||
524 | GNUNET_SCHEDULER_shutdown (); | ||
525 | } | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | |||
530 | /** | ||
531 | * The main function for gnunet-gns. | ||
532 | * | ||
533 | * @param argc number of arguments from the command line | ||
534 | * @param argv command line arguments | ||
535 | * @return 0 ok, 1 on error | ||
536 | */ | ||
537 | int | ||
538 | main (int argc, char *const *argv) | ||
539 | { | ||
540 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
541 | {'I', "issue", NULL, | ||
542 | gettext_noop ("create credential"), 0, | ||
543 | &GNUNET_GETOPT_set_one, &create_cred}, | ||
544 | {'V', "verify", NULL, | ||
545 | gettext_noop ("verify credential against attribute"), 0, | ||
546 | &GNUNET_GETOPT_set_one, &verify}, | ||
547 | {'s', "subject", "PKEY", | ||
548 | gettext_noop ("The public key of the subject to lookup the credential for"), 1, | ||
549 | &GNUNET_GETOPT_set_string, &subject_key}, | ||
550 | {'b', "credential", "CRED", | ||
551 | gettext_noop ("The name of the credential presented by the subject"), 1, | ||
552 | &GNUNET_GETOPT_set_string, &subject_credential}, | ||
553 | {'i', "issuer", "PKEY", | ||
554 | gettext_noop ("The public key of the authority to verify the credential against"), 1, | ||
555 | &GNUNET_GETOPT_set_string, &issuer_key}, | ||
556 | {'e', "ego", "EGO", | ||
557 | gettext_noop ("The ego to use"), 1, | ||
558 | &GNUNET_GETOPT_set_string, &ego_name}, | ||
559 | {'a', "attribute", "ATTR", | ||
560 | gettext_noop ("The issuer attribute to verify against or to issue"), 1, | ||
561 | &GNUNET_GETOPT_set_string, &issuer_attr}, | ||
562 | {'T', "ttl", "EXP", | ||
563 | gettext_noop ("The time to live for the credential"), 1, | ||
564 | &GNUNET_GETOPT_set_string, &expiration}, | ||
565 | {'g', "collect", NULL, | ||
566 | gettext_noop ("collect credentials"), 0, | ||
567 | &GNUNET_GETOPT_set_one, &collect}, | ||
568 | GNUNET_GETOPT_OPTION_END | ||
569 | }; | ||
570 | int ret; | ||
571 | |||
572 | timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
573 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
574 | return 2; | ||
575 | |||
576 | GNUNET_log_setup ("gnunet-credential", "WARNING", NULL); | ||
577 | ret = | ||
578 | (GNUNET_OK == | ||
579 | GNUNET_PROGRAM_run (argc, argv, "gnunet-credential", | ||
580 | _("GNUnet credential resolver tool"), | ||
581 | options, | ||
582 | &run, NULL)) ? 0 : 1; | ||
583 | GNUNET_free ((void*) argv); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | /* end of gnunet-credential.c */ | ||