aboutsummaryrefslogtreecommitdiff
path: root/src/service/identity
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/identity')
-rw-r--r--src/service/identity/.gitignore4
-rw-r--r--src/service/identity/Makefile.am66
-rw-r--r--src/service/identity/gnunet-service-identity.c1035
-rw-r--r--src/service/identity/identity.conf.in17
-rw-r--r--src/service/identity/identity.h226
-rw-r--r--src/service/identity/identity_api.c768
-rw-r--r--src/service/identity/identity_api_lookup.c244
-rw-r--r--src/service/identity/identity_api_suffix_lookup.c246
-rw-r--r--src/service/identity/meson.build40
-rw-r--r--src/service/identity/test_identity.c324
-rw-r--r--src/service/identity/test_identity.conf11
-rwxr-xr-xsrc/service/identity/test_plugin_rest_identity.sh157
-rwxr-xr-xsrc/service/identity/test_plugin_rest_identity_signature.sh81
13 files changed, 3219 insertions, 0 deletions
diff --git a/src/service/identity/.gitignore b/src/service/identity/.gitignore
new file mode 100644
index 000000000..634a0bdd6
--- /dev/null
+++ b/src/service/identity/.gitignore
@@ -0,0 +1,4 @@
1gnunet-service-identity
2gnunet-identity
3test_identity
4test_identity_defaults
diff --git a/src/service/identity/Makefile.am b/src/service/identity/Makefile.am
new file mode 100644
index 000000000..455fcab31
--- /dev/null
+++ b/src/service/identity/Makefile.am
@@ -0,0 +1,66 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11pkgcfgdir= $(pkgdatadir)/config.d/
12
13libexecdir= $(pkglibdir)/libexec/
14
15pkgcfg_DATA = \
16 identity.conf
17
18lib_LTLIBRARIES = \
19 libgnunetidentity.la
20
21
22libgnunetidentity_la_SOURCES = \
23 identity_api.c \
24 identity_api_lookup.c \
25 identity_api_suffix_lookup.c \
26 identity.h
27libgnunetidentity_la_LIBADD = \
28 $(top_builddir)/src/lib/util/libgnunetutil.la \
29 $(GN_LIBINTL) $(XLIB)
30libgnunetidentity_la_LDFLAGS = \
31 $(GN_LIB_LDFLAGS) \
32 -lsodium \
33 -version-info 1:0:0
34
35libexec_PROGRAMS = \
36 gnunet-service-identity
37
38gnunet_service_identity_SOURCES = \
39 gnunet-service-identity.c
40gnunet_service_identity_LDADD = \
41 libgnunetidentity.la \
42 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
43 $(top_builddir)/src/lib/util/libgnunetutil.la \
44 $(GN_LIBINTL)
45
46
47check_PROGRAMS = \
48 test_identity
49
50# if ENABLE_TEST_RUN
51# AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
52# TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
53# endif
54
55
56test_identity_SOURCES = \
57 test_identity.c
58test_identity_LDADD = \
59 libgnunetidentity.la \
60 $(top_builddir)/src/service/testing/libgnunettesting.la \
61 $(top_builddir)/src/lib/util/libgnunetutil.la
62
63EXTRA_DIST = \
64 test_identity.conf
65
66
diff --git a/src/service/identity/gnunet-service-identity.c b/src/service/identity/gnunet-service-identity.c
new file mode 100644
index 000000000..7ac4bf2b9
--- /dev/null
+++ b/src/service/identity/gnunet-service-identity.c
@@ -0,0 +1,1035 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 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/**
22 * @file identity/gnunet-service-identity.c
23 * @brief identity management service
24 * @author Christian Grothoff
25 *
26 * The purpose of this service is to manage private keys that
27 * represent the various egos/pseudonyms/identities of a GNUnet user.
28 *
29 * Todo:
30 * - auto-initialze default egos; maybe trigger default
31 * initializations (such as gnunet-gns-import.sh?)
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_constants.h"
36#include "gnunet_protocols.h"
37#include "gnunet_statistics_service.h"
38#include "gnunet_identity_service.h"
39#include "identity.h"
40
41
42/**
43 * Information we keep about each ego.
44 */
45struct Ego
46{
47 /**
48 * We keep egos in a DLL.
49 */
50 struct Ego *next;
51
52 /**
53 * We keep egos in a DLL.
54 */
55 struct Ego *prev;
56
57 /**
58 * Private key of the ego.
59 */
60 struct GNUNET_CRYPTO_PrivateKey pk;
61
62 /**
63 * String identifier for the ego.
64 */
65 char *identifier;
66};
67
68
69/**
70 * Handle to our current configuration.
71 */
72static const struct GNUNET_CONFIGURATION_Handle *cfg;
73
74/**
75 * Handle to subsystem configuration which for each subsystem contains
76 * the name of the default ego.
77 */
78static struct GNUNET_CONFIGURATION_Handle *subsystem_cfg;
79
80/**
81 * Handle to the statistics service.
82 */
83static struct GNUNET_STATISTICS_Handle *stats;
84
85/**
86 * Notification context, simplifies client broadcasts.
87 */
88static struct GNUNET_NotificationContext *nc;
89
90/**
91 * Directory where we store the identities.
92 */
93static char *ego_directory;
94
95/**
96 * Configuration file name where subsystem information is kept.
97 */
98static char *subsystem_cfg_file;
99
100/**
101 * Head of DLL of all egos.
102 */
103static struct Ego *ego_head;
104
105/**
106 * Tail of DLL of all egos.
107 */
108static struct Ego *ego_tail;
109
110
111/**
112 * Get the name of the file we use to store a given ego.
113 *
114 * @param ego ego for which we need the filename
115 * @return full filename for the given ego
116 */
117static char *
118get_ego_filename (struct Ego *ego)
119{
120 char *filename;
121
122 GNUNET_asprintf (&filename,
123 "%s%s%s",
124 ego_directory,
125 DIR_SEPARATOR_STR,
126 ego->identifier);
127 return filename;
128}
129
130
131/**
132 * Called whenever a client is disconnected.
133 *
134 * @param cls closure
135 * @param client identification of the client
136 * @param app_ctx @a client
137 */
138static void
139client_disconnect_cb (void *cls,
140 struct GNUNET_SERVICE_Client *client,
141 void *app_ctx)
142{
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Client %p disconnected\n",
145 client);
146}
147
148
149/**
150 * Add a client to our list of active clients.
151 *
152 * @param cls NULL
153 * @param client client to add
154 * @param mq message queue for @a client
155 * @return internal namestore client structure for this client
156 */
157static void *
158client_connect_cb (void *cls,
159 struct GNUNET_SERVICE_Client *client,
160 struct GNUNET_MQ_Handle *mq)
161{
162 return client;
163}
164
165
166/**
167 * Task run during shutdown.
168 *
169 * @param cls unused
170 */
171static void
172shutdown_task (void *cls)
173{
174 struct Ego *e;
175
176 if (NULL != nc)
177 {
178 GNUNET_notification_context_destroy (nc);
179 nc = NULL;
180 }
181 if (NULL != stats)
182 {
183 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
184 stats = NULL;
185 }
186 GNUNET_CONFIGURATION_destroy (subsystem_cfg);
187 subsystem_cfg = NULL;
188 GNUNET_free (subsystem_cfg_file);
189 subsystem_cfg_file = NULL;
190 GNUNET_free (ego_directory);
191 ego_directory = NULL;
192 while (NULL != (e = ego_head))
193 {
194 GNUNET_CONTAINER_DLL_remove (ego_head,
195 ego_tail,
196 e);
197 GNUNET_free (e->identifier);
198 GNUNET_free (e);
199 }
200}
201
202
203/**
204 * Send a result code back to the client.
205 *
206 * @param client client that should receive the result code
207 * @param result_code code to transmit
208 */
209static void
210send_result_code (struct GNUNET_SERVICE_Client *client,
211 uint32_t result_code)
212{
213 struct ResultCodeMessage *rcm;
214 struct GNUNET_MQ_Envelope *env;
215
216 env =
217 GNUNET_MQ_msg (rcm, GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
218 rcm->result_code = htonl (result_code);
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220 "Sending result %d (%s) to client\n",
221 (int) result_code,
222 GNUNET_ErrorCode_get_hint (result_code));
223 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
224}
225
226
227/**
228 * Create an update message with information about the current state of an ego.
229 *
230 * @param ego ego to create message for
231 * @return corresponding update message
232 */
233static struct GNUNET_MQ_Envelope *
234create_update_message (struct Ego *ego)
235{
236 struct UpdateMessage *um;
237 struct GNUNET_MQ_Envelope *env;
238 size_t name_len;
239 ssize_t key_len;
240
241 key_len = GNUNET_CRYPTO_private_key_get_length (&ego->pk);
242 name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
243 env = GNUNET_MQ_msg_extra (um, name_len + key_len,
244 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
245 um->name_len = htons (name_len);
246 um->end_of_list = htons (GNUNET_NO);
247 um->key_len = htons (key_len);
248 GNUNET_memcpy (&um[1], ego->identifier, name_len);
249 GNUNET_CRYPTO_write_private_key_to_buffer (&ego->pk,
250 ((char*) &um[1]) + name_len,
251 key_len);
252 return env;
253}
254
255
256/**
257 * Handler for START message from client, sends information
258 * about all identities to the client immediately and
259 * adds the client to the notification context for future
260 * updates.
261 *
262 * @param cls a `struct GNUNET_SERVICE_Client *`
263 * @param message the message received
264 */
265static void
266handle_start_message (void *cls,
267 const struct GNUNET_MessageHeader *message)
268{
269 struct GNUNET_SERVICE_Client *client = cls;
270
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Received START message from client\n");
273 GNUNET_SERVICE_client_mark_monitor (client);
274 GNUNET_SERVICE_client_disable_continue_warning (client);
275 GNUNET_notification_context_add (nc,
276 GNUNET_SERVICE_client_get_mq (client));
277 for (struct Ego *ego = ego_head; NULL != ego; ego = ego->next)
278 {
279 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
280 create_update_message (ego));
281 }
282 {
283 struct UpdateMessage *ume;
284 struct GNUNET_MQ_Envelope *env;
285
286 env = GNUNET_MQ_msg_extra (ume,
287 0,
288 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
289 ume->end_of_list = htons (GNUNET_YES);
290 ume->name_len = htons (0);
291 ume->key_len = htons (0);
292 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
293 env);
294 }
295 GNUNET_SERVICE_client_continue (client);
296}
297
298
299/**
300 * Handler for LOOKUP message from client, sends information
301 * about ONE identity to the client immediately.
302 *
303 * @param cls unused
304 * @param message the message received
305 * @return #GNUNET_SYSERR if message was ill-formed
306 */
307static int
308check_lookup_message (void *cls,
309 const struct LookupMessage *message)
310{
311 GNUNET_MQ_check_zero_termination (message);
312 return GNUNET_OK;
313}
314
315
316/**
317 * Handler for LOOKUP message from client, sends information
318 * about ONE identity to the client immediately.
319 *
320 * @param cls a `struct GNUNET_SERVICE_Client *`
321 * @param message the message received
322 */
323static void
324handle_lookup_message (void *cls,
325 const struct LookupMessage *message)
326{
327 struct GNUNET_SERVICE_Client *client = cls;
328 const char *name;
329 struct GNUNET_MQ_Envelope *env;
330 struct Ego *ego;
331
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Received LOOKUP message from client\n");
334 name = (const char *) &message[1];
335 for (ego = ego_head; NULL != ego; ego = ego->next)
336 {
337 if (0 != strcasecmp (name, ego->identifier))
338 continue;
339 env = create_update_message (ego);
340 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
341 GNUNET_SERVICE_client_continue (client);
342 return;
343 }
344 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
345 GNUNET_SERVICE_client_continue (client);
346}
347
348
349/**
350 * Handler for LOOKUP message from client, sends information
351 * about ONE identity to the client immediately.
352 *
353 * @param cls unused
354 * @param message the message received
355 * @return #GNUNET_SYSERR if message was ill-formed
356 */
357static int
358check_lookup_by_suffix_message (void *cls,
359 const struct LookupMessage *message)
360{
361 GNUNET_MQ_check_zero_termination (message);
362 return GNUNET_OK;
363}
364
365
366/**
367 * Handler for LOOKUP_BY_SUFFIX message from client, sends information
368 * about ONE identity to the client immediately.
369 *
370 * @param cls a `struct GNUNET_SERVICE_Client *`
371 * @param message the message received
372 */
373static void
374handle_lookup_by_suffix_message (void *cls,
375 const struct LookupMessage *message)
376{
377 struct GNUNET_SERVICE_Client *client = cls;
378 const char *name;
379 struct GNUNET_MQ_Envelope *env;
380 struct Ego *lprefix;
381
382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383 "Received LOOKUP_BY_SUFFIX message from client\n");
384 name = (const char *) &message[1];
385 lprefix = NULL;
386 for (struct Ego *ego = ego_head; NULL != ego; ego = ego->next)
387 {
388 if ((strlen (ego->identifier) <= strlen (name)) &&
389 (0 == strcmp (ego->identifier,
390 &name[strlen (name) - strlen (ego->identifier)])) &&
391 ((strlen (name) == strlen (ego->identifier)) ||
392 ('.' == name[strlen (name) - strlen (ego->identifier) - 1])) &&
393 ((NULL == lprefix) ||
394 (strlen (ego->identifier) > strlen (lprefix->identifier))))
395 {
396 /* found better match, update! */
397 lprefix = ego;
398 }
399 }
400 if (NULL != lprefix)
401 {
402 env = create_update_message (lprefix);
403 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
404 GNUNET_SERVICE_client_continue (client);
405 return;
406 }
407 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
408 GNUNET_SERVICE_client_continue (client);
409}
410
411
412/**
413 * Send an updated message for the given ego to all listeners.
414 *
415 * @param ego ego to send the update for
416 */
417static void
418notify_listeners (struct Ego *ego)
419{
420 struct UpdateMessage *um;
421 size_t name_len;
422 ssize_t key_len;
423
424 name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
425 key_len = GNUNET_CRYPTO_private_key_get_length (&ego->pk);
426 um = GNUNET_malloc (sizeof(struct UpdateMessage) + name_len + key_len);
427 um->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
428 um->header.size = htons (sizeof(struct UpdateMessage) + name_len + key_len);
429 um->name_len = htons (name_len);
430 um->end_of_list = htons (GNUNET_NO);
431 um->key_len = htons (key_len);
432 GNUNET_memcpy (&um[1], ego->identifier, name_len);
433 GNUNET_CRYPTO_write_private_key_to_buffer (&ego->pk,
434 ((char*) &um[1]) + name_len,
435 key_len);
436 GNUNET_notification_context_broadcast (nc, &um->header, GNUNET_NO);
437 GNUNET_free (um);
438}
439
440
441/**
442 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_CREATE message
443 *
444 * @param cls client sending the message
445 * @param msg message of type `struct CreateRequestMessage`
446 * @return #GNUNET_OK if @a msg is well-formed
447 */
448static int
449check_create_message (void *cls,
450 const struct CreateRequestMessage *msg)
451{
452 uint16_t size;
453 uint16_t name_len;
454 size_t key_len;
455 const char *str;
456
457 size = ntohs (msg->header.size);
458 if (size <= sizeof(struct CreateRequestMessage))
459 {
460 GNUNET_break (0);
461 return GNUNET_SYSERR;
462 }
463 name_len = ntohs (msg->name_len);
464 key_len = ntohs (msg->key_len);
465 if (name_len + key_len + sizeof(struct CreateRequestMessage) != size)
466 {
467 GNUNET_break (0);
468 return GNUNET_SYSERR;
469 }
470 str = (const char *) &msg[1] + key_len;
471 if ('\0' != str[name_len - 1])
472 {
473 GNUNET_break (0);
474 return GNUNET_SYSERR;
475 }
476 return GNUNET_OK;
477}
478
479
480/**
481 * Handler for CREATE message from client, creates new identity.
482 *
483 * @param cls unused
484 * @param crm the message received
485 */
486static void
487handle_create_message (void *cls,
488 const struct CreateRequestMessage *crm)
489{
490 struct GNUNET_CRYPTO_PrivateKey private_key;
491 struct GNUNET_SERVICE_Client *client = cls;
492 struct Ego *ego;
493 char *str;
494 char *fn;
495 size_t key_len;
496 size_t kb_read;
497
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CREATE message from client\n");
499 key_len = ntohs (crm->key_len);
500 if ((GNUNET_SYSERR ==
501 GNUNET_CRYPTO_read_private_key_from_buffer (&crm[1],
502 key_len,
503 &private_key,
504 &kb_read)) ||
505 (kb_read != key_len))
506 {
507 GNUNET_SERVICE_client_drop (client);
508 return;
509 }
510 str = GNUNET_strdup ((const char *) &crm[1] + key_len);
511 GNUNET_STRINGS_utf8_tolower ((const char *) &crm[1] + key_len, str);
512 for (ego = ego_head; NULL != ego; ego = ego->next)
513 {
514 if (0 == strcmp (ego->identifier, str))
515 {
516 send_result_code (client,
517 GNUNET_EC_IDENTITY_NAME_CONFLICT);
518 GNUNET_SERVICE_client_continue (client);
519 GNUNET_free (str);
520 return;
521 }
522 }
523 ego = GNUNET_new (struct Ego);
524 ego->pk = private_key;
525 ego->identifier = GNUNET_strdup (str);
526 GNUNET_CONTAINER_DLL_insert (ego_head,
527 ego_tail,
528 ego);
529 send_result_code (client, GNUNET_EC_NONE);
530 fn = get_ego_filename (ego);
531 if (GNUNET_OK !=
532 GNUNET_DISK_fn_write (fn,
533 &private_key,
534 sizeof(struct GNUNET_CRYPTO_PrivateKey),
535 GNUNET_DISK_PERM_USER_READ
536 | GNUNET_DISK_PERM_USER_WRITE))
537 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
538 GNUNET_free (fn);
539 GNUNET_free (str);
540 notify_listeners (ego);
541 GNUNET_SERVICE_client_continue (client);
542}
543
544
545/**
546 * Closure for 'handle_ego_rename'.
547 */
548struct RenameContext
549{
550 /**
551 * Old name.
552 */
553 const char *old_name;
554
555 /**
556 * New name.
557 */
558 const char *new_name;
559};
560
561/**
562 * An ego was renamed; rename it in all subsystems where it is
563 * currently set as the default.
564 *
565 * @param cls the 'struct RenameContext'
566 * @param section a section in the configuration to process
567 */
568static void
569handle_ego_rename (void *cls, const char *section)
570{
571 struct RenameContext *rc = cls;
572 char *id;
573
574 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
575 section,
576 "DEFAULT_IDENTIFIER",
577 &id))
578 return;
579 if (0 != strcmp (id, rc->old_name))
580 {
581 GNUNET_free (id);
582 return;
583 }
584 GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
585 section,
586 "DEFAULT_IDENTIFIER",
587 rc->new_name);
588 GNUNET_free (id);
589}
590
591
592/**
593 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_RENAME message
594 *
595 * @param cls client sending the message
596 * @param msg message of type `struct RenameMessage`
597 * @return #GNUNET_OK if @a msg is well-formed
598 */
599static int
600check_rename_message (void *cls, const struct RenameMessage *msg)
601{
602 uint16_t size;
603 uint16_t old_name_len;
604 uint16_t new_name_len;
605 const char *old_name;
606 const char *new_name;
607
608 size = ntohs (msg->header.size);
609 if (size <= sizeof(struct RenameMessage))
610 {
611 GNUNET_break (0);
612 return GNUNET_SYSERR;
613 }
614 old_name_len = ntohs (msg->old_name_len);
615 new_name_len = ntohs (msg->new_name_len);
616 old_name = (const char *) &msg[1];
617 new_name = &old_name[old_name_len];
618 if ((old_name_len + new_name_len + sizeof(struct RenameMessage) != size) ||
619 ('\0' != old_name[old_name_len - 1]) ||
620 ('\0' != new_name[new_name_len - 1]))
621 {
622 GNUNET_break (0);
623 return GNUNET_SYSERR;
624 }
625
626 return GNUNET_OK;
627}
628
629
630/**
631 * Handler for RENAME message from client, creates
632 * new identity.
633 *
634 * @param cls unused
635 * @param rm the message received
636 */
637static void
638handle_rename_message (void *cls, const struct RenameMessage *rm)
639{
640 uint16_t old_name_len;
641 struct Ego *ego;
642 char *old_name;
643 char *new_name;
644 struct RenameContext rename_ctx;
645 struct GNUNET_SERVICE_Client *client = cls;
646 char *fn_old;
647 char *fn_new;
648 const char *old_name_tmp;
649
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received RENAME message from client\n");
651 old_name_len = ntohs (rm->old_name_len);
652 old_name_tmp = (const char *) &rm[1];
653 old_name = GNUNET_strdup (old_name_tmp);
654 GNUNET_STRINGS_utf8_tolower (old_name_tmp, old_name);
655 new_name = GNUNET_strdup (&old_name_tmp[old_name_len]);
656 GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], new_name);
657
658 /* check if new name is already in use */
659 for (ego = ego_head; NULL != ego; ego = ego->next)
660 {
661 if (0 == strcmp (ego->identifier, new_name))
662 {
663 send_result_code (client, GNUNET_EC_IDENTITY_NAME_CONFLICT);
664 GNUNET_SERVICE_client_continue (client);
665 GNUNET_free (old_name);
666 GNUNET_free (new_name);
667 return;
668 }
669 }
670
671 /* locate old name and, if found, perform rename */
672 for (ego = ego_head; NULL != ego; ego = ego->next)
673 {
674 if (0 == strcmp (ego->identifier, old_name))
675 {
676 fn_old = get_ego_filename (ego);
677 GNUNET_free (ego->identifier);
678 rename_ctx.old_name = old_name;
679 rename_ctx.new_name = new_name;
680 GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
681 &handle_ego_rename,
682 &rename_ctx);
683 if (GNUNET_OK !=
684 GNUNET_CONFIGURATION_write (subsystem_cfg, subsystem_cfg_file))
685 GNUNET_log (
686 GNUNET_ERROR_TYPE_ERROR,
687 _ ("Failed to write subsystem default identifier map to `%s'.\n"),
688 subsystem_cfg_file);
689 ego->identifier = GNUNET_strdup (new_name);
690 fn_new = get_ego_filename (ego);
691 if (0 != rename (fn_old, fn_new))
692 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rename", fn_old);
693 GNUNET_free (fn_old);
694 GNUNET_free (fn_new);
695 GNUNET_free (old_name);
696 GNUNET_free (new_name);
697 notify_listeners (ego);
698 send_result_code (client, GNUNET_EC_NONE);
699 GNUNET_SERVICE_client_continue (client);
700 return;
701 }
702 }
703
704 /* failed to locate old name */
705 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
706 GNUNET_free (old_name);
707 GNUNET_free (new_name);
708 GNUNET_SERVICE_client_continue (client);
709}
710
711
712/**
713 * An ego was removed, remove it from all subsystems where it is
714 * currently set as the default.
715 *
716 * @param cls name of the removed ego (const char *)
717 * @param section a section in the configuration to process
718 */
719static void
720handle_ego_delete (void *cls, const char *section)
721{
722 const char *identifier = cls;
723 char *id;
724
725 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
726 section,
727 "DEFAULT_IDENTIFIER",
728 &id))
729 return;
730 if (0 != strcmp (id, identifier))
731 {
732 GNUNET_free (id);
733 return;
734 }
735 GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
736 section,
737 "DEFAULT_IDENTIFIER",
738 NULL);
739 GNUNET_free (id);
740}
741
742
743/**
744 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_DELETE message
745 *
746 * @param cls client sending the message
747 * @param msg message of type `struct DeleteMessage`
748 * @return #GNUNET_OK if @a msg is well-formed
749 */
750static int
751check_delete_message (void *cls, const struct DeleteMessage *msg)
752{
753 uint16_t size;
754 uint16_t name_len;
755 const char *name;
756
757 size = ntohs (msg->header.size);
758 if (size <= sizeof(struct DeleteMessage))
759 {
760 GNUNET_break (0);
761 return GNUNET_SYSERR;
762 }
763 name = (const char *) &msg[1];
764 name_len = ntohs (msg->name_len);
765 if ((name_len + sizeof(struct DeleteMessage) != size) ||
766 (0 != ntohs (msg->reserved)) || ('\0' != name[name_len - 1]))
767 {
768 GNUNET_break (0);
769 return GNUNET_SYSERR;
770 }
771 return GNUNET_OK;
772}
773
774
775/**
776 * Handler for DELETE message from client, creates
777 * new identity.
778 *
779 * @param cls unused
780 * @param dm the message received
781 */
782static void
783handle_delete_message (void *cls, const struct DeleteMessage *dm)
784{
785 struct Ego *ego;
786 char *name;
787 char *fn;
788 struct GNUNET_SERVICE_Client *client = cls;
789
790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received DELETE message from client\n");
791 name = GNUNET_strdup ((const char *) &dm[1]);
792 GNUNET_STRINGS_utf8_tolower ((const char *) &dm[1], name);
793
794 for (ego = ego_head; NULL != ego; ego = ego->next)
795 {
796 if (0 == strcmp (ego->identifier, name))
797 {
798 GNUNET_CONTAINER_DLL_remove (ego_head, ego_tail, ego);
799 GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
800 &handle_ego_delete,
801 ego->identifier);
802 if (GNUNET_OK !=
803 GNUNET_CONFIGURATION_write (subsystem_cfg, subsystem_cfg_file))
804 GNUNET_log (
805 GNUNET_ERROR_TYPE_ERROR,
806 _ ("Failed to write subsystem default identifier map to `%s'.\n"),
807 subsystem_cfg_file);
808 fn = get_ego_filename (ego);
809 if (0 != unlink (fn))
810 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
811 GNUNET_free (fn);
812 GNUNET_free (ego->identifier);
813 ego->identifier = NULL;
814 notify_listeners (ego);
815 GNUNET_free (ego);
816 GNUNET_free (name);
817 send_result_code (client, GNUNET_EC_NONE);
818 GNUNET_SERVICE_client_continue (client);
819 return;
820 }
821 }
822
823 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
824 GNUNET_free (name);
825 GNUNET_SERVICE_client_continue (client);
826}
827
828
829static int
830read_from_file (const char *filename,
831 void *buf,
832 size_t buf_size)
833{
834 int fd;
835 struct stat sb;
836
837 fd = open (filename,
838 O_RDONLY);
839 if (-1 == fd)
840 {
841 memset (buf,
842 0,
843 buf_size);
844 return GNUNET_SYSERR;
845 }
846 if (0 != fstat (fd,
847 &sb))
848 {
849 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
850 "stat",
851 filename);
852 GNUNET_assert (0 == close (fd));
853 memset (buf,
854 0,
855 buf_size);
856 return GNUNET_SYSERR;
857 }
858 if (sb.st_size != buf_size)
859 {
860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
861 "File `%s' has wrong size (%llu), expected %llu bytes\n",
862 filename,
863 (unsigned long long) sb.st_size,
864 (unsigned long long) buf_size);
865 GNUNET_assert (0 == close (fd));
866 memset (buf,
867 0,
868 buf_size);
869 return GNUNET_SYSERR;
870 }
871 if (buf_size !=
872 read (fd,
873 buf,
874 buf_size))
875 {
876 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
877 "read",
878 filename);
879 GNUNET_assert (0 == close (fd));
880 memset (buf,
881 0,
882 buf_size);
883 return GNUNET_SYSERR;
884 }
885 GNUNET_assert (0 == close (fd));
886 return GNUNET_OK;
887}
888
889
890/**
891 * Process the given file from the "EGODIR". Parses the file
892 * and creates the respective 'struct Ego' in memory.
893 *
894 * @param cls NULL
895 * @param filename name of the file to parse
896 * @return #GNUNET_OK to continue to iterate,
897 * #GNUNET_NO to stop iteration with no error,
898 * #GNUNET_SYSERR to abort iteration with error!
899 */
900static int
901process_ego_file (void *cls,
902 const char *filename)
903{
904 struct Ego *ego;
905 const char *fn;
906
907 fn = strrchr (filename, (int) DIR_SEPARATOR);
908 if (NULL == fn)
909 {
910 GNUNET_break (0);
911 return GNUNET_OK;
912 }
913 ego = GNUNET_new (struct Ego);
914 if (GNUNET_OK !=
915 read_from_file (filename,
916 &ego->pk,
917 sizeof (ego->pk)))
918 {
919 GNUNET_free (ego);
920 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
921 _ ("Failed to parse ego information in `%s'\n"),
922 filename);
923 return GNUNET_OK;
924 }
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 "Loaded ego `%s'\n",
927 fn + 1);
928 ego->identifier = GNUNET_strdup (fn + 1);
929 GNUNET_CONTAINER_DLL_insert (ego_head, ego_tail, ego);
930 return GNUNET_OK;
931}
932
933
934/**
935 * Handle network size estimate clients.
936 *
937 * @param cls closure
938 * @param server the initialized server
939 * @param c configuration to use
940 */
941static void
942run (void *cls,
943 const struct GNUNET_CONFIGURATION_Handle *c,
944 struct GNUNET_SERVICE_Handle *service)
945{
946 cfg = c;
947 nc = GNUNET_notification_context_create (1);
948 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
949 "identity",
950 "EGODIR",
951 &ego_directory))
952 {
953 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
954 GNUNET_SCHEDULER_shutdown ();
955 return;
956 }
957 if (GNUNET_OK !=
958 GNUNET_CONFIGURATION_get_value_filename (cfg,
959 "identity",
960 "SUBSYSTEM_CFG",
961 &subsystem_cfg_file))
962 {
963 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
964 "identity",
965 "SUBSYSTEM_CFG");
966 GNUNET_SCHEDULER_shutdown ();
967 return;
968 }
969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
970 "Loading subsystem configuration `%s'\n",
971 subsystem_cfg_file);
972 subsystem_cfg = GNUNET_CONFIGURATION_create ();
973 if ((GNUNET_YES == GNUNET_DISK_file_test (subsystem_cfg_file)) &&
974 (GNUNET_OK !=
975 GNUNET_CONFIGURATION_parse (subsystem_cfg, subsystem_cfg_file)))
976 {
977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
978 _ (
979 "Failed to parse subsystem identity configuration file `%s'\n"),
980 subsystem_cfg_file);
981 GNUNET_SCHEDULER_shutdown ();
982 return;
983 }
984 stats = GNUNET_STATISTICS_create ("identity", cfg);
985 if (GNUNET_OK != GNUNET_DISK_directory_create (ego_directory))
986 {
987 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
988 _ ("Failed to create directory `%s' for storing egos\n"),
989 ego_directory);
990 }
991 GNUNET_DISK_directory_scan (ego_directory,
992 &process_ego_file,
993 NULL);
994 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
995}
996
997
998/**
999 * Define "main" method using service macro.
1000 */
1001GNUNET_SERVICE_MAIN (
1002 "identity",
1003 GNUNET_SERVICE_OPTION_NONE,
1004 &run,
1005 &client_connect_cb,
1006 &client_disconnect_cb,
1007 NULL,
1008 GNUNET_MQ_hd_fixed_size (start_message,
1009 GNUNET_MESSAGE_TYPE_IDENTITY_START,
1010 struct GNUNET_MessageHeader,
1011 NULL),
1012 GNUNET_MQ_hd_var_size (lookup_message,
1013 GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP,
1014 struct LookupMessage,
1015 NULL),
1016 GNUNET_MQ_hd_var_size (lookup_by_suffix_message,
1017 GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP_BY_SUFFIX,
1018 struct LookupMessage,
1019 NULL),
1020 GNUNET_MQ_hd_var_size (create_message,
1021 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE,
1022 struct CreateRequestMessage,
1023 NULL),
1024 GNUNET_MQ_hd_var_size (rename_message,
1025 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME,
1026 struct RenameMessage,
1027 NULL),
1028 GNUNET_MQ_hd_var_size (delete_message,
1029 GNUNET_MESSAGE_TYPE_IDENTITY_DELETE,
1030 struct DeleteMessage,
1031 NULL),
1032 GNUNET_MQ_handler_end ());
1033
1034
1035/* end of gnunet-service-identity.c */
diff --git a/src/service/identity/identity.conf.in b/src/service/identity/identity.conf.in
new file mode 100644
index 000000000..f5d454323
--- /dev/null
+++ b/src/service/identity/identity.conf.in
@@ -0,0 +1,17 @@
1[identity]
2START_ON_DEMAND = @START_ON_DEMAND@
3RUN_PER_USER = YES
4@JAVAPORT@PORT = 2108
5HOSTNAME = localhost
6BINARY = gnunet-service-identity
7ACCEPT_FROM = 127.0.0.1;
8ACCEPT_FROM6 = ::1;
9UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-identity.sock
10UNIX_MATCH_UID = NO
11UNIX_MATCH_GID = YES
12
13# Directory where we store information about our egos
14EGODIR = $GNUNET_DATA_HOME/identity/egos/
15
16# File where we store default identities for subsystems
17SUBSYSTEM_CFG = $GNUNET_CONFIG_HOME/identity/subsystem_defaults.conf
diff --git a/src/service/identity/identity.h b/src/service/identity/identity.h
new file mode 100644
index 000000000..acb403736
--- /dev/null
+++ b/src/service/identity/identity.h
@@ -0,0 +1,226 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 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/**
22 * @author Christian Grothoff
23 * @file identity/identity.h
24 *
25 * @brief Common type definitions for the identity
26 * service and API.
27 */
28#ifndef IDENTITY_H
29#define IDENTITY_H
30
31#include "gnunet_common.h"
32
33/**
34 * Handle for an ego.
35 */
36struct GNUNET_IDENTITY_Ego
37{
38 /**
39 * Hash of the private key of this ego.
40 */
41 struct GNUNET_HashCode id;
42
43 /**
44 * The identity key pair
45 */
46 struct GNUNET_CRYPTO_PublicKey pub;
47
48 /**
49 * The identity key pair
50 */
51 struct GNUNET_CRYPTO_PrivateKey pk;
52
53 /**
54 * Current name associated with this ego.
55 */
56 char *name;
57
58 /**
59 * Client context associated with this ego.
60 */
61 void *ctx;
62
63 /**
64 * Set to true once @e pub was initialized
65 */
66 bool pub_initialized;
67};
68
69
70
71
72GNUNET_NETWORK_STRUCT_BEGIN
73
74
75/**
76 * Answer from service to client about last operation;
77 * GET_DEFAULT maybe answered with this message on failure;
78 * CREATE and RENAME will always be answered with this message.
79 */
80struct ResultCodeMessage
81{
82 /**
83 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE
84 */
85 struct GNUNET_MessageHeader header;
86
87 /**
88 * Status code for the last operation, in NBO.
89 * (currently not used).
90 */
91 uint32_t result_code GNUNET_PACKED;
92};
93
94
95/**
96 * Client informs service about desire to lookup a (single) pseudonym.
97 */
98struct LookupMessage
99{
100 /**
101 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP or
102 * #GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP_BY_SUFFIX
103 */
104 struct GNUNET_MessageHeader header;
105
106 /* followed by 0-terminated ego name */
107};
108
109
110/**
111 * Service informs client about status of a pseudonym.
112 */
113struct UpdateMessage
114{
115 /**
116 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE
117 */
118 struct GNUNET_MessageHeader header;
119
120 /**
121 * Number of bytes in ego name string including 0-termination, in NBO;
122 * 0 if the ego was deleted.
123 */
124 uint16_t name_len GNUNET_PACKED;
125
126 /**
127 * Usually #GNUNET_NO, #GNUNET_YES to signal end of list.
128 */
129 uint16_t end_of_list GNUNET_PACKED;
130
131 /**
132 * Key length
133 */
134 uint16_t key_len GNUNET_PACKED;
135
136 /**
137 * Reserved (alignment)
138 */
139 uint16_t reserved GNUNET_PACKED;
140
141 /* followed by 0-terminated ego name */
142 /* followed by the private key */
143};
144
145
146/**
147 * Client requests creation of an identity. Service
148 * will respond with a result code.
149 */
150struct CreateRequestMessage
151{
152 /**
153 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_CREATE
154 */
155 struct GNUNET_MessageHeader header;
156
157 /**
158 * Number of bytes in identity name string including 0-termination, in NBO.
159 */
160 uint16_t name_len GNUNET_PACKED;
161
162 /**
163 * Key length
164 */
165 uint16_t key_len GNUNET_PACKED;
166
167 /*
168 * Followed by the private key
169 * followed by 0-terminated identity name */
170};
171
172
173/**
174 * Client requests renaming of an identity. Service
175 * will respond with a result code.
176 */
177struct RenameMessage
178{
179 /**
180 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_RENAME
181 */
182 struct GNUNET_MessageHeader header;
183
184 /**
185 * Number of characters in the old name including 0-termination, in NBO.
186 */
187 uint16_t old_name_len GNUNET_PACKED;
188
189 /**
190 * Number of characters in the new name including 0-termination, in NBO.
191 */
192 uint16_t new_name_len GNUNET_PACKED;
193
194 /* followed by 0-terminated old name */
195 /* followed by 0-terminated new name */
196};
197
198
199/**
200 * Client requests deletion of an identity. Service
201 * will respond with a result code.
202 */
203struct DeleteMessage
204{
205 /**
206 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_DELETE
207 */
208 struct GNUNET_MessageHeader header;
209
210 /**
211 * Number of characters in the name including 0-termination, in NBO.
212 */
213 uint16_t name_len GNUNET_PACKED;
214
215 /**
216 * Always zero.
217 */
218 uint16_t reserved GNUNET_PACKED;
219
220 /* followed by 0-terminated name */
221};
222
223GNUNET_NETWORK_STRUCT_END
224
225
226#endif
diff --git a/src/service/identity/identity_api.c b/src/service/identity/identity_api.c
new file mode 100644
index 000000000..fe789d643
--- /dev/null
+++ b/src/service/identity/identity_api.c
@@ -0,0 +1,768 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016, 2021 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/**
22 * @file identity/identity_api.c
23 * @brief api to interact with the identity service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_error_codes.h"
30#include "gnunet_protocols.h"
31#include "gnunet_identity_service.h"
32#include "identity.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "identity-api", __VA_ARGS__)
35
36
37/**
38 * Handle for an operation with the identity service.
39 */
40struct GNUNET_IDENTITY_Operation
41{
42 /**
43 * Main identity handle.
44 */
45 struct GNUNET_IDENTITY_Handle *h;
46
47 /**
48 * We keep operations in a DLL.
49 */
50 struct GNUNET_IDENTITY_Operation *next;
51
52 /**
53 * We keep operations in a DLL.
54 */
55 struct GNUNET_IDENTITY_Operation *prev;
56
57 /**
58 * Message to send to the identity service.
59 * Allocated at the end of this struct.
60 */
61 const struct GNUNET_MessageHeader *msg;
62
63 /**
64 * Continuation to invoke with the result of the transmission; @e cb
65 * and @e create_cont will be NULL in this case.
66 */
67 GNUNET_IDENTITY_Continuation cont;
68
69 /**
70 * Continuation to invoke with the result of the transmission; @e cb
71 * and @a cb will be NULL in this case.
72 */
73 GNUNET_IDENTITY_CreateContinuation create_cont;
74
75 /**
76 * Private key to return to @e create_cont, or NULL.
77 */
78 struct GNUNET_CRYPTO_PrivateKey pk;
79
80 /**
81 * Continuation to invoke with the result of the transmission for
82 * 'get' operations (@e cont and @a create_cont will be NULL in this case).
83 */
84 GNUNET_IDENTITY_Callback cb;
85
86 /**
87 * Closure for @e cont or @e cb.
88 */
89 void *cls;
90};
91
92
93/**
94 * Handle for the service.
95 */
96struct GNUNET_IDENTITY_Handle
97{
98 /**
99 * Configuration to use.
100 */
101 const struct GNUNET_CONFIGURATION_Handle *cfg;
102
103 /**
104 * Connection to service.
105 */
106 struct GNUNET_MQ_Handle *mq;
107
108 /**
109 * Hash map from the hash of the private key to the
110 * respective `GNUNET_IDENTITY_Ego` handle.
111 */
112 struct GNUNET_CONTAINER_MultiHashMap *egos;
113
114 /**
115 * Function to call when we receive updates.
116 */
117 GNUNET_IDENTITY_Callback cb;
118
119 /**
120 * Closure for @e cb.
121 */
122 void *cb_cls;
123
124 /**
125 * Head of active operations.
126 */
127 struct GNUNET_IDENTITY_Operation *op_head;
128
129 /**
130 * Tail of active operations.
131 */
132 struct GNUNET_IDENTITY_Operation *op_tail;
133
134 /**
135 * Task doing exponential back-off trying to reconnect.
136 */
137 struct GNUNET_SCHEDULER_Task *reconnect_task;
138
139 /**
140 * Time for next connect retry.
141 */
142 struct GNUNET_TIME_Relative reconnect_delay;
143
144 /**
145 * Are we polling for incoming messages right now?
146 */
147 int in_receive;
148};
149
150
151/**
152 * Obtain the ego representing 'anonymous' users.
153 *
154 * @return handle for the anonymous user, MUST NOT be freed
155 */
156struct GNUNET_IDENTITY_Ego *
157GNUNET_IDENTITY_ego_get_anonymous ()
158{
159 static struct GNUNET_IDENTITY_Ego anon;
160 static int setup;
161 ssize_t key_len;
162
163 if (setup)
164 return &anon;
165 anon.pk.type = htonl (GNUNET_PUBLIC_KEY_TYPE_ECDSA);
166 anon.pub.type = htonl (GNUNET_PUBLIC_KEY_TYPE_ECDSA);
167 anon.pk.ecdsa_key = *GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
168 key_len = GNUNET_CRYPTO_private_key_get_length (&anon.pk);
169 GNUNET_assert (0 < key_len);
170 GNUNET_CRYPTO_hash (&anon.pk,
171 key_len,
172 &anon.id);
173 setup = 1;
174 return &anon;
175}
176
177
178
179/**
180 * Try again to connect to the identity service.
181 *
182 * @param cls handle to the identity service.
183 */
184static void
185reconnect (void *cls);
186
187
188/**
189 * Free ego from hash map.
190 *
191 * @param cls identity service handle
192 * @param key unused
193 * @param value ego to free
194 * @return #GNUNET_OK (continue to iterate)
195 */
196static int
197free_ego (void *cls,
198 const struct GNUNET_HashCode *key,
199 void *value)
200{
201 struct GNUNET_IDENTITY_Handle *h = cls;
202 struct GNUNET_IDENTITY_Ego *ego = value;
203
204 if (NULL != h->cb)
205 h->cb (h->cb_cls, ego,
206 &ego->ctx,
207 NULL);
208 GNUNET_free (ego->name);
209 GNUNET_assert (GNUNET_YES ==
210 GNUNET_CONTAINER_multihashmap_remove (h->egos,
211 key,
212 value));
213 GNUNET_free (ego);
214 return GNUNET_OK;
215}
216
217
218/**
219 * Reschedule a connect attempt to the service.
220 *
221 * @param h transport service to reconnect
222 */
223static void
224reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
225{
226 struct GNUNET_IDENTITY_Operation *op;
227
228 GNUNET_assert (NULL == h->reconnect_task);
229
230 if (NULL != h->mq)
231 {
232 GNUNET_MQ_destroy (h->mq);
233 h->mq = NULL;
234 }
235 while (NULL != (op = h->op_head))
236 {
237 GNUNET_CONTAINER_DLL_remove (h->op_head,
238 h->op_tail,
239 op);
240 if (NULL != op->cont)
241 op->cont (op->cls,
242 GNUNET_EC_SERVICE_COMMUNICATION_FAILED);
243 else if (NULL != op->cb)
244 op->cb (op->cls, NULL, NULL, NULL);
245 else if (NULL != op->create_cont)
246 op->create_cont (op->cls,
247 NULL,
248 GNUNET_EC_SERVICE_COMMUNICATION_FAILED);
249 GNUNET_free (op);
250 }
251 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
252 &free_ego,
253 h);
254 LOG (GNUNET_ERROR_TYPE_DEBUG,
255 "Scheduling task to reconnect to identity service in %s.\n",
256 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
257 GNUNET_YES));
258 h->reconnect_task =
259 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
260 &reconnect,
261 h);
262 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
263}
264
265
266/**
267 * Generic error handler, called with the appropriate error code and
268 * the same closure specified at the creation of the message queue.
269 * Not every message queue implementation supports an error handler.
270 *
271 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
272 * @param error error code
273 */
274static void
275mq_error_handler (void *cls,
276 enum GNUNET_MQ_Error error)
277{
278 struct GNUNET_IDENTITY_Handle *h = cls;
279
280 reschedule_connect (h);
281}
282
283
284/**
285 * We received a result code from the service.
286 *
287 * @param cls closure
288 * @param rcm result message received
289 */
290static void
291handle_identity_result_code (void *cls,
292 const struct ResultCodeMessage *rcm)
293{
294 struct GNUNET_IDENTITY_Handle *h = cls;
295 struct GNUNET_IDENTITY_Operation *op;
296 enum GNUNET_ErrorCode ec = ntohl (rcm->result_code);
297
298 op = h->op_head;
299 if (NULL == op)
300 {
301 GNUNET_break (0);
302 reschedule_connect (h);
303 return;
304 }
305 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
306 if (NULL != op->cont)
307 op->cont (op->cls, ec);
308 else if (NULL != op->cb)
309 op->cb (op->cls, NULL, NULL, NULL);
310 else if (NULL != op->create_cont)
311 op->create_cont (op->cls, (GNUNET_EC_NONE == ec) ? &op->pk : NULL, ec);
312 GNUNET_free (op);
313}
314
315
316/**
317 * Check validity of identity update message.
318 *
319 * @param cls closure
320 * @param um message received
321 * @return #GNUNET_OK if the message is well-formed
322 */
323static int
324check_identity_update (void *cls,
325 const struct UpdateMessage *um)
326{
327 uint16_t size = ntohs (um->header.size);
328 uint16_t name_len = ntohs (um->name_len);
329 const char *str = (const char *) &um[1];
330
331 if ((size < name_len + sizeof(struct UpdateMessage)) ||
332 ((0 != name_len) && ('\0' != str[name_len - 1])))
333 {
334 GNUNET_break (0);
335 return GNUNET_SYSERR;
336 }
337 return GNUNET_OK;
338}
339
340
341/**
342 * Handle identity update message.
343 *
344 * @param cls closure
345 * @param um message received
346 */
347static void
348handle_identity_update (void *cls,
349 const struct UpdateMessage *um)
350{
351 struct GNUNET_IDENTITY_Handle *h = cls;
352 uint16_t name_len = ntohs (um->name_len);
353 const char *str;
354 size_t key_len;
355 size_t kb_read;
356 struct GNUNET_HashCode id;
357 struct GNUNET_IDENTITY_Ego *ego;
358 struct GNUNET_CRYPTO_PrivateKey private_key;
359 const char *tmp;
360
361 if (GNUNET_YES == ntohs (um->end_of_list))
362 {
363 /* end of initial list of data */
364 if (NULL != h->cb)
365 h->cb (h->cb_cls, NULL, NULL, NULL);
366 return;
367 }
368 tmp = (const char*) &um[1];
369 str = (0 == name_len) ? NULL : tmp;
370 memset (&private_key, 0, sizeof (private_key));
371 key_len = ntohs (um->key_len);
372 GNUNET_assert (GNUNET_SYSERR !=
373 GNUNET_CRYPTO_read_private_key_from_buffer (tmp + name_len,
374 key_len,
375 &private_key,
376 &kb_read));
377 GNUNET_assert (0 <= GNUNET_CRYPTO_private_key_get_length (&private_key));
378 GNUNET_CRYPTO_hash (&private_key,
379 GNUNET_CRYPTO_private_key_get_length (&private_key),
380 &id);
381 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
382 &id);
383 if (NULL == ego)
384 {
385 /* ego was created */
386 if (NULL == str)
387 {
388 /* deletion of unknown ego? not allowed */
389 GNUNET_break (0);
390 reschedule_connect (h);
391 return;
392 }
393 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
394 ego->pub_initialized = GNUNET_NO;
395 ego->pk = private_key;
396 ego->name = GNUNET_strdup (str);
397 ego->id = id;
398 GNUNET_assert (GNUNET_YES ==
399 GNUNET_CONTAINER_multihashmap_put (
400 h->egos,
401 &ego->id,
402 ego,
403 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
404 }
405 if (NULL == str)
406 {
407 /* ego was deleted */
408 GNUNET_assert (GNUNET_YES ==
409 GNUNET_CONTAINER_multihashmap_remove (h->egos,
410 &ego->id,
411 ego));
412 }
413 else
414 {
415 /* ego changed name */
416 GNUNET_free (ego->name);
417 ego->name = GNUNET_strdup (str);
418 }
419 /* inform application about change */
420 if (NULL != h->cb)
421 h->cb (h->cb_cls,
422 ego,
423 &ego->ctx,
424 str);
425 /* complete deletion */
426 if (NULL == str)
427 {
428 GNUNET_free (ego->name);
429 GNUNET_free (ego);
430 }
431}
432
433
434/**
435 * Try again to connect to the identity service.
436 *
437 * @param cls handle to the identity service.
438 */
439static void
440reconnect (void *cls)
441{
442 struct GNUNET_IDENTITY_Handle *h = cls;
443 struct GNUNET_MQ_MessageHandler handlers[] = {
444 GNUNET_MQ_hd_fixed_size (identity_result_code,
445 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
446 struct ResultCodeMessage,
447 h),
448 GNUNET_MQ_hd_var_size (identity_update,
449 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
450 struct UpdateMessage,
451 h),
452 GNUNET_MQ_handler_end ()
453 };
454 struct GNUNET_MQ_Envelope *env;
455 struct GNUNET_MessageHeader *msg;
456
457 h->reconnect_task = NULL;
458 LOG (GNUNET_ERROR_TYPE_DEBUG,
459 "Connecting to identity service.\n");
460 GNUNET_assert (NULL == h->mq);
461 h->mq = GNUNET_CLIENT_connect (h->cfg,
462 "identity",
463 handlers,
464 &mq_error_handler,
465 h);
466 if (NULL == h->mq)
467 return;
468 if (NULL != h->cb)
469 {
470 env = GNUNET_MQ_msg (msg,
471 GNUNET_MESSAGE_TYPE_IDENTITY_START);
472 GNUNET_MQ_send (h->mq,
473 env);
474 }
475}
476
477
478/**
479 * Connect to the identity service.
480 *
481 * @param cfg the configuration to use
482 * @param cb function to call on all identity events, can be NULL
483 * @param cb_cls closure for @a cb
484 * @return handle to use
485 */
486struct GNUNET_IDENTITY_Handle *
487GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
488 GNUNET_IDENTITY_Callback cb,
489 void *cb_cls)
490{
491 struct GNUNET_IDENTITY_Handle *h;
492
493 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
494 h->cfg = cfg;
495 h->cb = cb;
496 h->cb_cls = cb_cls;
497 h->egos = GNUNET_CONTAINER_multihashmap_create (16,
498 GNUNET_YES);
499 reconnect (h);
500 if (NULL == h->mq)
501 {
502 GNUNET_free (h);
503 return NULL;
504 }
505 return h;
506}
507
508
509
510/**
511 * Obtain the ECC key associated with a ego.
512 *
513 * @param ego the ego
514 * @return associated ECC key, valid as long as the ego is valid
515 */
516const struct GNUNET_CRYPTO_PrivateKey *
517GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
518{
519 return &ego->pk;
520}
521
522/**
523 * Get the identifier (public key) of an ego.
524 *
525 * @param ego identity handle with the private key
526 * @param pk set to ego's public key
527 */
528void
529GNUNET_IDENTITY_ego_get_public_key (struct GNUNET_IDENTITY_Ego *ego,
530 struct GNUNET_CRYPTO_PublicKey *pk)
531{
532 if (GNUNET_NO == ego->pub_initialized)
533 {
534 GNUNET_CRYPTO_key_get_public (&ego->pk, &ego->pub);
535 ego->pub_initialized = GNUNET_YES;
536 }
537 *pk = ego->pub;
538}
539
540static enum GNUNET_GenericReturnValue
541private_key_create (enum GNUNET_CRYPTO_KeyType ktype,
542 struct GNUNET_CRYPTO_PrivateKey *key)
543{
544 key->type = htonl (ktype);
545 switch (ktype)
546 {
547 case GNUNET_PUBLIC_KEY_TYPE_ECDSA:
548 GNUNET_CRYPTO_ecdsa_key_create (&key->ecdsa_key);
549 break;
550 case GNUNET_PUBLIC_KEY_TYPE_EDDSA:
551 GNUNET_CRYPTO_eddsa_key_create (&key->eddsa_key);
552 break;
553 default:
554 GNUNET_break (0);
555 return GNUNET_SYSERR;
556 }
557 return GNUNET_OK;
558}
559
560struct GNUNET_IDENTITY_Operation *
561GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
562 const char *name,
563 const struct GNUNET_CRYPTO_PrivateKey *privkey,
564 enum GNUNET_CRYPTO_KeyType ktype,
565 GNUNET_IDENTITY_CreateContinuation cont,
566 void *cont_cls)
567{
568 struct GNUNET_CRYPTO_PrivateKey private_key;
569 struct GNUNET_IDENTITY_Operation *op;
570 struct GNUNET_MQ_Envelope *env;
571 struct CreateRequestMessage *crm;
572 size_t slen;
573 size_t key_len;
574
575 if (NULL == h->mq)
576 return NULL;
577 slen = strlen (name) + 1;
578 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct CreateRequestMessage))
579 {
580 GNUNET_break (0);
581 return NULL;
582 }
583 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
584 op->h = h;
585 op->create_cont = cont;
586 op->cls = cont_cls;
587 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
588 if (NULL == privkey)
589 {
590 GNUNET_assert (GNUNET_OK ==
591 private_key_create (ktype, &private_key));
592 }
593 else
594 private_key = *privkey;
595 key_len = GNUNET_CRYPTO_private_key_get_length (&private_key);
596 env = GNUNET_MQ_msg_extra (crm, slen + key_len,
597 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
598 crm->name_len = htons (slen);
599 GNUNET_CRYPTO_write_private_key_to_buffer (&private_key,
600 &crm[1],
601 key_len);
602 crm->key_len = htons (key_len);
603 op->pk = private_key;
604 GNUNET_memcpy ((char*) &crm[1] + key_len, name, slen);
605 GNUNET_MQ_send (h->mq, env);
606 return op;
607}
608
609
610/**
611 * Renames an existing identity.
612 *
613 * @param h identity service to use
614 * @param old_name old name
615 * @param new_name desired new name
616 * @param cb function to call with the result (will only be called once)
617 * @param cb_cls closure for @a cb
618 * @return handle to abort the operation
619 */
620struct GNUNET_IDENTITY_Operation *
621GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
622 const char *old_name,
623 const char *new_name,
624 GNUNET_IDENTITY_Continuation cb,
625 void *cb_cls)
626{
627 struct GNUNET_IDENTITY_Operation *op;
628 struct GNUNET_MQ_Envelope *env;
629 struct RenameMessage *grm;
630 size_t slen_old;
631 size_t slen_new;
632 char *dst;
633
634 if (NULL == h->mq)
635 return NULL;
636 slen_old = strlen (old_name) + 1;
637 slen_new = strlen (new_name) + 1;
638 if ((slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
639 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
640 (slen_old + slen_new >=
641 GNUNET_MAX_MESSAGE_SIZE - sizeof(struct RenameMessage)))
642 {
643 GNUNET_break (0);
644 return NULL;
645 }
646 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
647 op->h = h;
648 op->cont = cb;
649 op->cls = cb_cls;
650 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
651 env = GNUNET_MQ_msg_extra (grm,
652 slen_old + slen_new,
653 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
654 grm->old_name_len = htons (slen_old);
655 grm->new_name_len = htons (slen_new);
656 dst = (char *) &grm[1];
657 GNUNET_memcpy (dst, old_name, slen_old);
658 GNUNET_memcpy (&dst[slen_old], new_name, slen_new);
659 GNUNET_MQ_send (h->mq, env);
660 return op;
661}
662
663
664/**
665 * Delete an existing identity.
666 *
667 * @param h identity service to use
668 * @param name name of the identity to delete
669 * @param cb function to call with the result (will only be called once)
670 * @param cb_cls closure for @a cb
671 * @return handle to abort the operation
672 */
673struct GNUNET_IDENTITY_Operation *
674GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
675 const char *name,
676 GNUNET_IDENTITY_Continuation cb,
677 void *cb_cls)
678{
679 struct GNUNET_IDENTITY_Operation *op;
680 struct GNUNET_MQ_Envelope *env;
681 struct DeleteMessage *gdm;
682 size_t slen;
683
684 if (NULL == h->mq)
685 return NULL;
686 slen = strlen (name) + 1;
687 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct DeleteMessage))
688 {
689 GNUNET_break (0);
690 return NULL;
691 }
692 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
693 op->h = h;
694 op->cont = cb;
695 op->cls = cb_cls;
696 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
697 env = GNUNET_MQ_msg_extra (gdm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
698 gdm->name_len = htons (slen);
699 gdm->reserved = htons (0);
700 GNUNET_memcpy (&gdm[1], name, slen);
701 GNUNET_MQ_send (h->mq, env);
702 return op;
703}
704
705
706/**
707 * Cancel an identity operation. Note that the operation MAY still
708 * be executed; this merely cancels the continuation; if the request
709 * was already transmitted, the service may still choose to complete
710 * the operation.
711 *
712 * @param op operation to cancel
713 */
714void
715GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
716{
717 op->cont = NULL;
718 op->cb = NULL;
719 op->create_cont = NULL;
720 memset (&op->pk,
721 0,
722 sizeof (op->pk));
723}
724
725
726/**
727 * Disconnect from identity service
728 *
729 * @param h handle to destroy
730 */
731void
732GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
733{
734 struct GNUNET_IDENTITY_Operation *op;
735
736 GNUNET_assert (NULL != h);
737 if (h->reconnect_task != NULL)
738 {
739 GNUNET_SCHEDULER_cancel (h->reconnect_task);
740 h->reconnect_task = NULL;
741 }
742 if (NULL != h->egos)
743 {
744 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
745 &free_ego,
746 h);
747 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
748 h->egos = NULL;
749 }
750 while (NULL != (op = h->op_head))
751 {
752 GNUNET_break (NULL == op->cont);
753 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
754 memset (&op->pk,
755 0,
756 sizeof (op->pk));
757 GNUNET_free (op);
758 }
759 if (NULL != h->mq)
760 {
761 GNUNET_MQ_destroy (h->mq);
762 h->mq = NULL;
763 }
764 GNUNET_free (h);
765}
766
767
768/* end of identity_api.c */
diff --git a/src/service/identity/identity_api_lookup.c b/src/service/identity/identity_api_lookup.c
new file mode 100644
index 000000000..03b229e08
--- /dev/null
+++ b/src/service/identity/identity_api_lookup.c
@@ -0,0 +1,244 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 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/**
22 * @file identity/identity_api_lookup.c
23 * @brief api to lookup an ego
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_identity_service.h"
29#include "identity.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "identity-api", __VA_ARGS__)
32
33
34/**
35 * Handle for ego lookup.
36 */
37struct GNUNET_IDENTITY_EgoLookup
38{
39 /**
40 * Connection to service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Name of the ego we are looking up.
46 */
47 char *name;
48
49 /**
50 * Function to call with the result.
51 */
52 GNUNET_IDENTITY_EgoCallback cb;
53
54 /**
55 * Closure for @e cb
56 */
57 void *cb_cls;
58};
59
60
61/**
62 * We received a result code from the service. Check the message
63 * is well-formed.
64 *
65 * @param cls closure
66 * @param rcm result message received
67 * @return #GNUNET_OK if the message is well-formed
68 */
69static int
70check_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
71{
72 if (sizeof(*rcm) != htons (rcm->header.size))
73 GNUNET_MQ_check_zero_termination (rcm);
74 return GNUNET_OK;
75}
76
77
78/**
79 * We received a result code from the service.
80 *
81 * @param cls closure
82 * @param rcm result message received
83 */
84static void
85handle_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
86{
87 struct GNUNET_IDENTITY_EgoLookup *el = cls;
88
89 el->cb (el->cb_cls, NULL);
90 GNUNET_IDENTITY_ego_lookup_cancel (el);
91}
92
93
94/**
95 * Check validity of identity update message.
96 *
97 * @param cls closure
98 * @param um message received
99 * @return #GNUNET_OK if the message is well-formed
100 */
101static int
102check_identity_update (void *cls, const struct UpdateMessage *um)
103{
104 uint16_t size = ntohs (um->header.size);
105 uint16_t name_len = ntohs (um->name_len);
106 const char *str = (const char *) &um[1];
107
108 if ((size < name_len + sizeof(struct UpdateMessage)) ||
109 ((0 != name_len) && ('\0' != str[name_len - 1])))
110 {
111 GNUNET_break (0);
112 return GNUNET_SYSERR;
113 }
114 return GNUNET_OK;
115}
116
117
118/**
119 * Handle identity update message.
120 *
121 * @param cls closure
122 * @param um message received
123 */
124static void
125handle_identity_update (void *cls, const struct UpdateMessage *um)
126{
127 struct GNUNET_IDENTITY_EgoLookup *el = cls;
128 uint16_t name_len = ntohs (um->name_len);
129 const char *str;
130 size_t key_len;
131 size_t kb_read;
132 struct GNUNET_HashCode id;
133 struct GNUNET_IDENTITY_Ego ego;
134 struct GNUNET_CRYPTO_PrivateKey private_key;
135 const char *tmp;
136
137 memset (&ego, 0, sizeof (ego));
138
139 GNUNET_break (GNUNET_YES != ntohs (um->end_of_list));
140 tmp = (const char*) &um[1];
141 str = (0 == name_len) ? NULL : tmp;
142 memset (&private_key, 0, sizeof (private_key));
143 key_len = ntohs (um->header.size) - sizeof (*um) - name_len;
144 GNUNET_assert (GNUNET_SYSERR !=
145 GNUNET_CRYPTO_read_private_key_from_buffer (tmp + name_len,
146 key_len,
147 &private_key,
148 &kb_read));
149 GNUNET_assert (key_len == kb_read);
150 GNUNET_CRYPTO_hash (&private_key, sizeof (private_key), &id);
151 ego.pk = private_key;
152 ego.name = (char *) str;
153 ego.id = id;
154 el->cb (el->cb_cls, &ego);
155 GNUNET_IDENTITY_ego_lookup_cancel (el);
156}
157
158
159/**
160 * Generic error handler, called with the appropriate error code and
161 * the same closure specified at the creation of the message queue.
162 * Not every message queue implementation supports an error handler.
163 *
164 * @param cls closure with the `struct GNUNET_IDENTITY_EgoLookup *`
165 * @param error error code
166 */
167static void
168mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
169{
170 struct GNUNET_IDENTITY_EgoLookup *el = cls;
171
172 el->cb (el->cb_cls, NULL);
173}
174
175
176/**
177 * Lookup an ego by name.
178 *
179 * @param cfg configuration to use
180 * @param name name to look up
181 * @param cb callback to invoke with the result
182 * @param cb_cls closure for @a cb
183 * @return NULL on error
184 */
185struct GNUNET_IDENTITY_EgoLookup *
186GNUNET_IDENTITY_ego_lookup (const struct GNUNET_CONFIGURATION_Handle *cfg,
187 const char *name,
188 GNUNET_IDENTITY_EgoCallback cb,
189 void *cb_cls)
190{
191 struct GNUNET_IDENTITY_EgoLookup *el;
192 struct GNUNET_MQ_Envelope *env;
193 struct GNUNET_MessageHeader *req;
194 size_t nlen;
195
196 GNUNET_assert (NULL != cb);
197 el = GNUNET_new (struct GNUNET_IDENTITY_EgoLookup);
198 el->cb = cb;
199 el->cb_cls = cb_cls;
200 {
201 struct GNUNET_MQ_MessageHandler handlers[] =
202 { GNUNET_MQ_hd_var_size (identity_result_code,
203 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
204 struct ResultCodeMessage,
205 el),
206 GNUNET_MQ_hd_var_size (identity_update,
207 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
208 struct UpdateMessage,
209 el),
210 GNUNET_MQ_handler_end () };
211
212 el->mq =
213 GNUNET_CLIENT_connect (cfg, "identity", handlers, &mq_error_handler, el);
214 }
215 if (NULL == el->mq)
216 {
217 GNUNET_break (0);
218 GNUNET_free (el);
219 return NULL;
220 }
221 el->name = GNUNET_strdup (name);
222 nlen = strlen (name) + 1;
223 env = GNUNET_MQ_msg_extra (req, nlen, GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP);
224 memcpy (&req[1], name, nlen);
225 GNUNET_MQ_send (el->mq, env);
226 return el;
227}
228
229
230/**
231 * Abort ego lookup attempt.
232 *
233 * @param el handle for lookup to abort
234 */
235void
236GNUNET_IDENTITY_ego_lookup_cancel (struct GNUNET_IDENTITY_EgoLookup *el)
237{
238 GNUNET_MQ_destroy (el->mq);
239 GNUNET_free (el->name);
240 GNUNET_free (el);
241}
242
243
244/* end of identity_api_lookup.c */
diff --git a/src/service/identity/identity_api_suffix_lookup.c b/src/service/identity/identity_api_suffix_lookup.c
new file mode 100644
index 000000000..7bc0d18f3
--- /dev/null
+++ b/src/service/identity/identity_api_suffix_lookup.c
@@ -0,0 +1,246 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 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/**
22 * @file identity/identity_api_suffix_lookup.c
23 * @brief api to lookup an ego
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_identity_service.h"
29#include "identity.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "identity-api", __VA_ARGS__)
32
33
34/**
35 * Handle for ego lookup.
36 */
37struct GNUNET_IDENTITY_EgoSuffixLookup
38{
39 /**
40 * Connection to service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Suffix we are looking up.
46 */
47 char *suffix;
48
49 /**
50 * Function to call with the result.
51 */
52 GNUNET_IDENTITY_EgoSuffixCallback cb;
53
54 /**
55 * Closure for @e cb
56 */
57 void *cb_cls;
58};
59
60
61/**
62 * We received a result code from the service. Check the message
63 * is well-formed.
64 *
65 * @param cls closure
66 * @param rcm result message received
67 * @return #GNUNET_OK if the message is well-formed
68 */
69static int
70check_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
71{
72 (void) cls;
73 if (sizeof(*rcm) != htons (rcm->header.size))
74 GNUNET_MQ_check_zero_termination (rcm);
75 return GNUNET_OK;
76}
77
78
79/**
80 * We received a result code from the service.
81 *
82 * @param cls closure
83 * @param rcm result message received
84 */
85static void
86handle_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
87{
88 struct GNUNET_IDENTITY_EgoSuffixLookup *el = cls;
89
90 (void) rcm;
91 el->cb (el->cb_cls, NULL, NULL);
92 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (el);
93}
94
95
96/**
97 * Check validity of identity update message.
98 *
99 * @param cls closure
100 * @param um message received
101 * @return #GNUNET_OK if the message is well-formed
102 */
103static int
104check_identity_update (void *cls, const struct UpdateMessage *um)
105{
106 uint16_t size = ntohs (um->header.size);
107 uint16_t name_len = ntohs (um->name_len);
108 const char *str = (const char *) &um[1];
109
110 (void) cls;
111 if ((size < name_len + sizeof(struct UpdateMessage)) ||
112 ((0 != name_len) && ('\0' != str[name_len - 1])))
113 {
114 GNUNET_break (0);
115 return GNUNET_SYSERR;
116 }
117 return GNUNET_OK;
118}
119
120
121/**
122 * Handle identity update message.
123 *
124 * @param cls closure
125 * @param um message received
126 */
127static void
128handle_identity_update (void *cls, const struct UpdateMessage *um)
129{
130 struct GNUNET_IDENTITY_EgoSuffixLookup *el = cls;
131 uint16_t name_len = ntohs (um->name_len);
132 const char *str;
133 size_t key_len;
134 size_t kb_read;
135 struct GNUNET_CRYPTO_PrivateKey private_key;
136 const char *tmp;
137
138 tmp = (const char*) &um[1];
139 str = (0 == name_len) ? NULL : tmp;
140 memset (&private_key, 0, sizeof (private_key));
141 key_len = ntohs (um->header.size) - name_len - sizeof (*um);
142 if (0 < key_len)
143 {
144 GNUNET_assert (GNUNET_SYSERR !=
145 GNUNET_CRYPTO_read_private_key_from_buffer (tmp + name_len,
146 key_len,
147 &private_key,
148 &kb_read));
149 GNUNET_assert (key_len == kb_read);
150 }
151 el->cb (el->cb_cls, &private_key, str);
152 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (el);
153}
154
155
156/**
157 * Generic error handler, called with the appropriate error code and
158 * the same closure specified at the creation of the message queue.
159 * Not every message queue implementation supports an error handler.
160 *
161 * @param cls closure with the `struct GNUNET_IDENTITY_EgoSuffixLookup *`
162 * @param error error code
163 */
164static void
165mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
166{
167 struct GNUNET_IDENTITY_EgoSuffixLookup *el = cls;
168
169 (void) error;
170 el->cb (el->cb_cls, NULL, NULL);
171 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (el);
172}
173
174
175/**
176 * Lookup an ego by name.
177 *
178 * @param cfg configuration to use
179 * @param name name to look up
180 * @param cb callback to invoke with the result
181 * @param cb_cls closure for @a cb
182 * @return NULL on error
183 */
184struct GNUNET_IDENTITY_EgoSuffixLookup *
185GNUNET_IDENTITY_ego_lookup_by_suffix (const struct
186 GNUNET_CONFIGURATION_Handle *cfg,
187 const char *suffix,
188 GNUNET_IDENTITY_EgoSuffixCallback cb,
189 void *cb_cls)
190{
191 struct GNUNET_IDENTITY_EgoSuffixLookup *el;
192 struct GNUNET_MQ_Envelope *env;
193 struct GNUNET_MessageHeader *req;
194 size_t nlen;
195
196 GNUNET_assert (NULL != cb);
197 el = GNUNET_new (struct GNUNET_IDENTITY_EgoSuffixLookup);
198 el->cb = cb;
199 el->cb_cls = cb_cls;
200 {
201 struct GNUNET_MQ_MessageHandler handlers[] =
202 { GNUNET_MQ_hd_var_size (identity_result_code,
203 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
204 struct ResultCodeMessage,
205 el),
206 GNUNET_MQ_hd_var_size (identity_update,
207 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
208 struct UpdateMessage,
209 el),
210 GNUNET_MQ_handler_end () };
211
212 el->mq =
213 GNUNET_CLIENT_connect (cfg, "identity", handlers, &mq_error_handler, el);
214 }
215 if (NULL == el->mq)
216 {
217 GNUNET_break (0);
218 GNUNET_free (el);
219 return NULL;
220 }
221 el->suffix = GNUNET_strdup (suffix);
222 nlen = strlen (suffix) + 1;
223 env = GNUNET_MQ_msg_extra (req, nlen,
224 GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP_BY_SUFFIX);
225 memcpy (&req[1], suffix, nlen);
226 GNUNET_MQ_send (el->mq, env);
227 return el;
228}
229
230
231/**
232 * Abort ego lookup attempt.
233 *
234 * @param el handle for lookup to abort
235 */
236void
237GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (struct
238 GNUNET_IDENTITY_EgoSuffixLookup *el)
239{
240 GNUNET_MQ_destroy (el->mq);
241 GNUNET_free (el->suffix);
242 GNUNET_free (el);
243}
244
245
246/* end of identity_api_suffix_lookup.c */
diff --git a/src/service/identity/meson.build b/src/service/identity/meson.build
new file mode 100644
index 000000000..961badbbc
--- /dev/null
+++ b/src/service/identity/meson.build
@@ -0,0 +1,40 @@
1libgnunetidentity_src = ['identity_api.c',
2 'identity_api_lookup.c',
3 'identity_api_suffix_lookup.c']
4
5gnunetserviceidentity_src = ['gnunet-service-identity.c']
6
7configure_file(input : 'identity.conf.in',
8 output : 'identity.conf',
9 configuration : cdata,
10 install: true,
11 install_dir: pkgcfgdir)
12
13
14if get_option('monolith')
15 foreach p : libgnunetidentity_src + gnunetserviceidentity_src
16 gnunet_src += 'identity/' + p
17 endforeach
18endif
19
20libgnunetidentity = library('gnunetidentity',
21 libgnunetidentity_src,
22 soversion: '1',
23 version: '1.0.0',
24 dependencies: [libgnunetutil_dep, sodium_dep],
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 install_dir: get_option('libdir'))
28libgnunetidentity_dep = declare_dependency(link_with : libgnunetidentity)
29pkg.generate(libgnunetidentity, url: 'https://www.gnunet.org',
30 description : 'API to access and organize private keys of the user egos')
31
32executable ('gnunet-service-identity',
33 gnunetserviceidentity_src,
34 dependencies: [libgnunetidentity_dep,
35 libgnunetutil_dep,
36 libgnunetstatistics_dep],
37 include_directories: [incdir, configuration_inc],
38 install: true,
39 install_dir: get_option('libdir')/'gnunet'/'libexec')
40
diff --git a/src/service/identity/test_identity.c b/src/service/identity/test_identity.c
new file mode 100644
index 000000000..d133e3ee4
--- /dev/null
+++ b/src/service/identity/test_identity.c
@@ -0,0 +1,324 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016 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/**
22 * @file identity/test_identity.c
23 * @brief testcase for identity service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_testing_lib.h"
30
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
33
34
35/**
36 * Return value from 'main'.
37 */
38static int res;
39
40/**
41 * Handle to identity service.
42 */
43static struct GNUNET_IDENTITY_Handle *h;
44
45/**
46 * Handle to identity operation.
47 */
48static struct GNUNET_IDENTITY_Operation *op;
49
50/**
51 * Handle for task for timeout termination.
52 */
53static struct GNUNET_SCHEDULER_Task *endbadly_task;
54
55#define CHECK(cond) \
56 do \
57 { \
58 if (! (cond)) \
59 { \
60 GNUNET_break (0); \
61 end (); \
62 return; \
63 } \
64 } while (0)
65
66
67/**
68 * Clean up all resources used.
69 */
70static void
71cleanup (void *cls)
72{
73 (void) cls;
74 if (NULL != op)
75 {
76 GNUNET_IDENTITY_cancel (op);
77 op = NULL;
78 }
79 if (NULL != h)
80 {
81 GNUNET_IDENTITY_disconnect (h);
82 h = NULL;
83 }
84}
85
86
87/**
88 * Termiante the testcase (failure).
89 *
90 * @param cls NULL
91 */
92static void
93endbadly (void *cls)
94{
95 GNUNET_SCHEDULER_shutdown ();
96}
97
98
99/**
100 * Finish the testcase (successfully).
101 */
102static void
103end ()
104{
105 if (NULL != endbadly_task)
106 {
107 GNUNET_SCHEDULER_cancel (endbadly_task);
108 endbadly_task = NULL;
109 }
110 GNUNET_SCHEDULER_shutdown ();
111}
112
113
114/**
115 * Called with events about egos.
116 *
117 * @param cls NULL
118 * @param ego ego handle
119 * @param ego_ctx context for application to store data for this ego
120 * (during the lifetime of this process, initially NULL)
121 * @param identifier identifier assigned by the user for this ego,
122 * NULL if the user just deleted the ego and it
123 * must thus no longer be used
124 */
125static void
126notification_cb (void *cls,
127 struct GNUNET_IDENTITY_Ego *ego,
128 void **ctx,
129 const char *identifier)
130{
131 static struct GNUNET_IDENTITY_Ego *my_ego;
132 static int round;
133
134 switch (round)
135 {
136 case 0: /* end of initial iteration */
137 CHECK (NULL == ego);
138 CHECK (NULL == identifier);
139 break;
140
141 case 1: /* create */
142 CHECK (NULL != ego);
143 CHECK (NULL != identifier);
144 CHECK (0 == strcmp (identifier, "test-id"));
145 my_ego = ego;
146 *ctx = &round;
147 break;
148
149 case 2: /* rename */
150 CHECK (my_ego == ego);
151 CHECK (NULL != identifier);
152 CHECK (0 == strcmp (identifier, "test"));
153 CHECK (*ctx == &round);
154 break;
155
156 case 3: /* reconnect-down */
157 CHECK (my_ego == ego);
158 CHECK (NULL == identifier);
159 CHECK (*ctx == &round);
160 *ctx = NULL;
161 break;
162
163 case 4: /* reconnect-up */
164 CHECK (NULL != identifier);
165 CHECK (0 == strcmp (identifier, "test"));
166 my_ego = ego;
167 *ctx = &round;
168 break;
169
170 case 5: /* end of iteration after reconnect */
171 CHECK (NULL == ego);
172 CHECK (NULL == identifier);
173 break;
174
175 case 6: /* delete */
176 CHECK (my_ego == ego);
177 CHECK (*ctx == &round);
178 *ctx = NULL;
179 break;
180
181 default:
182 CHECK (0);
183 }
184 round++;
185}
186
187
188/**
189 * Continuation called from successful delete operation.
190 *
191 * @param cls NULL
192 * @param ec
193 */
194static void
195delete_cont (void *cls, enum GNUNET_ErrorCode ec)
196{
197 op = NULL;
198 CHECK (GNUNET_EC_NONE == ec);
199 res = 0;
200 end ();
201}
202
203
204/**
205 * Continue by deleting the "test" identity.
206 *
207 * @param cls NULL
208 */
209static void
210finally_delete (void *cls)
211{
212 op = GNUNET_IDENTITY_delete (h, "test", &delete_cont, NULL);
213}
214
215
216/**
217 * Continuation called from expected-to-fail rename operation.
218 *
219 * @param cls NULL
220 * @param ec
221 */
222static void
223fail_rename_cont (void *cls, enum GNUNET_ErrorCode ec)
224{
225 CHECK (GNUNET_EC_NONE != ec);
226 op = NULL;
227 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
228 &finally_delete,
229 NULL);
230}
231
232
233/**
234 * Continuation called from successful rename operation.
235 *
236 * @param cls NULL
237 * @param ec
238 */
239static void
240success_rename_cont (void *cls, enum GNUNET_ErrorCode ec)
241{
242 CHECK (GNUNET_EC_NONE == ec);
243 op = GNUNET_IDENTITY_rename (h, "test-id", "test", &fail_rename_cont, NULL);
244}
245
246
247/**
248 * Called with events about created ego.
249 *
250 * @param cls NULL
251 * @param pk private key of the ego, or NULL on error
252 * @param ec
253 */
254static void
255create_cb (void *cls,
256 const struct GNUNET_CRYPTO_PrivateKey *pk,
257 enum GNUNET_ErrorCode ec)
258{
259 CHECK (NULL != pk);
260 CHECK (GNUNET_EC_NONE == ec);
261 struct GNUNET_CRYPTO_PublicKey pub;
262 size_t pt_len = strlen ("test") + 1;
263 unsigned char ct[pt_len + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES];
264 char pt[pt_len];
265 enum GNUNET_GenericReturnValue res;
266
267 GNUNET_CRYPTO_key_get_public (pk, &pub);
268 res = GNUNET_CRYPTO_encrypt ("test", pt_len, &pub, ct,
269 pt_len
270 + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES);
271 CHECK (GNUNET_OK == res);
272 res = GNUNET_CRYPTO_decrypt (ct, pt_len
273 + GNUNET_CRYPTO_ENCRYPT_OVERHEAD_BYTES,
274 pk, pt, pt_len);
275 CHECK (GNUNET_OK == res);
276 CHECK (0 == strcmp (pt, "test"));
277 op =
278 GNUNET_IDENTITY_rename (h, "test-id", "test", &success_rename_cont, NULL);
279}
280
281
282/**
283 * Main function of the test, run from scheduler.
284 *
285 * @param cls NULL
286 * @param cfg configuration we use (also to connect to identity service)
287 * @param peer handle to access more of the peer (not used)
288 */
289static void
290run (void *cls,
291 const struct GNUNET_CONFIGURATION_Handle *cfg,
292 struct GNUNET_TESTING_Peer *peer)
293{
294 endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &endbadly, NULL);
295 GNUNET_SCHEDULER_add_shutdown (&cleanup, NULL);
296 h = GNUNET_IDENTITY_connect (cfg, &notification_cb, NULL);
297 CHECK (NULL != h);
298 op = GNUNET_IDENTITY_create (h,
299 "test-id",
300 NULL,
301 GNUNET_PUBLIC_KEY_TYPE_ECDSA,
302 &create_cb, NULL);
303}
304
305
306int
307main (int argc, char *argv[])
308{
309 GNUNET_DISK_purge_cfg_dir ("test_identity.conf",
310 "GNUNET_TEST_HOME");
311 res = 1;
312 if (0 != GNUNET_TESTING_service_run ("test-identity",
313 "identity",
314 "test_identity.conf",
315 &run,
316 NULL))
317 return 1;
318 GNUNET_DISK_purge_cfg_dir ("test_identity.conf",
319 "GNUNET_TEST_HOME");
320 return res;
321}
322
323
324/* end of test_identity.c */
diff --git a/src/service/identity/test_identity.conf b/src/service/identity/test_identity.conf
new file mode 100644
index 000000000..14b915732
--- /dev/null
+++ b/src/service/identity/test_identity.conf
@@ -0,0 +1,11 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-identity-service/
3
4[arm]
5PORT = 12000
6UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
7
8[identity]
9# need to overwrite paths to ensure they stay the same between runs...
10EGODIR = $GNUNET_TMP/test-identity-service/egos/
11SUBSYSTEM_CFG = $GNUNET_TMP/test-identity-service/s.conf
diff --git a/src/service/identity/test_plugin_rest_identity.sh b/src/service/identity/test_plugin_rest_identity.sh
new file mode 100755
index 000000000..a5879dd7e
--- /dev/null
+++ b/src/service/identity/test_plugin_rest_identity.sh
@@ -0,0 +1,157 @@
1#!/usr/bin/bash
2
3#First, start gnunet-arm and the rest-service.
4#Exit 0 means success, exit 1 means failed test
5
6identity_link="http://localhost:7776/identity"
7wrong_link="http://localhost:7776/identityandmore"
8
9
10curl_get () {
11 #$1 is link
12 #$2 is grep
13 cache="$(curl -v "$1" 2>&1 | grep "$2")"
14 #echo $cache
15 if [ "" == "$cache" ]
16 then
17 exit 1
18 fi
19}
20
21curl_post () {
22 #$1 is link
23 #$2 is data
24 #$3 is grep
25 cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")"
26 #echo $cache
27 if [ "" == "$cache" ]
28 then
29 exit 1
30 fi
31}
32
33curl_delete () {
34 #$1 is link
35 #$2 is grep
36 cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")"
37 #echo $cache
38 if [ "" == "$cache" ]
39 then
40 exit 1
41 fi
42}
43
44curl_put () {
45 #$1 is link
46 #$2 is data
47 #$3 is grep
48 cache="$(curl -v -X "PUT" "$1" --data "$2" 2>&1 | grep "$3")"
49 #echo $cache
50 if [ "" == "$cache" ]
51 then
52 exit 1
53 fi
54}
55
56#Test GET
57test="$(gnunet-identity -d)"
58#if no identity exists
59if [ "" == "$test" ]
60then
61 curl_get "$identity_link/all" "error"
62 gnunet-identity -C "test_plugin_rest_identity"
63 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
64 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
65
66 curl_get "${identity_link}/name/$name" "$public"
67 curl_get "${identity_link}/name/$public" "error"
68 curl_get "${identity_link}/name/" "error"
69
70 curl_get "${identity_link}/pubkey/$public" "$name"
71 curl_get "${identity_link}/pubkey/$name" "error"
72 curl_get "${identity_link}/pubkey/" "error"
73
74 gnunet-identity -D "test_plugin_rest_identity"
75else
76 name="$(gnunet-identity -d | awk 'NR==1{print $1}')"
77 public="$(gnunet-identity -d | awk 'NR==1{print $3}')"
78
79 curl_get "${identity_link}/name/$name" "$public"
80 curl_get "${identity_link}/name/$public" "error"
81 curl_get "${identity_link}/name/" "error"
82
83 curl_get "${identity_link}/pubkey/$public" "$name"
84 curl_get "${identity_link}/pubkey/$name" "error"
85 curl_get "${identity_link}/pubkey/" "error"
86fi
87
88#Test POST
89gnunet-identity -D "test_plugin_rest_identity" > /dev/null 2>&1
90gnunet-identity -D "test_plugin_rest_identity1" > /dev/null 2>&1
91
92curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 201 Created"
93curl_post "${identity_link}" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 409"
94curl_post "${identity_link}" '{"name":"Test_plugin_rest_identity"}' "HTTP/1.1 409"
95curl_post "${identity_link}" '{}' "error"
96curl_post "${identity_link}" '' "error"
97curl_post "${identity_link}" '{"name":""}' "error"
98curl_post "${identity_link}" '{"name":123}' "error"
99curl_post "${identity_link}" '{"name":[]}' "error"
100curl_post "${identity_link}" '{"name1":"test_plugin_rest_identity"}' "error"
101curl_post "${identity_link}" '{"other":""}' "error"
102curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1", "other":"test_plugin_rest_identity2"}' "error"
103
104#Test PUT
105name="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $1}')"
106public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
107
108curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
109curl_put "${identity_link}/pubkey/$public" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
110curl_put "${identity_link}/pubkey/${public}xx" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404"
111curl_put "${identity_link}/pubkey/" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404"
112curl_put "${identity_link}/pubke" '{"newname":"test_plugin_rest_identity1"}' "error"
113curl_put "${identity_link}" '{"newname":"test_plugin_rest_identity1","other":"sdfdsf"}' "error"
114curl_put "${identity_link}/pubkey/$name" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404"
115curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204"
116curl_put "${identity_link}/pubkey/$public" '{"newnam":"test_plugin_rest_identity"}' "error"
117curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 204"
118curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"TEST_plugin_rest_identity1"}' "HTTP/1.1 409"
119curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 409"
120curl_put "${identity_link}/name/test_plugin_rest_identityxxx" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 404"
121curl_put "${identity_link}/name/test_plugin_rest_identity1" '{"newname":"test_plugin_rest_identity"}' "HTTP/1.1 204"
122curl_put "${identity_link}/name/test_plugin_rest_identity" '{"newnam":"test_plugin_rest_identityfail"}' "error"
123
124#Test subsystem
125curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204"
126curl_put "${identity_link}/subsystem/test_plugin_rest_identity" '{"subsystem":"namestore"}' "HTTP/1.1 204"
127curl_get "${identity_link}/subsystem/namestore" "test_plugin_rest_identity"
128public="$(gnunet-identity -d | grep "test_plugin_rest_identity" | awk 'NR==1{print $3}')"
129curl_put "${identity_link}/subsystem/$public" '{"subsystem":"namestore"}' "HTTP/1.1 404"
130curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
131curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "error"
132curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204"
133curl_get "${identity_link}/subsystem/test_plugin_rest_identity_no_subsystem" "test_plugin_rest_identity1"
134
135curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsyste":"test_plugin_rest_identity_no_subsystem"}' "error"
136curl_put "${identity_link}/subsystem/test_plugin_rest_identity1" '{"subsystem":"test_plugin_rest_identity_no_subsystem"}' "HTTP/1.1 204"
137
138#Test DELETE
139curl_delete "${identity_link}/name/test_plugin_rest_identity" "HTTP/1.1 204"
140curl_get "${identity_link}/name/test_plugin_rest_identity" "error"
141curl_delete "${identity_link}/name/TEST_plugin_rest_identity1" "HTTP/1.1 204"
142curl_delete "${identity_link}/name/test_plugin_rest_identity1" "HTTP/1.1 404"
143curl_get "${identity_link}/name/test_plugin_rest_identity1" "error"
144curl_delete "${identity_link}/name/test_plugin_rest_identity_not_found" "HTTP/1.1 404"
145curl_post "${identity_link}" '{"name":"test_plugin_rest_identity1"}' "HTTP/1.1 201 Created"
146public="$(gnunet-identity -d | grep "test_plugin_rest_identity1" | awk 'NR==1{print $3}')"
147curl_delete "${identity_link}/pubkey/$public" "HTTP/1.1 204"
148curl_delete "${identity_link}/pubke/$public" "error"
149curl_delete "${identity_link}/pubkey/${public}other=232" "HTTP/1.1 404"
150
151#Test wrong_link
152curl_get "$wrong_link" "HTTP/1.1 404"
153curl_post "$wrong_link" '{"name":"test_plugin_rest_identity"}' "HTTP/1.1 404"
154curl_put "$wrong_link/name/test_plugin_rest_identity" '{"newname":"test_plugin_rest_identity1"}' "HTTP/1.1 404"
155curl_delete "$wrong_link/name/test_plugin_rest_identity1" "HTTP/1.1 404"
156
157exit 0;
diff --git a/src/service/identity/test_plugin_rest_identity_signature.sh b/src/service/identity/test_plugin_rest_identity_signature.sh
new file mode 100755
index 000000000..a4d5fa5d7
--- /dev/null
+++ b/src/service/identity/test_plugin_rest_identity_signature.sh
@@ -0,0 +1,81 @@
1#!/usr/bin/bash
2
3# https://www.rfc-editor.org/rfc/rfc7515#appendix-A.3
4
5header='{"alg":"EdDSA"}'
6payload='Example of Ed25519 signing'
7key='{ "kty":"OKP",
8 "crv":"Ed25519",
9 "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
10 "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
11 }'
12
13header_payload_test="eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc"
14signature_test="hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg"
15
16base64url_add_padding() {
17 for i in $( seq 1 $(( 4 - ${#1} % 4 )) ); do padding+="="; done
18 echo "$1""$padding"
19}
20
21base64url_encode () {
22 echo -n -e "$1" | base64 -w0 | tr '+/' '-_' | tr -d '='
23}
24
25base64url_decode () {
26 padded_input=$(base64url_add_padding "$1")
27 echo -n "$padded_input" | basenc --base64url -d
28}
29
30base32crockford_encode () {
31 echo -n -e "$1" | basenc --base32hex | tr 'IJKLMNOPQRSTUV' 'JKMNPQRSTVWXYZ'
32}
33
34echo -n "jwk: "
35echo $key | jq
36
37# Create Header
38# 65556 (decimal)
39# = 00000000-00000001-00000000-00010100 (binary little endian)
40# = 00-01-00-14 (hex little endian)
41header_hex=("00" "01" "00" "14")
42
43# Convert secret JWK to HEX array
44key_hex=( $( base64url_decode $( echo -n "$key" | jq -r '.d' ) | xxd -p | tr -d '\n' | fold -w 2 | tr '\n' ' ' ) )
45
46# Concat header and key
47header_key_hex=(${header_hex[@]} ${key_hex[@]})
48
49# Encode with Base32Crogford
50key_gnunet=$(echo -n "${header_key_hex[*]}" | tr -d " " | xxd -p -r | basenc --base32hex | tr 'IJKLMNOPQRSTUV' 'JKMNPQRSTVWXYZ' | tr -d "=")
51echo "gnunet skey: $key_gnunet"
52
53# Create ego
54gnunet-identity -C ego9696595726 -X -P "$key_gnunet"
55
56# Test base64url encoding and header.payload generation
57header_payload_enc="$(base64url_encode "$header").$(base64url_encode "$payload")"
58if [ $header_payload_enc != $header_payload_test ] ;
59then
60 exit 1
61fi
62echo "header.payload: $header_payload_enc"
63
64# Sign JWT
65signature_enc=$(curl -s "localhost:7776/sign?user=ego9696595726&data=$header_payload_enc" | jq -r '.signature')
66jwt="$header_payload_enc.$signature_enc"
67echo "header.payload.signature: $jwt"
68
69gnunet-identity -D ego9696595726
70
71if [ $signature_enc != $signature_test ]
72then
73 echo "Signature does not check out:"
74 echo "$signature_enc"
75 echo "$signature_test"
76 exit 1
77else
78 echo "Signature does check out!"
79 exit 1
80fi
81