aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2022-01-14 18:42:27 +0100
committerMartin Schanzenbach <schanzen@gnunet.org>2022-01-14 18:42:27 +0100
commit7e43ac55443b309d193f5c9f3dea02452205880d (patch)
tree958a12e9fa0cea19c62e001ec0ca29b63a5e10a3
parent004c81e6a357baac6f3092710f0e866d0ea90881 (diff)
downloadgnunet-7e43ac55443b309d193f5c9f3dea02452205880d.tar.gz
gnunet-7e43ac55443b309d193f5c9f3dea02452205880d.zip
RECLAIM: Add DIDs - trizuz
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am3
-rw-r--r--src/reclaim/Makefile.am22
-rw-r--r--src/reclaim/gnunet-did.c922
-rw-r--r--src/reclaim/test_w3c_ed25519_2020.c69
5 files changed, 1014 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index feee06f9f..096a9f768 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1367,6 +1367,7 @@ src/dht/Makefile
1367src/dht/dht.conf 1367src/dht/dht.conf
1368src/dhtu/Makefile 1368src/dhtu/Makefile
1369src/dns/Makefile 1369src/dns/Makefile
1370src/did/Makefile
1370src/dns/dns.conf 1371src/dns/dns.conf
1371src/exit/Makefile 1372src/exit/Makefile
1372src/fragmentation/Makefile 1373src/fragmentation/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c665c3b3..06d018c56 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,8 @@ TESTBED = testbed-logger testbed
6if HAVE_EXPERIMENTAL 6if HAVE_EXPERIMENTAL
7 EXP_DIR = \ 7 EXP_DIR = \
8 rps \ 8 rps \
9 abd 9 abd \
10 did
10if HAVE_ABE 11if HAVE_ABE
11 EXP_DIR += \ 12 EXP_DIR += \
12 abe 13 abe
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am
index 350d77d4b..6b5934a2f 100644
--- a/src/reclaim/Makefile.am
+++ b/src/reclaim/Makefile.am
@@ -43,7 +43,8 @@ plugin_LTLIBRARIES = \
43 $(REST_PLUGIN) 43 $(REST_PLUGIN)
44 44
45bin_PROGRAMS = \ 45bin_PROGRAMS = \
46 gnunet-reclaim 46 gnunet-reclaim \
47 gnunet-did
47 48
48libexec_PROGRAMS = \ 49libexec_PROGRAMS = \
49 gnunet-service-reclaim 50 gnunet-service-reclaim
@@ -187,13 +188,30 @@ test_reclaim_attribute_LDADD = \
187 libgnunetreclaim.la \ 188 libgnunetreclaim.la \
188 $(GN_LIBINTL) 189 $(GN_LIBINTL)
189 190
191gnunet_did_SOURCES = \
192 gnunet-did.c
193gnunet_did_LDADD = \
194 $(top_builddir)/src/util/libgnunetutil.la \
195 $(top_builddir)/src/gns/libgnunetgns.la \
196 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
197 $(top_builddir)/src/identity/libgnunetidentity.la \
198 $(top_builddir)/src/namestore/libgnunetnamestore.la \
199 -ljansson
200
201
202test_w3c_ed25519_2020_SOURCES = \
203 test_w3c_ed25519_2020.c
204test_w3c_ed25519_2020_LDADD = \
205 $(top_builddir)/src/util/libgnunetutil.la
206
190check_SCRIPTS = \ 207check_SCRIPTS = \
191 test_reclaim_attribute.sh \ 208 test_reclaim_attribute.sh \
192 test_reclaim_issue.sh \ 209 test_reclaim_issue.sh \
193 test_reclaim_consume.sh 210 test_reclaim_consume.sh
194 211
195check_PROGRAMS = \ 212check_PROGRAMS = \
196 test_reclaim_attribute 213 test_reclaim_attribute \
214 test_w3c_ed25519_2020
197 215
198if ENABLE_TEST_RUN 216if ENABLE_TEST_RUN
199 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; 217 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
diff --git a/src/reclaim/gnunet-did.c b/src/reclaim/gnunet-did.c
new file mode 100644
index 000000000..2ebef7601
--- /dev/null
+++ b/src/reclaim/gnunet-did.c
@@ -0,0 +1,922 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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 * FIXME: Do we only want to handle EdDSA identities?
23 * TODO: Own GNS record type
24 * TODO: Fix overwrite of records in @ if present look for other with same sub
25 * TODO. Tests
26 * TODO: Move constants to did.h
27 * FIXME: Remove and lookup require differnt representations (did vs egoname)
28 */
29
30/**
31 * @author Tristan Schwieren
32 * @file src/did/gnunet-did.c
33 * @brief DID Method Wrapper
34 *
35 */
36#include "platform.h"
37#include "gnunet_util_lib.h"
38#include "gnunet_namestore_service.h"
39#include "gnunet_gns_service.h"
40#include "gnunet_gnsrecord_lib.h"
41#include "jansson.h"
42
43#define GNUNET_DID_METHOD_RECLAIM_PREFIX "did:reclaim:"
44#define GNUNET_DID_DEFAULT_DID_DOCUMENT_EXPIRATION_TIME "1d"
45
46/**
47 * return value
48 */
49static int ret;
50
51/**
52 * Replace DID Document Flag
53 */
54static int replace;
55
56/**
57 * Remove DID Document Flag
58 */
59static int remove_did;
60
61/**
62 * Get DID Documement for DID Flag
63 */
64static int get;
65
66/**
67 * Create DID Document Flag
68 */
69static int create;
70
71/**
72 * Show DID for Ego Flag
73 */
74static int show;
75
76/**
77 * Show DID for Ego Flag
78 */
79static int show_all;
80
81/**
82 * DID Attribut String
83 */
84static char *did;
85
86/**
87 * DID Document Attribut String
88 */
89static char *didd;
90
91/**
92 * Ego Attribut String
93 */
94static char *egoname;
95
96/**
97 * DID Document expiration Date Attribut String
98 */
99static char *expire;
100
101/*
102 * Handle to the GNS service
103 */
104static struct GNUNET_GNS_Handle *gns_handle;
105
106/*
107 * Handle to the NAMESTORE service
108 */
109static struct GNUNET_NAMESTORE_Handle *namestore_handle;
110
111/*
112 * Handle to the IDENTITY service
113 */
114static struct GNUNET_IDENTITY_Handle *identity_handle;
115
116
117/*
118 * The configuration
119 */
120const static struct GNUNET_CONFIGURATION_Handle *my_cfg;
121
122/**
123 * Give ego exists
124 */
125static int ego_exists = 0;
126
127/**
128 * @brief Disconnect and shutdown
129 * @param cls closure
130 */
131static void
132cleanup (void *cls)
133{
134 if (NULL != gns_handle)
135 GNUNET_GNS_disconnect (gns_handle);
136 if (NULL != namestore_handle)
137 GNUNET_NAMESTORE_disconnect (namestore_handle);
138 if (NULL != identity_handle)
139 GNUNET_IDENTITY_disconnect (identity_handle);
140
141 GNUNET_free (did);
142 GNUNET_free (didd);
143 GNUNET_free (egoname);
144 GNUNET_free (expire);
145
146 GNUNET_SCHEDULER_shutdown ();
147}
148
149char*
150ego_to_did (struct GNUNET_IDENTITY_Ego *ego)
151{
152 struct GNUNET_IDENTITY_PublicKey pkey; // Get Public key
153 char *pkey_str;
154 char *did_str;
155 size_t pkey_len;
156
157 GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
158
159 pkey_str = GNUNET_IDENTITY_public_key_to_string (&pkey);
160 GNUNET_asprintf (&did_str, "%s%s",
161 GNUNET_DID_METHOD_RECLAIM_PREFIX,
162 pkey_str);
163
164 free (pkey_str);
165 return did_str;
166}
167
168/**
169 * @brief Callback for ego loockup of get_did_for_ego()
170 *
171 * @param cls closure
172 * @param ego the returned ego
173 */
174static void
175get_did_for_ego_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
176{
177 char *did_str;
178
179 if (ego == NULL)
180 {
181 printf ("EGO not found\n");
182 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
183 ret = 1;
184 return;
185 }
186 did_str = ego_to_did (ego);
187
188 printf ("%s\n", did_str);
189
190 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
191 ret = 0;
192 return;
193}
194
195/**
196 * @brief Get the DID for a given EGO
197 *
198 */
199static void
200get_did_for_ego ()
201{
202 if (egoname != NULL)
203 {
204 GNUNET_IDENTITY_ego_lookup (my_cfg,
205 egoname,
206 &get_did_for_ego_lookup_cb,
207 NULL);
208 }
209 else {
210 printf ("Set the EGO argument to get the DID for a given EGO\n");
211 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
212 ret = 1;
213 return;
214 }
215}
216
217
218/**
219 * @brief Get the public key from did attribute given by the user
220 *
221 * @param pkey place to write the public key to
222 */
223static void
224get_pkey_from_attr_did (struct GNUNET_IDENTITY_PublicKey *pkey)
225{
226 /* FIXME-MSC: I suggest introducing a
227 * #define MAX_DID_LENGTH <something>
228 * here and use it for parsing
229 */
230 char pkey_str[59];
231
232 if ((1 != (sscanf (did, GNUNET_DID_METHOD_RECLAIM_PREFIX"%58s", pkey_str))) ||
233 (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (pkey_str, pkey)))
234 {
235 fprintf (stderr, _("Invalid DID `%s'\n"), pkey_str);
236 GNUNET_SCHEDULER_add_now (cleanup, NULL);
237 ret = 1;
238 return;
239 }
240}
241
242/**
243 * @brief GNS lookup callback. Prints the DID Document to standard out.
244 * Fails if there is more than one DID record.
245 *
246 * @param cls closure
247 * @param rd_count number of records in @a rd
248 * @param rd the records in the reply
249 */
250static void
251print_did_document (
252 void *cls,
253 uint32_t rd_count,
254 const struct GNUNET_GNSRECORD_Data *rd)
255{
256 /*
257 * FIXME-MSC: The user may decide to put other records here.
258 * In general I am fine with the constraint here, but not when
259 * we move it to "@"
260 */
261 if (rd_count != 1)
262 {
263 printf ("An ego should only have one DID Document\n");
264 GNUNET_SCHEDULER_add_now (cleanup, NULL);
265 ret = 1;
266 return;
267 }
268
269 if (rd[0].record_type == GNUNET_DNSPARSER_TYPE_TXT)
270 {
271 printf ("%s\n", (char *) rd[0].data);
272 }
273 else {
274 printf ("DID Document is not a TXT record\n");
275 }
276
277 GNUNET_SCHEDULER_add_now (cleanup, NULL);
278 ret = 0;
279 return;
280}
281
282/**
283 * @brief Resolve a DID given by the user.
284 */
285static void
286resolve_did_document ()
287{
288 struct GNUNET_IDENTITY_PublicKey pkey;
289
290 if (did == NULL)
291 {
292 printf ("Set DID option to resolve DID\n");
293 GNUNET_SCHEDULER_add_now (cleanup, NULL);
294 ret = 1;
295 return;
296 }
297
298 get_pkey_from_attr_did (&pkey);
299
300 GNUNET_GNS_lookup (gns_handle, GNUNET_GNS_EMPTY_LABEL_AT, &pkey, GNUNET_DNSPARSER_TYPE_TXT,
301 GNUNET_GNS_LO_DEFAULT, &print_did_document, NULL);
302}
303
304
305/**
306 * @brief Signature of a callback function that is called after a did has been removed
307 */
308typedef void
309(*remove_did_document_callback) (void *cls);
310
311/**
312 * @brief A Structure containing a cont and cls. Can be passed as a cls to a callback function
313 *
314 */
315struct Event
316{
317 remove_did_document_callback cont;
318 void *cls;
319};
320
321/**
322 * @brief Implements the GNUNET_NAMESTORE_ContinuationWithStatus
323 * Calls the callback function and cls in the event struct
324 *
325 * @param cls closure containing the event struct
326 * @param success
327 * @param emgs
328 */
329static void
330remove_did_document_namestore_cb (void *cls, int32_t success, const char *emgs)
331{
332 struct Event *event;
333
334 if (success != GNUNET_SYSERR)
335 {
336 event = (struct Event *) cls;
337
338 if (event->cont != NULL)
339 {
340 event->cont (event->cls);
341 free (event);
342 }
343 else {
344 free (event);
345 GNUNET_SCHEDULER_add_now (cleanup, NULL);
346 ret = 0;
347 return;
348 }
349 } else {
350 printf ("Something went wrong when deleting the DID Document\n");
351
352 if (emgs != NULL)
353 {
354 printf ("%s\n", emgs);
355 }
356
357 GNUNET_SCHEDULER_add_now (cleanup, NULL);
358 ret = 0;
359 return;
360 }
361}
362
363/**
364 * @brief Callback called after the ego has been locked up
365 *
366 * @param cls closure
367 * @param ego the ego returned by the identity service
368 */
369static void
370remove_did_document_ego_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
371{
372 const struct GNUNET_IDENTITY_PrivateKey *skey =
373 GNUNET_IDENTITY_ego_get_private_key (ego);
374
375 GNUNET_NAMESTORE_records_store (namestore_handle,
376 skey,
377 GNUNET_GNS_EMPTY_LABEL_AT,
378 0,
379 NULL,
380 &remove_did_document_namestore_cb,
381 cls);
382}
383
384/**
385 * @brief Remove a DID Document
386 */
387static void
388remove_did_document (remove_did_document_callback cont, void *cls)
389{
390 struct Event *event;
391
392 if (egoname == NULL)
393 {
394 printf ("Remove requieres an ego option\n");
395 GNUNET_SCHEDULER_add_now (cleanup, NULL);
396 ret = 1;
397 return;
398 }
399 else {
400 event = malloc (sizeof(*event));
401 event->cont = cont;
402 event->cls = cls;
403
404 GNUNET_IDENTITY_ego_lookup (my_cfg,
405 egoname,
406 &remove_did_document_ego_lookup_cb,
407 (void *) event);
408 }
409}
410
411
412/**
413 * @brief Create a did generate did object
414 *
415 * @param pkey
416 * @return void* Return pointer to the DID Document
417 */
418char *
419create_did_generate (struct GNUNET_IDENTITY_PublicKey pkey)
420{
421 /* FIXME-MSC: I would prefer constants instead of magic numbers */
422 char *pkey_str; // Convert public key to string
423 char did_str[71]; // 58 + 12 + 1 = 71
424 char *didd_str;
425 char verify_id_str[77]; // did_str len + "#key-1" = 71 + 6 = 77
426 char *pkey_multibase_str;
427
428 /* FIXME-MSC: This screams for a GNUNET_DID_identity_key_to_string() */
429 char *b64;
430 char pkx[34];
431 pkx[0] = 0xed;
432 pkx[1] = 0x01;
433 memcpy (pkx + 2, &(pkey.eddsa_key), sizeof(pkey.eddsa_key));
434 GNUNET_STRINGS_base64_encode (pkx, sizeof(pkx), &b64);
435
436 GNUNET_asprintf (&pkey_multibase_str, "u%s", b64);
437
438 json_t *didd;
439 json_t *did_json;
440 json_t *pkey_multibase_json;
441 json_t *context_json;
442 json_t *context_1_json;
443 json_t *context_2_json;
444 json_t *verify_json;
445 json_t *verify_1_json;
446 json_t *verify_1_type_json;
447 json_t *verify_1_id_json;
448 json_t *verify_relative_ref_json;
449 json_t *auth_json;
450 json_t *assert_json;
451
452 /* FIXME-MSC: This screams for GNUNET_DID_identity_to_did() */
453 pkey_str = GNUNET_IDENTITY_public_key_to_string (&pkey); // Convert public key to string
454 sprintf (did_str, "did:reclaim:%s", pkey_str); // Convert the public key to a DID str
455 sprintf (verify_id_str, "did:reclaim:%s#key-1", pkey_str); // Convert the public key to a DID str
456
457 // sprintf(pkey_multibase_str, "V%s", pkey_str); // Convert the public key to MultiBase data format
458
459 /* FIXME-MSC: This is effectively creating a DID Document default template for
460 * the initial document.
461 * Maybe this can be refactored to generate such a template for an identity?
462 * Even if higher layers add/modify it, there should probably still be a
463 * GNUNET_DID_document_template_from_identity()
464 */
465 // Create Json Strings
466 did_json = json_string (did_str);
467 pkey_multibase_json = json_string (pkey_multibase_str);
468
469 context_1_json = json_string ("https://www.w3.org/ns/did/v1");
470 context_2_json = json_string (
471 "https://w3id.org/security/suites/ed25519-2020/v1");
472 verify_1_id_json = json_string (verify_id_str);
473 verify_1_type_json = json_string ("Ed25519VerificationKey2020");
474
475 // Add a relative DID URL to reference a verifiation method
476 // https://www.w3.org/TR/did-core/#relative-did-urls`
477 verify_relative_ref_json = json_string ("#key-1");
478
479 // Create DID Document
480 didd = json_object ();
481
482 // Add context
483 context_json = json_array ();
484 json_array_append (context_json, context_1_json);
485 json_array_append (context_json, context_2_json);
486 json_object_set (didd, "@context", context_json);
487
488 // Add id
489 json_object_set (didd, "id", did_json);
490
491 // Add verification method
492 verify_json = json_array ();
493 verify_1_json = json_object ();
494 json_object_set (verify_1_json, "id", verify_1_id_json);
495 json_object_set (verify_1_json, "type", verify_1_type_json);
496 json_object_set (verify_1_json, "controller", did_json);
497 json_object_set (verify_1_json, "publicKeyMultiBase", pkey_multibase_json);
498 json_array_append (verify_json, verify_1_json);
499 json_object_set (didd, "verificationMethod", verify_json);
500
501 // Add authentication method
502 auth_json = json_array ();
503 json_array_append (auth_json, verify_relative_ref_json);
504 json_object_set (didd, "authentication", auth_json);
505
506 // Add assertion method to issue a Verifiable Credential
507 assert_json = json_array ();
508 json_array_append (assert_json, verify_relative_ref_json);
509 json_object_set (didd, "assertionMethod", assert_json);
510
511 // Encode DID Document as JSON string
512 didd_str = json_dumps (didd, JSON_INDENT (2));
513 if (didd_str == NULL)
514 {
515 printf ("DID Document could not be encoded");
516 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
517 ret = 1;
518 return NULL;
519 }
520
521 // TODO: MORE FREEEEEEEE
522 /* FIXME-MSC: json_t's are free'd using "json_decref". Also json_t usually
523 * keeps a reference counter. Check jansson docs for how to use it.
524 * Also: Use valgrind to find leaks.
525 */
526 free (pkey_multibase_str);
527 free (b64);
528
529 free (didd);
530 free (did_json);
531 free (pkey_multibase_json);
532 free (context_json);
533 free (context_1_json);
534 free (context_2_json);
535 free (verify_json);
536 free (verify_1_json);
537 free (verify_1_type_json);
538 free (verify_1_id_json);
539 free (auth_json);
540 free (assert_json);
541 free (verify_relative_ref_json);
542
543 return didd_str;
544}
545
546/**
547 * @brief Create a DID. Store DID in Namestore cb
548 *
549 */
550static void
551create_did_store_cb (void *cls, int32_t success, const char *emsg)
552{
553 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
554 ret = 0;
555 return;
556}
557
558/**
559 * @brief Create a did. Store DID in Namestore
560 *
561 * @param didd_str String endoced DID Docuement
562 * @param ego Identity whos DID Document is stored
563 */
564static void
565create_did_store (char *didd_str, struct GNUNET_IDENTITY_Ego *ego)
566{
567
568 struct GNUNET_TIME_Relative expire_time;
569 struct GNUNET_GNSRECORD_Data record_data;
570 const struct GNUNET_IDENTITY_PrivateKey *skey;
571
572 if (GNUNET_STRINGS_fancy_time_to_relative ((NULL != expire) ?
573 expire :
574 GNUNET_DID_DEFAULT_DID_DOCUMENT_EXPIRATION_TIME,
575 &expire_time) == GNUNET_OK)
576 {
577 record_data.data = didd_str;
578 record_data.expiration_time = expire_time.rel_value_us;
579 record_data.data_size = strlen (didd_str) + 1;
580 record_data.record_type = GNUNET_GNSRECORD_typename_to_number ("TXT"),
581 record_data.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
582
583 skey = GNUNET_IDENTITY_ego_get_private_key (ego);
584
585 GNUNET_NAMESTORE_records_store (namestore_handle,
586 skey,
587 GNUNET_GNS_EMPTY_LABEL_AT,
588 1, //FIXME what if GNUNET_GNS_EMPTY_LABEL_AT has records
589 &record_data,
590 &create_did_store_cb,
591 NULL);
592 }
593 else {
594 printf ("Failed to read given expiration time\n");
595 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
596 ret = 1;
597 return;
598 }
599}
600
601/**
602 * @brief Create a did ego lockup cb
603 *
604 * @param cls
605 * @param ego
606 */
607static void
608create_did_ego_lockup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
609{
610 struct GNUNET_IDENTITY_PublicKey pkey;
611 char *didd_str;
612
613 if (ego == NULL)
614 {
615 printf ("EGO not found\n");
616 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
617 ret = 1;
618 return;
619 }
620
621 GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
622
623 if (ntohl (pkey.type) != GNUNET_GNSRECORD_TYPE_EDKEY)
624 {
625 printf ("The EGO has to have an EDDSA key pair\n");
626 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
627 ret = 1;
628 return;
629 }
630
631 if (didd != NULL)
632 {
633 printf (
634 "DID Docuement is read from \"did-document\" argument (EXPERIMENTAL)\n");
635 didd_str = strdup (didd);
636 }
637 else {
638 // Generate DID Docuement from public key
639 didd_str = create_did_generate (pkey);
640 }
641
642 // Print DID Document to stdout
643 printf ("%s\n", didd_str);
644
645 // Store the DID Document
646 create_did_store (didd_str, ego);
647
648 // Save DID Document String to GNS
649 free (didd_str);
650}
651
652/**
653 * @brief Create a did document - Create a new identity first
654 */
655static void
656create_did_document_ego_create_cb (void *cls,
657 const struct GNUNET_IDENTITY_PrivateKey *pk,
658 const char *emsg)
659{
660
661 if (emsg != NULL)
662 {
663 printf ("%s\n", emsg);
664 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
665 ret = 1;
666 return;
667 }
668
669 GNUNET_IDENTITY_ego_lookup (my_cfg,
670 egoname,
671 &create_did_ego_lockup_cb,
672 NULL);
673}
674
675/**
676 * @brief Create a did document
677 *
678 */
679static void
680create_did_document ()
681{
682 if ((egoname != NULL) && (expire != NULL))
683 {
684 GNUNET_IDENTITY_create (identity_handle,
685 egoname,
686 NULL,
687 GNUNET_IDENTITY_TYPE_EDDSA,
688 &create_did_document_ego_create_cb,
689 egoname);
690 }
691 else {
692 printf (
693 "Set the EGO and the Expiration-time argument to create a new DID(-Document)\n");
694 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
695 ret = 1;
696 return;
697 }
698}
699
700
701/**
702 * @brief Replace a DID Docuemnt. Callback function after ego lockup
703 *
704 * @param cls
705 * @param ego
706 */
707static void
708replace_did_document_ego_lookup_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
709{
710 create_did_store (didd, ego);
711}
712
713/**
714 * @brief Replace a DID Document. Callback functiona after remove
715 *
716 * @param cls
717 */
718static void
719replace_did_document_remove_cb (void *cls)
720{
721 GNUNET_IDENTITY_ego_lookup (my_cfg,
722 egoname,
723 &replace_did_document_ego_lookup_cb,
724 NULL);
725}
726
727/**
728 * @brief Replace a DID Docuemnt
729 *
730 */
731static void
732replace_did_document ()
733{
734 if ((didd != NULL) && (expire != NULL))
735 {
736 remove_did_document (&replace_did_document_remove_cb, NULL);
737 }
738 else {
739 printf (
740 "Set the DID Document and expiration time argument to replace the DID Document\n");
741 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
742 ret = 1;
743 return;
744 }
745}
746
747static void
748post_ego_iteration (void *cls)
749{
750 if (1 == replace)
751 {
752 replace_did_document ();
753 }
754 else if (1 == get)
755 {
756 resolve_did_document ();
757 }
758 else if (1 == remove_did)
759 {
760 remove_did_document (NULL, NULL);
761 }
762 else if (1 == create)
763 {
764 create_did_document ();
765 }
766 else {
767 // No Argument found
768 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
769 return;
770 }
771}
772
773static void
774process_dids (void *cls, struct GNUNET_IDENTITY_Ego *ego,
775 void **ctx, const char*name)
776{
777 char *did_str;
778
779 if (ego == NULL)
780 {
781 if (1 == ego_exists)
782 {
783 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
784 return;
785 }
786 GNUNET_SCHEDULER_add_now (&post_ego_iteration, NULL);
787 return;
788 }
789 if (NULL == name)
790 return;
791 if ((1 == create) &&
792 (0 == strncmp (name, egoname, strlen (egoname))) &&
793 (1 != ego_exists))
794 {
795 fprintf(stderr, "%s already exists!\n", egoname);
796 ego_exists = 1;
797 return;
798 }
799 if (1 == show_all)
800 {
801 did_str = ego_to_did (ego);
802 printf ("%s\n", did_str);
803 GNUNET_free (did_str);
804 return;
805 }
806 if (1 == show)
807 {
808 if (0 == strncmp (name, egoname, strlen (egoname)))
809 {
810 did_str = ego_to_did (ego);
811 printf ("%s\n", did_str);
812 GNUNET_free (did_str);
813 return;
814 }
815 }
816}
817
818
819
820static void
821run (void *cls,
822 char *const *args,
823 const char *cfgfile,
824 const struct GNUNET_CONFIGURATION_Handle *c)
825{
826 gns_handle = GNUNET_GNS_connect (c);
827 namestore_handle = GNUNET_NAMESTORE_connect (c);
828 my_cfg = c;
829
830 // check if GNS_handle could connect
831 if (gns_handle == NULL)
832 {
833 ret = 1;
834 return;
835 }
836
837 // check if NAMESTORE_handle could connect
838 if (namestore_handle == NULL)
839 {
840 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
841 ret = 1;
842 return;
843 }
844
845 identity_handle = GNUNET_IDENTITY_connect (c, &process_dids, NULL);
846 if (identity_handle == NULL)
847 {
848 GNUNET_SCHEDULER_add_now (&cleanup, NULL);
849 ret = 1;
850 return;
851 }
852}
853
854int
855main (int argc, char *const argv[])
856{
857 struct GNUNET_GETOPT_CommandLineOption options[] = {
858 GNUNET_GETOPT_option_flag ('C',
859 "create",
860 gettext_noop (
861 "Create a DID Document and display its DID"),
862 &create),
863 GNUNET_GETOPT_option_flag ('g',
864 "get",
865 gettext_noop (
866 "Get the DID Document associated with the given DID"),
867 &get),
868 GNUNET_GETOPT_option_flag ('s',
869 "show",
870 gettext_noop ("Show the DID for a given ego"),
871 &show),
872 GNUNET_GETOPT_option_flag ('r',
873 "remove",
874 gettext_noop (
875 "Remove the DID"),
876 &remove_did),
877 GNUNET_GETOPT_option_flag ('R',
878 "replace",
879 gettext_noop ("Replace the DID Document."),
880 &replace),
881 GNUNET_GETOPT_option_flag ('A',
882 "--show-all",
883 gettext_noop ("Replace the DID Document."),
884 &show_all),
885 GNUNET_GETOPT_option_string ('d',
886 "did",
887 "DID",
888 gettext_noop (
889 "The Decentralized Identity (DID)"),
890 &did),
891 GNUNET_GETOPT_option_string ('D',
892 "--did-document",
893 "JSON",
894 gettext_noop (
895 "The DID Document to store in GNUNET"),
896 &didd),
897 GNUNET_GETOPT_option_string ('e',
898 "ego",
899 "EGO",
900 gettext_noop ("The name of the EGO"),
901 &egoname),
902 GNUNET_GETOPT_option_string ('t',
903 "expiration-time",
904 "TIME",
905 gettext_noop (
906 "The time until the DID Document is going to expire (e.g. 5d)"),
907 &expire),
908 GNUNET_GETOPT_OPTION_END
909 };
910
911 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
912 argv,
913 "gnunet-did",
914 _ (
915 "Manage Decentralized Identities (DIDs)"),
916 options,
917 &run,
918 NULL))
919 return 1;
920 else
921 return ret;
922}
diff --git a/src/reclaim/test_w3c_ed25519_2020.c b/src/reclaim/test_w3c_ed25519_2020.c
new file mode 100644
index 000000000..e2534e6ab
--- /dev/null
+++ b/src/reclaim/test_w3c_ed25519_2020.c
@@ -0,0 +1,69 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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/**
23 * @file src/did/test_w3c_ed25519_2020.c
24 * @brief Testcases for the w3c Ed25519 formats for SSIs https://w3c-ccg.github.io/lds-ed25519-2020
25 * @author Martin Schanzenbach
26 */
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_strings_lib.h"
31
32static char test_privkey[32] = {
33 0x9b, 0x93, 0x7b, 0x81, 0x32, 0x2d, 0x81, 0x6c,
34 0xfa, 0xb9, 0xd5, 0xa3, 0xba, 0xac, 0xc9, 0xb2,
35 0xa5, 0xfe, 0xbe, 0x4b, 0x14, 0x9f, 0x12, 0x6b,
36 0x36, 0x30, 0xf9, 0x3a, 0x29, 0x52, 0x70, 0x17
37};
38
39static char *targetPublicKeyMultibase = "u7QEJX5oaWV3edV2CeGhkrQPfpaT71ogyVmNk4rZeE8yeRA";
40
41int
42main ()
43{
44 struct GNUNET_CRYPTO_EddsaPrivateKey privkey;
45 struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
46
47 memcpy (&privkey, test_privkey, sizeof (privkey));
48 GNUNET_CRYPTO_eddsa_key_get_public (&privkey, &pubkey);
49
50 //This is how to convert out pubkeys to W3c Ed25519-2020 multibase (base64url no padding)
51 char *b64;
52 char pkx[34];
53 pkx[0] = 0xed;
54 pkx[1] = 0x01;
55 memcpy (pkx+2, &pubkey, sizeof (pubkey));
56 GNUNET_STRINGS_base64url_encode (pkx,
57 sizeof (pkx),
58 &b64);
59 printf ("u%s\n%s\n", b64, targetPublicKeyMultibase);
60 // FIXME convert pubkey to target
61 char *res;
62 GNUNET_asprintf (&res, "u%s", b64);
63 GNUNET_assert (0 == strcmp (res,
64 targetPublicKeyMultibase));
65
66 GNUNET_free (b64);
67 GNUNET_free (res);
68 return 0;
69}