aboutsummaryrefslogtreecommitdiff
path: root/src/cli/identity/gnunet-identity.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/identity/gnunet-identity.c')
-rw-r--r--src/cli/identity/gnunet-identity.c624
1 files changed, 624 insertions, 0 deletions
diff --git a/src/cli/identity/gnunet-identity.c b/src/cli/identity/gnunet-identity.c
new file mode 100644
index 000000000..9fe4ccc51
--- /dev/null
+++ b/src/cli/identity/gnunet-identity.c
@@ -0,0 +1,624 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2018, 2019 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 identity/gnunet-identity.c
22 * @brief IDENTITY management command line tool
23 * @author Christian Grothoff
24 *
25 * Todo:
26 * - add options to get default egos
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31
32
33/**
34 * Return value from main on timeout.
35 */
36#define TIMEOUT_STATUS_CODE 40
37
38/**
39 * Handle to IDENTITY service.
40 */
41static struct GNUNET_IDENTITY_Handle *sh;
42
43/**
44 * Was "list" specified?
45 */
46static int list;
47
48/**
49 * Was "monitor" specified?
50 */
51static int monitor;
52
53/**
54 * Was "private" specified?
55 */
56static int private_keys;
57
58/**
59 * Was "verbose" specified?
60 */
61static unsigned int verbose;
62
63/**
64 * Was "quiet" specified?
65 */
66static int quiet;
67
68/**
69 * Was "eddsa" specified?
70 */
71static int type_eddsa;
72
73/**
74 * -W option
75 */
76static char *write_msg;
77
78/**
79 * -R option
80 */
81static char *read_msg;
82
83/**
84 * -C option
85 */
86static char *create_ego;
87
88/**
89 * -D option
90 */
91static char *delete_ego;
92
93/**
94 * -P option
95 */
96static char *privkey_ego;
97
98/**
99 * -k option
100 */
101static char *pubkey_msg;
102
103/**
104 * -s option.
105 */
106static char *set_ego;
107
108/**
109 * Operation handle for set operation.
110 */
111static struct GNUNET_IDENTITY_Operation *set_op;
112
113/**
114 * Handle for create operation.
115 */
116static struct GNUNET_IDENTITY_Operation *create_op;
117
118/**
119 * Handle for delete operation.
120 */
121static struct GNUNET_IDENTITY_Operation *delete_op;
122
123/**
124 * Private key from command line option, or NULL.
125 */
126struct GNUNET_CRYPTO_PrivateKey pk;
127
128/**
129 * Value to return from #main().
130 */
131static int global_ret;
132
133
134/**
135 * Task run on shutdown.
136 *
137 * @param cls NULL
138 */
139static void
140shutdown_task (void *cls)
141{
142 if (NULL != set_op)
143 {
144 GNUNET_IDENTITY_cancel (set_op);
145 set_op = NULL;
146 }
147 if (NULL != create_op)
148 {
149 GNUNET_IDENTITY_cancel (create_op);
150 create_op = NULL;
151 }
152 if (NULL != delete_op)
153 {
154 GNUNET_IDENTITY_cancel (delete_op);
155 delete_op = NULL;
156 }
157 if (NULL != set_ego)
158 {
159 GNUNET_free (set_ego);
160 set_ego = NULL;
161 }
162 GNUNET_IDENTITY_disconnect (sh);
163 sh = NULL;
164}
165
166
167/**
168 * Test if we are finished yet.
169 */
170static void
171test_finished (void)
172{
173 if ( (NULL == create_op) &&
174 (NULL == delete_op) &&
175 (NULL == set_op) &&
176 (NULL == write_msg) &&
177 (NULL == read_msg) &&
178 (! list) &&
179 (! monitor))
180 {
181 if (TIMEOUT_STATUS_CODE == global_ret)
182 global_ret = 0;
183 GNUNET_SCHEDULER_shutdown ();
184 }
185}
186
187
188/**
189 * Deletion operation finished.
190 *
191 * @param cls pointer to operation handle
192 * @param ec the error code
193 */
194static void
195delete_finished (void *cls,
196 enum GNUNET_ErrorCode ec)
197{
198 struct GNUNET_IDENTITY_Operation **op = cls;
199
200 *op = NULL;
201 if (GNUNET_EC_NONE != ec)
202 fprintf (stderr, "%s\n", GNUNET_ErrorCode_get_hint (ec));
203 test_finished ();
204}
205
206
207/**
208 * Creation operation finished.
209 *
210 * @param cls pointer to operation handle
211 * @param pk private key of the ego, or NULL on error
212 * @param ec the error code
213 */
214static void
215create_finished (void *cls,
216 const struct GNUNET_CRYPTO_PrivateKey *pk,
217 enum GNUNET_ErrorCode ec)
218{
219 struct GNUNET_IDENTITY_Operation **op = cls;
220
221 *op = NULL;
222 if (NULL == pk)
223 {
224 fprintf (stderr,
225 _ ("Failed to create ego: %s\n"),
226 GNUNET_ErrorCode_get_hint (ec));
227 global_ret = 1;
228 }
229 else if (verbose)
230 {
231 struct GNUNET_CRYPTO_PublicKey pub;
232 char *pubs;
233
234 GNUNET_CRYPTO_key_get_public (pk, &pub);
235 pubs = GNUNET_CRYPTO_public_key_to_string (&pub);
236 if (private_keys)
237 {
238 char *privs;
239
240 privs = GNUNET_CRYPTO_private_key_to_string (pk);
241 fprintf (stdout, "%s - %s\n", pubs, privs);
242 GNUNET_free (privs);
243 }
244 else
245 {
246 fprintf (stdout, "%s\n", pubs);
247 }
248 GNUNET_free (pubs);
249 }
250 test_finished ();
251}
252
253
254/**
255 * Encrypt a message given with -W, encrypted using public key of
256 * an identity given with -k.
257 */
258static void
259write_encrypted_message (void)
260{
261 struct GNUNET_CRYPTO_PublicKey recipient;
262 size_t ct_len = strlen (write_msg) + 1
263 + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES;
264 unsigned char ct[ct_len];
265 if (GNUNET_CRYPTO_public_key_from_string (pubkey_msg, &recipient) !=
266 GNUNET_SYSERR)
267 {
268 size_t msg_len = strlen (write_msg) + 1;
269 if (GNUNET_OK == GNUNET_CRYPTO_encrypt (write_msg,
270 msg_len,
271 &recipient,
272 ct, ct_len))
273 {
274 char *serialized_msg;
275 serialized_msg = GNUNET_STRINGS_data_to_string_alloc (ct, ct_len);
276 fprintf (stdout,
277 "%s\n",
278 serialized_msg);
279 GNUNET_free (serialized_msg);
280 }
281 else
282 {
283 fprintf (stderr, "Error during encryption.\n");
284 global_ret = 1;
285 }
286 }
287 else
288 {
289 fprintf (stderr, "Invalid recipient public key.\n");
290 global_ret = 1;
291 }
292}
293
294
295/**
296 * Decrypt a message given with -R, encrypted using public key of @c ego
297 * and ephemeral key given with -k.
298 *
299 * @param ego ego whose private key is used for decryption
300 */
301static void
302read_encrypted_message (struct GNUNET_IDENTITY_Ego *ego)
303{
304 char *deserialized_msg;
305 size_t msg_len;
306 if (GNUNET_OK == GNUNET_STRINGS_string_to_data_alloc (read_msg, strlen (
307 read_msg),
308 (void **) &
309 deserialized_msg,
310 &msg_len))
311 {
312 if (GNUNET_OK == GNUNET_CRYPTO_decrypt (deserialized_msg,
313 msg_len,
314 GNUNET_IDENTITY_ego_get_private_key (
315 ego),
316 deserialized_msg, msg_len))
317 {
318 deserialized_msg[msg_len - 1] = '\0';
319 fprintf (stdout,
320 "%s\n",
321 deserialized_msg);
322 }
323 else
324 {
325 fprintf (stderr, "Failed to decrypt message.\n");
326 global_ret = 1;
327 }
328 GNUNET_free (deserialized_msg);
329 }
330 else
331 {
332 fprintf (stderr, "Invalid message format.\n");
333 global_ret = 1;
334 }
335}
336
337
338/**
339 * If listing is enabled, prints information about the egos.
340 *
341 * This function is initially called for all egos and then again
342 * whenever a ego's identifier changes or if it is deleted. At the
343 * end of the initial pass over all egos, the function is once called
344 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
345 * be invoked in the future or that there was an error.
346 *
347 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
348 * function is only called ONCE, and 'NULL' being passed in 'ego' does
349 * indicate an error (for example because name is taken or no default value is
350 * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
351 * value WILL be passed to a subsequent call to the identity callback of
352 * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
353 *
354 * When an identity is renamed, this function is called with the
355 * (known) ego but the NEW identifier.
356 *
357 * When an identity is deleted, this function is called with the
358 * (known) ego and "NULL" for the 'identifier'. In this case,
359 * the 'ego' is henceforth invalid (and the 'ctx' should also be
360 * cleaned up).
361 *
362 * @param cls closure
363 * @param ego ego handle
364 * @param ctx context for application to store data for this ego
365 * (during the lifetime of this process, initially NULL)
366 * @param identifier identifier assigned by the user for this ego,
367 * NULL if the user just deleted the ego and it
368 * must thus no longer be used
369 */
370static void
371print_ego (void *cls,
372 struct GNUNET_IDENTITY_Ego *ego,
373 void **ctx,
374 const char *identifier)
375{
376 struct GNUNET_CRYPTO_PublicKey pk;
377 char *s;
378 char *privs;
379
380 if ( (NULL == ego) &&
381 (NULL != set_ego) &&
382 (NULL != read_msg) )
383 {
384 fprintf (stderr,
385 "Ego `%s' is not known, cannot decrypt message.\n",
386 set_ego);
387 GNUNET_free (read_msg);
388 read_msg = NULL;
389 GNUNET_free (set_ego);
390 set_ego = NULL;
391 }
392 if ((NULL == ego) && (! monitor))
393 {
394 list = 0;
395 test_finished ();
396 return;
397 }
398 if (! (list | monitor) && (NULL == read_msg))
399 return;
400 if ( (NULL == ego) ||
401 (NULL == identifier) )
402 return;
403 if ( (NULL != set_ego) &&
404 (0 != strcmp (identifier,
405 set_ego)) )
406 return;
407 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
408 s = GNUNET_CRYPTO_public_key_to_string (&pk);
409 privs = GNUNET_CRYPTO_private_key_to_string (
410 GNUNET_IDENTITY_ego_get_private_key (ego));
411 if ((NULL != read_msg) && (NULL != set_ego))
412 {
413 // due to the check above, set_ego and the identifier are equal
414 read_encrypted_message (ego);
415 GNUNET_free (read_msg);
416 read_msg = NULL;
417 }
418 else if ((monitor) || (NULL != identifier))
419 {
420 if (quiet)
421 {
422 if (private_keys)
423 fprintf (stdout, "%s - %s\n", s, privs);
424 else
425 fprintf (stdout, "%s\n", s);
426 }
427 else
428 {
429 if (private_keys)
430 fprintf (stdout, "%s - %s - %s - %s\n",
431 identifier, s, privs,
432 (ntohl (pk.type) == GNUNET_PUBLIC_KEY_TYPE_ECDSA) ?
433 "ECDSA" : "EdDSA");
434 else
435 fprintf (stdout, "%s - %s - %s\n",
436 identifier, s,
437 (ntohl (pk.type) == GNUNET_PUBLIC_KEY_TYPE_ECDSA) ?
438 "ECDSA" : "EdDSA");
439
440 }
441 }
442 GNUNET_free (privs);
443 GNUNET_free (s);
444}
445
446
447/**
448 * Main function that will be run by the scheduler.
449 *
450 * @param cls closure
451 * @param args remaining command-line arguments
452 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
453 * @param cfg configuration
454 */
455static void
456run (void *cls,
457 char *const *args,
458 const char *cfgfile,
459 const struct GNUNET_CONFIGURATION_Handle *cfg)
460{
461 if ((NULL != read_msg) && (NULL == set_ego))
462 {
463 fprintf (stderr,
464 "Option -R requires options -e to be specified as well.\n");
465 return;
466 }
467
468 if ((NULL != write_msg) && (NULL == pubkey_msg))
469 {
470 fprintf (stderr, "Option -W requires option -k to be specified as well.\n");
471 return;
472 }
473 sh = GNUNET_IDENTITY_connect (cfg,
474 (monitor | list) ||
475 (NULL != set_ego)
476 ? &print_ego
477 : NULL,
478 NULL);
479 if (NULL != write_msg)
480 {
481 write_encrypted_message ();
482 GNUNET_free (write_msg);
483 write_msg = NULL;
484 }
485 // read message is handled in ego callback (print_ego)
486 if (NULL != delete_ego)
487 delete_op =
488 GNUNET_IDENTITY_delete (sh,
489 delete_ego,
490 &delete_finished,
491 &delete_op);
492 if (NULL != create_ego)
493 {
494 if (NULL != privkey_ego)
495 {
496 GNUNET_STRINGS_string_to_data (privkey_ego,
497 strlen (privkey_ego),
498 &pk,
499 sizeof(struct
500 GNUNET_CRYPTO_PrivateKey));
501 create_op =
502 GNUNET_IDENTITY_create (sh,
503 create_ego,
504 &pk,
505 0, // Ignored
506 &create_finished,
507 &create_op);
508 }
509 else
510 create_op =
511 GNUNET_IDENTITY_create (sh,
512 create_ego,
513 NULL,
514 (type_eddsa) ?
515 GNUNET_PUBLIC_KEY_TYPE_EDDSA :
516 GNUNET_PUBLIC_KEY_TYPE_ECDSA,
517 &create_finished,
518 &create_op);
519 }
520 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
521 NULL);
522 test_finished ();
523}
524
525
526/**
527 * The main function.
528 *
529 * @param argc number of arguments from the command line
530 * @param argv command line arguments
531 * @return 0 ok, 1 on error
532 */
533int
534main (int argc, char *const *argv)
535{
536 struct GNUNET_GETOPT_CommandLineOption options[] = {
537 GNUNET_GETOPT_option_string ('C',
538 "create",
539 "NAME",
540 gettext_noop ("create ego NAME"),
541 &create_ego),
542 GNUNET_GETOPT_option_string ('D',
543 "delete",
544 "NAME",
545 gettext_noop ("delete ego NAME "),
546 &delete_ego),
547 GNUNET_GETOPT_option_string ('P',
548 "privkey",
549 "PRIVATE_KEY",
550 gettext_noop (
551 "set the private key for the identity to PRIVATE_KEY (use together with -C)"),
552 &privkey_ego),
553 GNUNET_GETOPT_option_string ('R',
554 "read",
555 "MESSAGE",
556 gettext_noop (
557 "Read and decrypt message encrypted for the given ego (use together with -e EGO)"),
558 &read_msg),
559 GNUNET_GETOPT_option_string ('W',
560 "write",
561 "MESSAGE",
562 gettext_noop (
563 "Encrypt and write message for recipient identity PULBIC_KEY, (use together with -k RECIPIENT_PUBLIC_KEY)"),
564 &write_msg),
565 GNUNET_GETOPT_option_flag ('X',
566 "eddsa",
567 gettext_noop (
568 "generate an EdDSA identity. (use together with -C) EXPERIMENTAL"),
569 &type_eddsa),
570 GNUNET_GETOPT_option_flag ('d',
571 "display",
572 gettext_noop ("display all egos"),
573 &list),
574 GNUNET_GETOPT_option_flag ('q',
575 "quiet",
576 gettext_noop ("reduce output"),
577 &quiet),
578 GNUNET_GETOPT_option_string (
579 'e',
580 "ego",
581 "NAME",
582 gettext_noop (
583 "restrict results to NAME (use together with -d) or read and decrypt a message for NAME (use together with -R)"),
584 &set_ego),
585 GNUNET_GETOPT_option_string ('k',
586 "key",
587 "PUBLIC_KEY",
588 gettext_noop (
589 "The public key of the recipient (with -W)"),
590 &pubkey_msg),
591 GNUNET_GETOPT_option_flag ('m',
592 "monitor",
593 gettext_noop ("run in monitor mode egos"),
594 &monitor),
595 GNUNET_GETOPT_option_flag ('p',
596 "private-keys",
597 gettext_noop ("display private keys as well"),
598 &private_keys),
599 GNUNET_GETOPT_option_verbose (&verbose),
600 GNUNET_GETOPT_OPTION_END
601 };
602 int res;
603
604 if (GNUNET_OK !=
605 GNUNET_STRINGS_get_utf8_args (argc, argv,
606 &argc, &argv))
607 return 4;
608 global_ret = TIMEOUT_STATUS_CODE; /* timeout */
609 res = GNUNET_PROGRAM_run (argc,
610 argv,
611 "gnunet-identity",
612 gettext_noop ("Maintain egos"),
613 options,
614 &run,
615 NULL);
616 GNUNET_free_nz ((void *) argv);
617
618 if (GNUNET_OK != res)
619 return 3;
620 return global_ret;
621}
622
623
624/* end of gnunet-identity.c */