aboutsummaryrefslogtreecommitdiff
path: root/src/reclaim
diff options
context:
space:
mode:
Diffstat (limited to 'src/reclaim')
-rw-r--r--src/reclaim/.gitignore2
-rw-r--r--src/reclaim/Makefile.am201
-rw-r--r--src/reclaim/gnunet-reclaim.c925
-rw-r--r--src/reclaim/gnunet-service-reclaim.c2504
-rw-r--r--src/reclaim/gnunet-service-reclaim_tickets.c1853
-rw-r--r--src/reclaim/gnunet-service-reclaim_tickets.h280
-rw-r--r--src/reclaim/json_reclaim.c398
-rw-r--r--src/reclaim/json_reclaim.h57
-rw-r--r--src/reclaim/oidc_helper.c934
-rw-r--r--src/reclaim/oidc_helper.h177
-rw-r--r--src/reclaim/pabc_helper.c365
-rw-r--r--src/reclaim/pabc_helper.h41
-rw-r--r--src/reclaim/plugin_gnsrecord_reclaim.c195
-rw-r--r--src/reclaim/plugin_reclaim_attribute_basic.c181
-rw-r--r--src/reclaim/plugin_reclaim_credential_jwt.c499
-rw-r--r--src/reclaim/plugin_reclaim_credential_pabc.c572
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c2860
-rw-r--r--src/reclaim/plugin_rest_pabc.c667
-rw-r--r--src/reclaim/plugin_rest_reclaim.c1564
-rw-r--r--src/reclaim/reclaim.conf19
-rw-r--r--src/reclaim/reclaim.h552
-rw-r--r--src/reclaim/reclaim_api.c1762
-rw-r--r--src/reclaim/reclaim_attribute.c582
-rw-r--r--src/reclaim/reclaim_attribute.h73
-rw-r--r--src/reclaim/reclaim_credential.c1064
-rw-r--r--src/reclaim/reclaim_credential.h99
-rw-r--r--src/reclaim/test_reclaim.conf34
-rwxr-xr-xsrc/reclaim/test_reclaim.sh31
-rw-r--r--src/reclaim/test_reclaim_attribute.c49
-rwxr-xr-xsrc/reclaim/test_reclaim_attribute.sh40
-rwxr-xr-xsrc/reclaim/test_reclaim_consume.sh43
-rw-r--r--src/reclaim/test_reclaim_defaults.conf24
-rwxr-xr-xsrc/reclaim/test_reclaim_issue.sh42
-rwxr-xr-xsrc/reclaim/test_reclaim_revoke.sh65
34 files changed, 0 insertions, 18754 deletions
diff --git a/src/reclaim/.gitignore b/src/reclaim/.gitignore
deleted file mode 100644
index 46472101b..000000000
--- a/src/reclaim/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
1gnunet-reclaim
2gnunet-service-reclaim
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am
deleted file mode 100644
index 350d77d4b..000000000
--- a/src/reclaim/Makefile.am
+++ /dev/null
@@ -1,201 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4 plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11
12REST_PLUGIN = \
13 libgnunet_plugin_rest_openid_connect.la \
14 libgnunet_plugin_rest_reclaim.la
15
16CREDENTIAL_PLUGIN = \
17 libgnunet_plugin_reclaim_credential_jwt.la
18
19if HAVE_PABC
20 CREDENTIAL_PLUGIN += libgnunet_plugin_reclaim_credential_pabc.la
21 REST_PLUGIN += libgnunet_plugin_rest_pabc.la
22endif
23
24EXTRA_DIST = \
25 reclaim.conf \
26 test_reclaim_defaults.conf \
27 test_reclaim.conf \
28 $(check_SCRIPTS)
29
30pkgcfgdir= $(pkgdatadir)/config.d/
31
32libexecdir= $(pkglibdir)/libexec/
33
34pkgcfg_DATA = \
35 reclaim.conf
36
37lib_LTLIBRARIES = \
38 libgnunetreclaim.la
39plugin_LTLIBRARIES = \
40 libgnunet_plugin_gnsrecord_reclaim.la \
41 libgnunet_plugin_reclaim_attribute_basic.la \
42 $(CREDENTIAL_PLUGIN) \
43 $(REST_PLUGIN)
44
45bin_PROGRAMS = \
46 gnunet-reclaim
47
48libexec_PROGRAMS = \
49 gnunet-service-reclaim
50
51libgnunet_plugin_rest_reclaim_la_SOURCES = \
52 plugin_rest_reclaim.c \
53 json_reclaim.h \
54 json_reclaim.c
55libgnunet_plugin_rest_reclaim_la_LIBADD = \
56 $(top_builddir)/src/identity/libgnunetidentity.la \
57 libgnunetreclaim.la \
58 $(top_builddir)/src/json/libgnunetjson.la \
59 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
60 $(top_builddir)/src/rest/libgnunetrest.la \
61 $(top_builddir)/src/namestore/libgnunetnamestore.la \
62 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
63 $(LTLIBINTL) -ljansson $(MHD_LIBS)
64libgnunet_plugin_rest_reclaim_la_LDFLAGS = \
65 $(GN_PLUGIN_LDFLAGS)
66libgnunet_plugin_rest_reclaim_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
67
68
69libgnunet_plugin_rest_openid_connect_la_SOURCES = \
70 plugin_rest_openid_connect.c \
71 oidc_helper.h \
72 oidc_helper.c
73libgnunet_plugin_rest_openid_connect_la_LIBADD = \
74 $(top_builddir)/src/identity/libgnunetidentity.la \
75 libgnunetreclaim.la \
76 $(top_builddir)/src/rest/libgnunetrest.la \
77 $(top_builddir)/src/namestore/libgnunetnamestore.la \
78 $(top_builddir)/src/gns/libgnunetgns.la \
79 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
80 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
81 $(LTLIBINTL) -ljansson $(MHD_LIBS) \
82 $(LIBGCRYPT_LIBS)
83libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \
84 $(GN_PLUGIN_LDFLAGS)
85libgnunet_plugin_rest_openid_connect_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
86
87if HAVE_PABC
88libgnunet_plugin_rest_pabc_la_SOURCES = \
89 plugin_rest_pabc.c \
90 pabc_helper.c
91libgnunet_plugin_rest_pabc_la_LIBADD = \
92 libgnunetreclaim.la \
93 $(top_builddir)/src/json/libgnunetjson.la \
94 $(top_builddir)/src/rest/libgnunetrest.la \
95 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
96 $(LTLIBINTL) -ljansson -lpabc $(MHD_LIBS)
97libgnunet_plugin_rest_pabc_la_LDFLAGS = \
98 $(GN_PLUGIN_LDFLAGS)
99libgnunet_plugin_rest_pabc_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
100endif
101
102
103libgnunet_plugin_gnsrecord_reclaim_la_SOURCES = \
104 plugin_gnsrecord_reclaim.c
105libgnunet_plugin_gnsrecord_reclaim_la_LIBADD = \
106 $(top_builddir)/src/util/libgnunetutil.la \
107 $(LTLIBINTL)
108libgnunet_plugin_gnsrecord_reclaim_la_LDFLAGS = \
109 $(GN_PLUGIN_LDFLAGS)
110
111
112gnunet_service_reclaim_SOURCES = \
113 gnunet-service-reclaim.c \
114 gnunet-service-reclaim_tickets.c \
115 gnunet-service-reclaim_tickets.h
116gnunet_service_reclaim_LDADD = \
117 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
118 $(top_builddir)/src/identity/libgnunetidentity.la \
119 $(top_builddir)/src/util/libgnunetutil.la \
120 $(top_builddir)/src/namestore/libgnunetnamestore.la \
121 $(top_builddir)/src/statistics/libgnunetstatistics.la \
122 libgnunetreclaim.la \
123 $(top_builddir)/src/gns/libgnunetgns.la \
124 $(GN_LIBINTL)
125
126libgnunetreclaim_la_SOURCES = \
127 reclaim_api.c \
128 reclaim.h \
129 reclaim_attribute.c \
130 reclaim_attribute.h \
131 reclaim_credential.c \
132 reclaim_credential.h
133libgnunetreclaim_la_LIBADD = \
134 $(top_builddir)/src/util/libgnunetutil.la \
135 $(GN_LIBINTL) $(XLIB)
136libgnunetreclaim_la_LDFLAGS = \
137 $(GN_LIB_LDFLAGS) \
138 -version-info 0:0:0
139
140
141libgnunet_plugin_reclaim_attribute_basic_la_SOURCES = \
142 plugin_reclaim_attribute_basic.c
143libgnunet_plugin_reclaim_attribute_basic_la_LIBADD = \
144 $(top_builddir)/src/util/libgnunetutil.la \
145 $(LTLIBINTL)
146libgnunet_plugin_reclaim_attribute_basic_la_LDFLAGS = \
147 $(GN_PLUGIN_LDFLAGS)
148
149if HAVE_PABC
150libgnunet_plugin_reclaim_credential_pabc_la_SOURCES = \
151 plugin_reclaim_credential_pabc.c \
152 pabc_helper.c
153libgnunet_plugin_reclaim_credential_pabc_la_LIBADD = \
154 $(top_builddir)/src/util/libgnunetutil.la \
155 libgnunetreclaim.la \
156 -ljansson\
157 -lpabc \
158 $(LTLIBINTL)
159libgnunet_plugin_reclaim_credential_pabc_la_LDFLAGS = \
160 $(GN_PLUGIN_LDFLAGS)
161endif
162
163
164libgnunet_plugin_reclaim_credential_jwt_la_SOURCES = \
165 plugin_reclaim_credential_jwt.c
166libgnunet_plugin_reclaim_credential_jwt_la_LIBADD = \
167 $(top_builddir)/src/util/libgnunetutil.la \
168 libgnunetreclaim.la \
169 -ljansson\
170 $(LTLIBINTL)
171libgnunet_plugin_reclaim_credential_jwt_la_LDFLAGS = \
172 $(GN_PLUGIN_LDFLAGS)
173
174gnunet_reclaim_SOURCES = \
175 gnunet-reclaim.c
176gnunet_reclaim_LDADD = \
177 $(top_builddir)/src/util/libgnunetutil.la \
178 $(top_builddir)/src/namestore/libgnunetnamestore.la \
179 libgnunetreclaim.la \
180 $(top_builddir)/src/identity/libgnunetidentity.la \
181 $(GN_LIBINTL)
182
183test_reclaim_attribute_SOURCES = \
184 test_reclaim_attribute.c
185test_reclaim_attribute_LDADD = \
186 $(top_builddir)/src/util/libgnunetutil.la \
187 libgnunetreclaim.la \
188 $(GN_LIBINTL)
189
190check_SCRIPTS = \
191 test_reclaim_attribute.sh \
192 test_reclaim_issue.sh \
193 test_reclaim_consume.sh
194
195check_PROGRAMS = \
196 test_reclaim_attribute
197
198if 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;
200 TESTS = $(check_SCRIPTS)
201endif
diff --git a/src/reclaim/gnunet-reclaim.c b/src/reclaim/gnunet-reclaim.c
deleted file mode 100644
index da5f90409..000000000
--- a/src/reclaim/gnunet-reclaim.c
+++ /dev/null
@@ -1,925 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @file src/reclaim/gnunet-reclaim.c
23 * @brief Identity Provider utility
24 *
25 */
26#include "platform.h"
27#include <inttypes.h>
28
29#include "gnunet_util_lib.h"
30
31#include "gnunet_identity_service.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_reclaim_service.h"
34#include "gnunet_signatures.h"
35/**
36 * return value
37 */
38static int ret;
39
40/**
41 * List attribute flag
42 */
43static int list;
44
45/**
46 * List credentials flag
47 */
48static int list_credentials;
49
50/**
51 * Credential ID string
52 */
53static char *credential_id;
54
55/**
56 * Credential ID
57 */
58static struct GNUNET_RECLAIM_Identifier credential;
59
60/**
61 * Credential name
62 */
63static char *credential_name;
64
65/**
66 * Credential type
67 */
68static char *credential_type;
69
70/**
71 * Credential exists
72 */
73static int credential_exists;
74
75/**
76 * Relying party
77 */
78static char *rp;
79
80/**
81 * The attribute
82 */
83static char *attr_name;
84
85/**
86 * Attribute value
87 */
88static char *attr_value;
89
90/**
91 * Attributes to issue
92 */
93static char *issue_attrs;
94
95/**
96 * Ticket to consume
97 */
98static char *consume_ticket;
99
100/**
101 * Attribute type
102 */
103static char *type_str;
104
105/**
106 * Ticket to revoke
107 */
108static char *revoke_ticket;
109
110/**
111 * Ticket listing
112 */
113static int list_tickets;
114
115/**
116 * Ego name
117 */
118static char *ego_name;
119
120/**
121 * Identity handle
122 */
123static struct GNUNET_IDENTITY_Handle *identity_handle;
124
125/**
126 * reclaim handle
127 */
128static struct GNUNET_RECLAIM_Handle *reclaim_handle;
129
130/**
131 * reclaim operation
132 */
133static struct GNUNET_RECLAIM_Operation *reclaim_op;
134
135/**
136 * Attribute iterator
137 */
138static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator;
139
140/**
141 * Credential iterator
142 */
143static struct GNUNET_RECLAIM_CredentialIterator *cred_iterator;
144
145
146/**
147 * Ticket iterator
148 */
149static struct GNUNET_RECLAIM_TicketIterator *ticket_iterator;
150
151
152/**
153 * ego private key
154 */
155static const struct GNUNET_IDENTITY_PrivateKey *pkey;
156
157/**
158 * rp public key
159 */
160static struct GNUNET_IDENTITY_PublicKey rp_key;
161
162/**
163 * Ticket to consume
164 */
165static struct GNUNET_RECLAIM_Ticket ticket;
166
167/**
168 * Attribute list
169 */
170static struct GNUNET_RECLAIM_AttributeList *attr_list;
171
172/**
173 * Attribute expiration interval
174 */
175static struct GNUNET_TIME_Relative exp_interval;
176
177/**
178 * Timeout task
179 */
180static struct GNUNET_SCHEDULER_Task *timeout;
181
182/**
183 * Cleanup task
184 */
185static struct GNUNET_SCHEDULER_Task *cleanup_task;
186
187/**
188 * Claim to store
189 */
190struct GNUNET_RECLAIM_Attribute *claim;
191
192/**
193 * Claim to delete
194 */
195static char *attr_delete;
196
197/**
198 * Claim object to delete
199 */
200static struct GNUNET_RECLAIM_Attribute *attr_to_delete;
201
202static void
203do_cleanup (void *cls)
204{
205 cleanup_task = NULL;
206 if (NULL != timeout)
207 GNUNET_SCHEDULER_cancel (timeout);
208 if (NULL != reclaim_op)
209 GNUNET_RECLAIM_cancel (reclaim_op);
210 if (NULL != attr_iterator)
211 GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
212 if (NULL != cred_iterator)
213 GNUNET_RECLAIM_get_credentials_stop (cred_iterator);
214 if (NULL != ticket_iterator)
215 GNUNET_RECLAIM_ticket_iteration_stop (ticket_iterator);
216 if (NULL != reclaim_handle)
217 GNUNET_RECLAIM_disconnect (reclaim_handle);
218 if (NULL != identity_handle)
219 GNUNET_IDENTITY_disconnect (identity_handle);
220 if (NULL != attr_list)
221 GNUNET_free (attr_list);
222 if (NULL != attr_to_delete)
223 GNUNET_free (attr_to_delete);
224 if (NULL == credential_type)
225 GNUNET_free (credential_type);
226}
227
228
229static void
230ticket_issue_cb (void *cls,
231 const struct GNUNET_RECLAIM_Ticket *ticket,
232 const struct GNUNET_RECLAIM_PresentationList *presentations)
233{
234 char *ticket_str;
235
236 reclaim_op = NULL;
237 if (NULL != ticket)
238 {
239 ticket_str =
240 GNUNET_STRINGS_data_to_string_alloc (ticket,
241 sizeof(
242 struct GNUNET_RECLAIM_Ticket));
243 printf ("%s\n", ticket_str);
244 GNUNET_free (ticket_str);
245 }
246 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
247}
248
249
250static void
251store_cont (void *cls, int32_t success, const char *emsg)
252{
253 reclaim_op = NULL;
254 if (GNUNET_SYSERR == success)
255 {
256 fprintf (stderr, "%s\n", emsg);
257 }
258 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
259}
260
261
262static void
263process_attrs (void *cls,
264 const struct GNUNET_IDENTITY_PublicKey *identity,
265 const struct GNUNET_RECLAIM_Attribute *attr,
266 const struct GNUNET_RECLAIM_Presentation *presentation)
267{
268 char *value_str;
269 char *id;
270 const char *attr_type;
271
272 if (NULL == identity)
273 {
274 reclaim_op = NULL;
275 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
276 return;
277 }
278 if (NULL == attr)
279 {
280 ret = 1;
281 return;
282 }
283 attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
284 id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
285 value_str = NULL;
286 if (NULL == presentation)
287 {
288 value_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
289 attr->data,
290 attr->data_size);
291 }
292 else
293 {
294 struct GNUNET_RECLAIM_AttributeListEntry *ale;
295 struct GNUNET_RECLAIM_AttributeList *al
296 = GNUNET_RECLAIM_presentation_get_attributes (presentation);
297
298 for (ale = al->list_head; NULL != ale; ale = ale->next)
299 {
300 if (0 != strncmp (attr->data, ale->attribute->name, attr->data_size))
301 continue;
302 value_str
303 = GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type,
304 ale->attribute->data,
305 ale->attribute->data_size);
306 break;
307 }
308 }
309 fprintf (stdout,
310 "Name: %s; Value: %s (%s); Flag %u; ID: %s %s\n",
311 attr->name,
312 (NULL != value_str) ? value_str : "???",
313 attr_type,
314 attr->flag,
315 id,
316 (NULL == presentation) ? "" : "(ATTESTED)");
317 GNUNET_free (value_str);
318 GNUNET_free (id);
319}
320
321
322static void
323ticket_iter_err (void *cls)
324{
325 ticket_iterator = NULL;
326 fprintf (stderr, "Failed to iterate over tickets\n");
327 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
328}
329
330
331static void
332ticket_iter_fin (void *cls)
333{
334 ticket_iterator = NULL;
335 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
336}
337
338
339static void
340ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
341{
342 char *aud;
343 char *ref;
344 char *tkt;
345
346 aud =
347 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
348 sizeof(struct
349 GNUNET_IDENTITY_PublicKey));
350 ref = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
351 tkt =
352 GNUNET_STRINGS_data_to_string_alloc (ticket,
353 sizeof(struct GNUNET_RECLAIM_Ticket));
354 fprintf (stdout, "Ticket: %s | ID: %s | Audience: %s\n", tkt, ref, aud);
355 GNUNET_free (aud);
356 GNUNET_free (ref);
357 GNUNET_free (tkt);
358 GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
359}
360
361
362static void
363iter_error (void *cls)
364{
365 attr_iterator = NULL;
366 cred_iterator = NULL;
367 fprintf (stderr, "Failed\n");
368
369 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
370}
371
372
373static void
374timeout_task (void *cls)
375{
376 timeout = NULL;
377 ret = 1;
378 fprintf (stderr, "Timeout\n");
379 if (NULL == cleanup_task)
380 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
381}
382
383
384static void
385process_rvk (void *cls, int success, const char *msg)
386{
387 reclaim_op = NULL;
388 if (GNUNET_OK != success)
389 {
390 fprintf (stderr, "Revocation failed.\n");
391 ret = 1;
392 }
393 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
394}
395
396
397static void
398process_delete (void *cls, int success, const char *msg)
399{
400 reclaim_op = NULL;
401 if (GNUNET_OK != success)
402 {
403 fprintf (stderr, "Deletion failed.\n");
404 ret = 1;
405 }
406 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
407}
408
409
410static void
411iter_finished (void *cls)
412{
413 char *data;
414 size_t data_size;
415 int type;
416
417 attr_iterator = NULL;
418 if (list)
419 {
420 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
421 return;
422 }
423
424 if (issue_attrs)
425 {
426 reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
427 pkey,
428 &rp_key,
429 attr_list,
430 &ticket_issue_cb,
431 NULL);
432 return;
433 }
434 if (consume_ticket)
435 {
436 reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
437 pkey,
438 &ticket,
439 &process_attrs,
440 NULL);
441 timeout = GNUNET_SCHEDULER_add_delayed (
442 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
443 &timeout_task,
444 NULL);
445 return;
446 }
447 if (revoke_ticket)
448 {
449 reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
450 pkey,
451 &ticket,
452 &process_rvk,
453 NULL);
454 return;
455 }
456 if (attr_delete)
457 {
458 if (NULL == attr_to_delete)
459 {
460 fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
461 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
462 return;
463 }
464 reclaim_op = GNUNET_RECLAIM_attribute_delete (reclaim_handle,
465 pkey,
466 attr_to_delete,
467 &process_delete,
468 NULL);
469 return;
470 }
471 if (attr_name)
472 {
473 if (NULL == type_str)
474 type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
475 else
476 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
477
478 GNUNET_assert (GNUNET_SYSERR !=
479 GNUNET_RECLAIM_attribute_string_to_value (type,
480 attr_value,
481 (void **) &data,
482 &data_size));
483 if (NULL != claim)
484 {
485 claim->type = type;
486 claim->data = data;
487 claim->data_size = data_size;
488 }
489 else
490 {
491 claim =
492 GNUNET_RECLAIM_attribute_new (attr_name, NULL, type, data, data_size);
493 }
494 if (NULL != credential_id)
495 {
496 claim->credential = credential;
497 }
498 reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
499 pkey,
500 claim,
501 &exp_interval,
502 &store_cont,
503 NULL);
504 GNUNET_free (data);
505 GNUNET_free (claim);
506 return;
507 }
508 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
509}
510
511
512static void
513iter_cb (void *cls,
514 const struct GNUNET_IDENTITY_PublicKey *identity,
515 const struct GNUNET_RECLAIM_Attribute *attr)
516{
517 struct GNUNET_RECLAIM_AttributeListEntry *le;
518 char *attrs_tmp;
519 char *attr_str;
520 char *label;
521 char *id;
522 const char *attr_type;
523
524 if ((NULL != attr_name) && (NULL == claim))
525 {
526 if (0 == strcasecmp (attr_name, attr->name))
527 {
528 claim = GNUNET_RECLAIM_attribute_new (attr->name,
529 &attr->credential,
530 attr->type,
531 attr->data,
532 attr->data_size);
533 claim->id = attr->id;
534 }
535 }
536 else if (issue_attrs)
537 {
538 attrs_tmp = GNUNET_strdup (issue_attrs);
539 attr_str = strtok (attrs_tmp, ",");
540 while (NULL != attr_str)
541 {
542 if (0 != strcasecmp (attr_str, attr->name))
543 {
544 attr_str = strtok (NULL, ",");
545 continue;
546 }
547 le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
548 le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
549 &attr->credential,
550 attr->type,
551 attr->data,
552 attr->data_size);
553 le->attribute->flag = attr->flag;
554 le->attribute->id = attr->id;
555 GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
556 attr_list->list_tail,
557 le);
558 break;
559 }
560 GNUNET_free (attrs_tmp);
561 }
562 else if (attr_delete && (NULL == attr_to_delete))
563 {
564 label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
565 if (0 == strcasecmp (attr_delete, label))
566 {
567 attr_to_delete = GNUNET_RECLAIM_attribute_new (attr->name,
568 &attr->credential,
569 attr->type,
570 attr->data,
571 attr->data_size);
572 attr_to_delete->id = attr->id;
573 }
574 GNUNET_free (label);
575 }
576 else if (list)
577 {
578 attr_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
579 attr->data,
580 attr->data_size);
581 attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
582 id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
583 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->credential))
584 {
585 fprintf (stdout,
586 "%s: ``%s'' (%s); ID: %s\n",
587 attr->name,
588 attr_str,
589 attr_type,
590 id);
591 }
592 else
593 {
594 char *cred_id =
595 GNUNET_STRINGS_data_to_string_alloc (&attr->credential,
596 sizeof(attr->credential));
597 fprintf (stdout,
598 "%s: ``%s'' in credential presentation `%s' (%s); ID: %s\n",
599 attr->name,
600 attr_str,
601 cred_id,
602 attr_type,
603 id);
604 GNUNET_free (cred_id);
605
606 }
607 GNUNET_free (id);
608 }
609 GNUNET_RECLAIM_get_attributes_next (attr_iterator);
610}
611
612
613static void
614cred_iter_finished (void *cls)
615{
616 cred_iterator = NULL;
617
618 // Add new credential
619 if ((NULL != credential_name) &&
620 (NULL != attr_value))
621 {
622 enum GNUNET_RECLAIM_CredentialType ctype =
623 GNUNET_RECLAIM_credential_typename_to_number (credential_type);
624 struct GNUNET_RECLAIM_Credential *credential =
625 GNUNET_RECLAIM_credential_new (credential_name,
626 ctype,
627 attr_value,
628 strlen (attr_value));
629 reclaim_op = GNUNET_RECLAIM_credential_store (reclaim_handle,
630 pkey,
631 credential,
632 &exp_interval,
633 store_cont,
634 NULL);
635 return;
636
637 }
638 if (list_credentials)
639 {
640 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
641 return;
642 }
643 attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
644 pkey,
645 &iter_error,
646 NULL,
647 &iter_cb,
648 NULL,
649 &iter_finished,
650 NULL);
651
652}
653
654
655static void
656cred_iter_cb (void *cls,
657 const struct GNUNET_IDENTITY_PublicKey *identity,
658 const struct GNUNET_RECLAIM_Credential *cred)
659{
660 char *cred_str;
661 char *attr_str;
662 char *id;
663 const char *cred_type;
664 struct GNUNET_RECLAIM_AttributeListEntry *ale;
665
666 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&credential,
667 &cred->id))
668 credential_exists = GNUNET_YES;
669 if (list_credentials)
670 {
671 cred_str = GNUNET_RECLAIM_credential_value_to_string (cred->type,
672 cred->data,
673 cred->data_size);
674 cred_type = GNUNET_RECLAIM_credential_number_to_typename (cred->type);
675 id = GNUNET_STRINGS_data_to_string_alloc (&cred->id, sizeof(cred->id));
676 fprintf (stdout,
677 "%s: ``%s'' (%s); ID: %s\n",
678 cred->name,
679 cred_str,
680 cred_type,
681 id);
682 struct GNUNET_RECLAIM_AttributeList *attrs =
683 GNUNET_RECLAIM_credential_get_attributes (cred);
684 if (NULL != attrs)
685 {
686 fprintf (stdout,
687 "\t Attributes:\n");
688 for (ale = attrs->list_head; NULL != ale; ale = ale->next)
689 {
690 attr_str = GNUNET_RECLAIM_attribute_value_to_string (
691 ale->attribute->type,
692 ale->attribute->data,
693 ale->attribute->data_size);
694 fprintf (stdout,
695 "\t %s: %s\n", ale->attribute->name, attr_str);
696 GNUNET_free (attr_str);
697 }
698 GNUNET_RECLAIM_attribute_list_destroy (attrs);
699 }
700 GNUNET_free (id);
701 }
702 GNUNET_RECLAIM_get_credentials_next (cred_iterator);
703}
704
705
706static void
707start_process ()
708{
709 if (NULL == pkey)
710 {
711 fprintf (stderr, "Ego %s not found\n", ego_name);
712 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
713 return;
714 }
715 if (NULL == credential_type)
716 credential_type = GNUNET_strdup ("JWT");
717 credential = GNUNET_RECLAIM_ID_ZERO;
718 if (NULL != credential_id)
719 GNUNET_STRINGS_string_to_data (credential_id,
720 strlen (credential_id),
721 &credential, sizeof(credential));
722 credential_exists = GNUNET_NO;
723 if (list_tickets)
724 {
725 ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (reclaim_handle,
726 pkey,
727 &ticket_iter_err,
728 NULL,
729 &ticket_iter,
730 NULL,
731 &ticket_iter_fin,
732 NULL);
733 return;
734 }
735
736 if ((NULL != rp) &&
737 (GNUNET_OK !=
738 GNUNET_IDENTITY_public_key_from_string (rp, &rp_key)) )
739 {
740 fprintf (stderr, "%s is not a public key!\n", rp);
741 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
742 return;
743 }
744 if (NULL != consume_ticket)
745 GNUNET_STRINGS_string_to_data (consume_ticket,
746 strlen (consume_ticket),
747 &ticket,
748 sizeof(struct GNUNET_RECLAIM_Ticket));
749 if (NULL != revoke_ticket)
750 GNUNET_STRINGS_string_to_data (revoke_ticket,
751 strlen (revoke_ticket),
752 &ticket,
753 sizeof(struct GNUNET_RECLAIM_Ticket));
754
755 attr_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
756 claim = NULL;
757 cred_iterator = GNUNET_RECLAIM_get_credentials_start (reclaim_handle,
758 pkey,
759 &iter_error,
760 NULL,
761 &cred_iter_cb,
762 NULL,
763 &cred_iter_finished,
764 NULL);
765
766}
767
768
769static int init = GNUNET_YES;
770
771static void
772ego_cb (void *cls,
773 struct GNUNET_IDENTITY_Ego *ego,
774 void **ctx,
775 const char *name)
776{
777 if (NULL == name)
778 {
779 if (GNUNET_YES == init)
780 {
781 init = GNUNET_NO;
782 start_process ();
783 }
784 return;
785 }
786 if (0 != strcmp (name, ego_name))
787 return;
788 pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
789}
790
791
792static void
793run (void *cls,
794 char *const *args,
795 const char *cfgfile,
796 const struct GNUNET_CONFIGURATION_Handle *c)
797{
798 ret = 0;
799 if (NULL == ego_name)
800 {
801 ret = 1;
802 fprintf (stderr, _ ("Ego is required\n"));
803 return;
804 }
805
806 if ((NULL == attr_value) && (NULL != attr_name))
807 {
808 ret = 1;
809 fprintf (stderr, _ ("Attribute value missing!\n"));
810 return;
811 }
812
813 if ((NULL == rp) && (NULL != issue_attrs))
814 {
815 ret = 1;
816 fprintf (stderr, _ ("Requesting party key is required!\n"));
817 return;
818 }
819
820 reclaim_handle = GNUNET_RECLAIM_connect (c);
821 // Get Ego
822 identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
823}
824
825
826int
827main (int argc, char *const argv[])
828{
829 exp_interval = GNUNET_TIME_UNIT_HOURS;
830 struct GNUNET_GETOPT_CommandLineOption options[] = {
831 GNUNET_GETOPT_option_string ('a',
832 "add",
833 "NAME",
834 gettext_noop ("Add or update an attribute NAME"),
835 &attr_name),
836 GNUNET_GETOPT_option_string ('d',
837 "delete",
838 "ID",
839 gettext_noop ("Delete the attribute with ID"),
840 &attr_delete),
841 GNUNET_GETOPT_option_string ('V',
842 "value",
843 "VALUE",
844 gettext_noop ("The attribute VALUE"),
845 &attr_value),
846 GNUNET_GETOPT_option_string ('e',
847 "ego",
848 "EGO",
849 gettext_noop ("The EGO to use"),
850 &ego_name),
851 GNUNET_GETOPT_option_string ('r',
852 "rp",
853 "RP",
854 gettext_noop (
855 "Specify the relying party for issue"),
856 &rp),
857 GNUNET_GETOPT_option_flag ('D',
858 "dump",
859 gettext_noop ("List attributes for EGO"),
860 &list),
861 GNUNET_GETOPT_option_flag ('A',
862 "credentials",
863 gettext_noop ("List credentials for EGO"),
864 &list_credentials),
865 GNUNET_GETOPT_option_string ('I',
866 "credential-id",
867 "CREDENTIAL_ID",
868 gettext_noop (
869 "Credential to use for attribute"),
870 &credential_id),
871 GNUNET_GETOPT_option_string ('N',
872 "credential-name",
873 "NAME",
874 gettext_noop ("Credential name"),
875 &credential_name),
876 GNUNET_GETOPT_option_string ('i',
877 "issue",
878 "A1,A2,...",
879 gettext_noop (
880 "Issue a ticket for a set of attributes separated by comma"),
881 &issue_attrs),
882 GNUNET_GETOPT_option_string ('C',
883 "consume",
884 "TICKET",
885 gettext_noop ("Consume a ticket"),
886 &consume_ticket),
887 GNUNET_GETOPT_option_string ('R',
888 "revoke",
889 "TICKET",
890 gettext_noop ("Revoke a ticket"),
891 &revoke_ticket),
892 GNUNET_GETOPT_option_string ('t',
893 "type",
894 "TYPE",
895 gettext_noop ("Type of attribute"),
896 &type_str),
897 GNUNET_GETOPT_option_string ('u',
898 "credential-type",
899 "TYPE",
900 gettext_noop ("Type of credential"),
901 &credential_type),
902 GNUNET_GETOPT_option_flag ('T',
903 "tickets",
904 gettext_noop ("List tickets of ego"),
905 &list_tickets),
906 GNUNET_GETOPT_option_relative_time ('E',
907 "expiration",
908 "INTERVAL",
909 gettext_noop (
910 "Expiration interval of the attribute"),
911 &exp_interval),
912
913 GNUNET_GETOPT_OPTION_END
914 };
915 if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
916 argv,
917 "gnunet-reclaim",
918 _ ("re:claimID command line tool"),
919 options,
920 &run,
921 NULL))
922 return 1;
923 else
924 return ret;
925}
diff --git a/src/reclaim/gnunet-service-reclaim.c b/src/reclaim/gnunet-service-reclaim.c
deleted file mode 100644
index 84a98d1e4..000000000
--- a/src/reclaim/gnunet-service-reclaim.c
+++ /dev/null
@@ -1,2504 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @file src/reclaim/gnunet-service-reclaim.c
23 * @brief reclaim Service
24 *
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet-service-reclaim_tickets.h"
29#include "gnunet_constants.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_reclaim_lib.h"
33#include "gnunet_reclaim_service.h"
34#include "gnunet_signatures.h"
35#include "reclaim.h"
36
37
38/**
39 * Namestore handle
40 */
41static struct GNUNET_NAMESTORE_Handle *nsh;
42
43/**
44 * Timeout task
45 */
46static struct GNUNET_SCHEDULER_Task *timeout_task;
47
48/**
49 * Our configuration.
50 */
51static const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53/**
54 * An idp client
55 */
56struct IdpClient;
57
58/**
59 * A ticket iteration operation.
60 */
61struct TicketIteration
62{
63 /**
64 * DLL
65 */
66 struct TicketIteration *next;
67
68 /**
69 * DLL
70 */
71 struct TicketIteration *prev;
72
73 /**
74 * Client which intiated this zone iteration
75 */
76 struct IdpClient *client;
77
78 /**
79 * The operation id for the iteration in the response for the client
80 */
81 uint32_t r_id;
82
83 /**
84 * The ticket iterator
85 */
86 struct RECLAIM_TICKETS_Iterator *iter;
87};
88
89
90/**
91 * An attribute iteration operation.
92 */
93struct Iterator
94{
95 /**
96 * Next element in the DLL
97 */
98 struct Iterator *next;
99
100 /**
101 * Previous element in the DLL
102 */
103 struct Iterator *prev;
104
105 /**
106 * IDP client which intiated this zone iteration
107 */
108 struct IdpClient *client;
109
110 /**
111 * Key of the zone we are iterating over.
112 */
113 struct GNUNET_IDENTITY_PrivateKey identity;
114
115 /**
116 * Namestore iterator
117 */
118 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
119
120 /**
121 * The operation id for the zone iteration in the response for the client
122 */
123 uint32_t request_id;
124
125 /**
126 * Context
127 */
128 void *ctx;
129};
130
131
132/**
133 * An idp client
134 */
135struct IdpClient
136{
137 /**
138 * DLL
139 */
140 struct IdpClient *prev;
141
142 /**
143 * DLL
144 */
145 struct IdpClient *next;
146
147 /**
148 * The client
149 */
150 struct GNUNET_SERVICE_Client *client;
151
152 /**
153 * Message queue for transmission to @e client
154 */
155 struct GNUNET_MQ_Handle *mq;
156
157 /**
158 * Head of the DLL of
159 * Attribute iteration operations in
160 * progress initiated by this client
161 */
162 struct Iterator *attr_iter_head;
163
164 /**
165 * Tail of the DLL of
166 * Attribute iteration operations
167 * in progress initiated by this client
168 */
169 struct Iterator *attr_iter_tail;
170
171 /**
172 * Head of the DLL of
173 * Credential iteration operations in
174 * progress initiated by this client
175 */
176 struct Iterator *cred_iter_head;
177
178 /**
179 * Tail of the DLL of
180 * Credential iteration operations
181 * in progress initiated by this client
182 */
183 struct Iterator *cred_iter_tail;
184
185 /**
186 * Head of DLL of ticket iteration ops
187 */
188 struct TicketIteration *ticket_iter_head;
189
190 /**
191 * Tail of DLL of ticket iteration ops
192 */
193 struct TicketIteration *ticket_iter_tail;
194
195 /**
196 * Head of DLL of ticket revocation ops
197 */
198 struct TicketRevocationOperation *revoke_op_head;
199
200 /**
201 * Tail of DLL of ticket revocation ops
202 */
203 struct TicketRevocationOperation *revoke_op_tail;
204
205 /**
206 * Head of DLL of ticket issue ops
207 */
208 struct TicketIssueOperation *issue_op_head;
209
210 /**
211 * Tail of DLL of ticket issue ops
212 */
213 struct TicketIssueOperation *issue_op_tail;
214
215 /**
216 * Head of DLL of ticket consume ops
217 */
218 struct ConsumeTicketOperation *consume_op_head;
219
220 /**
221 * Tail of DLL of ticket consume ops
222 */
223 struct ConsumeTicketOperation *consume_op_tail;
224
225 /**
226 * Head of DLL of attribute store ops
227 */
228 struct AttributeStoreHandle *store_op_head;
229
230 /**
231 * Tail of DLL of attribute store ops
232 */
233 struct AttributeStoreHandle *store_op_tail;
234 /**
235 * Head of DLL of attribute delete ops
236 */
237 struct AttributeDeleteHandle *delete_op_head;
238
239 /**
240 * Tail of DLL of attribute delete ops
241 */
242 struct AttributeDeleteHandle *delete_op_tail;
243};
244
245
246/**
247 * Handle for attribute deletion request
248 */
249struct AttributeDeleteHandle
250{
251 /**
252 * DLL
253 */
254 struct AttributeDeleteHandle *next;
255
256 /**
257 * DLL
258 */
259 struct AttributeDeleteHandle *prev;
260
261 /**
262 * Client connection
263 */
264 struct IdpClient *client;
265
266 /**
267 * Identity
268 */
269 struct GNUNET_IDENTITY_PrivateKey identity;
270
271
272 /**
273 * QueueEntry
274 */
275 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
276
277 /**
278 * Iterator
279 */
280 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
281
282 /**
283 * The attribute to delete
284 */
285 struct GNUNET_RECLAIM_Attribute *claim;
286
287 /**
288 * The credential to delete
289 */
290 struct GNUNET_RECLAIM_Credential *credential;
291
292 /**
293 * Tickets to update
294 */
295 struct TicketRecordsEntry *tickets_to_update_head;
296
297 /**
298 * Tickets to update
299 */
300 struct TicketRecordsEntry *tickets_to_update_tail;
301
302 /**
303 * Existing attributes
304 */
305 struct GNUNET_RECLAIM_AttributeList *existing_attributes;
306
307 /**
308 * Existing credentials
309 */
310 struct GNUNET_RECLAIM_CredentialList *existing_credentials;
311
312 /**
313 * Attribute label
314 */
315 char *label;
316
317 /**
318 * request id
319 */
320 uint32_t r_id;
321};
322
323
324/**
325 * Handle for attribute store request
326 */
327struct AttributeStoreHandle
328{
329 /**
330 * DLL
331 */
332 struct AttributeStoreHandle *next;
333
334 /**
335 * DLL
336 */
337 struct AttributeStoreHandle *prev;
338
339 /**
340 * Client connection
341 */
342 struct IdpClient *client;
343
344 /**
345 * Identity
346 */
347 struct GNUNET_IDENTITY_PrivateKey identity;
348
349 /**
350 * Identity pubkey
351 */
352 struct GNUNET_IDENTITY_PublicKey identity_pkey;
353
354 /**
355 * QueueEntry
356 */
357 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
358
359 /**
360 * The attribute to store
361 */
362 struct GNUNET_RECLAIM_Attribute *claim;
363
364 /**
365 * The credential to store
366 */
367 struct GNUNET_RECLAIM_Credential *credential;
368
369 /**
370 * The attribute expiration interval
371 */
372 struct GNUNET_TIME_Relative exp;
373
374 /**
375 * request id
376 */
377 uint32_t r_id;
378};
379
380
381/**
382 * Handle for ticket consume request
383 */
384struct ConsumeTicketOperation
385{
386 /**
387 * DLL
388 */
389 struct ConsumeTicketOperation *next;
390
391 /**
392 * DLL
393 */
394 struct ConsumeTicketOperation *prev;
395
396 /**
397 * Client connection
398 */
399 struct IdpClient *client;
400
401 /**
402 * request id
403 */
404 uint32_t r_id;
405
406 /**
407 * Ticket consume handle
408 */
409 struct RECLAIM_TICKETS_ConsumeHandle *ch;
410};
411
412
413/**
414 * Ticket revocation request handle
415 */
416struct TicketRevocationOperation
417{
418 /**
419 * DLL
420 */
421 struct TicketRevocationOperation *prev;
422
423 /**
424 * DLL
425 */
426 struct TicketRevocationOperation *next;
427
428 /**
429 * Client connection
430 */
431 struct IdpClient *client;
432
433 /**
434 * Revocation handle
435 */
436 struct RECLAIM_TICKETS_RevokeHandle *rh;
437
438 /**
439 * request id
440 */
441 uint32_t r_id;
442};
443
444
445/**
446 * Ticket issue operation handle
447 */
448struct TicketIssueOperation
449{
450 /**
451 * DLL
452 */
453 struct TicketIssueOperation *prev;
454
455 /**
456 * DLL
457 */
458 struct TicketIssueOperation *next;
459
460 /**
461 * Client connection
462 */
463 struct IdpClient *client;
464
465 /**
466 * request id
467 */
468 uint32_t r_id;
469};
470
471
472/**
473 * Client list
474 */
475static struct IdpClient *client_list_head = NULL;
476
477/**
478 * Client list
479 */
480static struct IdpClient *client_list_tail = NULL;
481
482
483/**
484 * Cleanup attribute delete handle
485 *
486 * @param adh the attribute to cleanup
487 */
488static void
489cleanup_adh (struct AttributeDeleteHandle *adh)
490{
491 struct TicketRecordsEntry *le;
492
493 if (NULL != adh->ns_it)
494 GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
495 if (NULL != adh->ns_qe)
496 GNUNET_NAMESTORE_cancel (adh->ns_qe);
497 if (NULL != adh->label)
498 GNUNET_free (adh->label);
499 if (NULL != adh->claim)
500 GNUNET_free (adh->claim);
501 if (NULL != adh->credential)
502 GNUNET_free (adh->credential);
503 if (NULL != adh->existing_credentials)
504 GNUNET_RECLAIM_credential_list_destroy (adh->existing_credentials);
505 if (NULL != adh->existing_attributes)
506 GNUNET_RECLAIM_attribute_list_destroy (adh->existing_attributes);
507 while (NULL != (le = adh->tickets_to_update_head))
508 {
509 GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
510 adh->tickets_to_update_tail,
511 le);
512 if (NULL != le->label)
513 GNUNET_free (le->label);
514 if (NULL != le->data)
515 GNUNET_free (le->data);
516 GNUNET_free (le);
517 }
518 GNUNET_free (adh);
519}
520
521
522/**
523 * Cleanup attribute store handle
524 *
525 * @param handle handle to clean up
526 */
527static void
528cleanup_as_handle (struct AttributeStoreHandle *ash)
529{
530 if (NULL != ash->ns_qe)
531 GNUNET_NAMESTORE_cancel (ash->ns_qe);
532 if (NULL != ash->claim)
533 GNUNET_free (ash->claim);
534 if (NULL != ash->credential)
535 GNUNET_free (ash->credential);
536 GNUNET_free (ash);
537}
538
539
540/**
541 * Cleanup client
542 *
543 * @param idp the client to clean up
544 */
545static void
546cleanup_client (struct IdpClient *idp)
547{
548 struct Iterator *ai;
549 struct TicketIteration *ti;
550 struct TicketRevocationOperation *rop;
551 struct TicketIssueOperation *iss;
552 struct ConsumeTicketOperation *ct;
553 struct AttributeStoreHandle *as;
554 struct AttributeDeleteHandle *adh;
555
556 while (NULL != (iss = idp->issue_op_head))
557 {
558 GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
559 GNUNET_free (iss);
560 }
561 while (NULL != (ct = idp->consume_op_head))
562 {
563 GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
564 idp->consume_op_tail,
565 ct);
566 if (NULL != ct->ch)
567 RECLAIM_TICKETS_consume_cancel (ct->ch);
568 GNUNET_free (ct);
569 }
570 while (NULL != (as = idp->store_op_head))
571 {
572 GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
573 cleanup_as_handle (as);
574 }
575 while (NULL != (adh = idp->delete_op_head))
576 {
577 GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
578 cleanup_adh (adh);
579 }
580
581 while (NULL != (ai = idp->attr_iter_head))
582 {
583 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
584 GNUNET_free (ai);
585 }
586 while (NULL != (ai = idp->cred_iter_head))
587 {
588 GNUNET_CONTAINER_DLL_remove (idp->cred_iter_head, idp->cred_iter_tail,
589 ai);
590 GNUNET_free (ai);
591 }
592
593 while (NULL != (rop = idp->revoke_op_head))
594 {
595 GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
596 if (NULL != rop->rh)
597 RECLAIM_TICKETS_revoke_cancel (rop->rh);
598 GNUNET_free (rop);
599 }
600 while (NULL != (ti = idp->ticket_iter_head))
601 {
602 GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
603 idp->ticket_iter_tail,
604 ti);
605 if (NULL != ti->iter)
606 RECLAIM_TICKETS_iteration_stop (ti->iter);
607 GNUNET_free (ti);
608 }
609 GNUNET_free (idp);
610}
611
612
613/**
614 * Cleanup task
615 */
616static void
617cleanup ()
618{
619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
620
621 RECLAIM_TICKETS_deinit ();
622 if (NULL != timeout_task)
623 GNUNET_SCHEDULER_cancel (timeout_task);
624 if (NULL != nsh)
625 GNUNET_NAMESTORE_disconnect (nsh);
626}
627
628
629/**
630 * Shutdown task
631 *
632 * @param cls NULL
633 */
634static void
635do_shutdown (void *cls)
636{
637 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
638 cleanup ();
639}
640
641
642/**
643 * Sends a ticket result message to the client
644 *
645 * @param client the client to send to
646 * @param r_id the request message ID to reply to
647 * @param ticket the ticket to include (may be NULL)
648 * @param success the success status of the request
649 */
650static void
651send_ticket_result (const struct IdpClient *client,
652 uint32_t r_id,
653 const struct GNUNET_RECLAIM_Ticket *ticket,
654 const struct GNUNET_RECLAIM_PresentationList *presentations,
655 uint32_t success)
656{
657 struct TicketResultMessage *irm;
658 struct GNUNET_MQ_Envelope *env;
659 size_t pres_len = 0;
660
661 if (NULL != presentations)
662 {
663 pres_len =
664 GNUNET_RECLAIM_presentation_list_serialize_get_size (presentations);
665 }
666 env = GNUNET_MQ_msg_extra (irm,
667 pres_len,
668 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
669 if (NULL != ticket)
670 {
671 irm->ticket = *ticket;
672 }
673 // TODO add success member
674 irm->id = htonl (r_id);
675 irm->presentations_len = htons (pres_len);
676 if (NULL != presentations)
677 {
678 GNUNET_RECLAIM_presentation_list_serialize (presentations,
679 (char*) &irm[1]);
680 }
681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
682 GNUNET_MQ_send (client->mq, env);
683}
684
685
686/**
687 * Issue ticket result
688 *
689 * @param cls out ticket issue operation handle
690 * @param ticket the issued ticket
691 * @param presentations newly created credential presentations (NULL on error)
692 * @param success issue success status (GNUNET_OK if successful)
693 * @param emsg error message (NULL of success is GNUNET_OK)
694 */
695static void
696issue_ticket_result_cb (void *cls,
697 struct GNUNET_RECLAIM_Ticket *ticket,
698 struct GNUNET_RECLAIM_PresentationList *presentations,
699 int32_t success,
700 const char *emsg)
701{
702 struct TicketIssueOperation *tio = cls;
703
704 if (GNUNET_OK != success)
705 {
706 send_ticket_result (tio->client, tio->r_id, NULL, NULL, GNUNET_SYSERR);
707 GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
708 tio->client->issue_op_tail,
709 tio);
710 GNUNET_free (tio);
711 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
712 return;
713 }
714 send_ticket_result (tio->client, tio->r_id,
715 ticket, presentations, GNUNET_SYSERR);
716 GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
717 tio->client->issue_op_tail,
718 tio);
719 GNUNET_free (tio);
720}
721
722
723/**
724 * Check issue ticket message
725 *
726 * @cls unused
727 * @im message to check
728 * @return GNUNET_OK if message is ok
729 */
730static int
731check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
732{
733 uint16_t size;
734 size_t attrs_len;
735
736 size = ntohs (im->header.size);
737 attrs_len = ntohs (im->attr_len);
738
739 if (attrs_len > size - sizeof(struct IssueTicketMessage))
740 {
741 GNUNET_break (0);
742 return GNUNET_SYSERR;
743 }
744 return GNUNET_OK;
745}
746
747
748/**
749 * Handle ticket issue message
750 *
751 * @param cls our client
752 * @param im the message
753 */
754static void
755handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
756{
757 struct TicketIssueOperation *tio;
758 struct IdpClient *idp = cls;
759 struct GNUNET_RECLAIM_AttributeList *attrs;
760 struct GNUNET_RECLAIM_AttributeListEntry *le;
761 size_t attrs_len;
762
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
764 tio = GNUNET_new (struct TicketIssueOperation);
765 attrs_len = ntohs (im->attr_len);
766 attrs = GNUNET_RECLAIM_attribute_list_deserialize ((char *) &im[1],
767 attrs_len);
768 for (le = attrs->list_head; NULL != le; le = le->next)
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770 "List entry: %s\n", le->attribute->name);
771
772 tio->r_id = ntohl (im->id);
773 tio->client = idp;
774 GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
775 RECLAIM_TICKETS_issue (&im->identity,
776 attrs,
777 &im->rp,
778 &issue_ticket_result_cb,
779 tio);
780 GNUNET_SERVICE_client_continue (idp->client);
781 GNUNET_RECLAIM_attribute_list_destroy (attrs);
782}
783
784
785/**********************************************************
786* Revocation
787**********************************************************/
788
789/**
790 * Handles revocation result
791 *
792 * @param cls our revocation operation handle
793 * @param success revocation result (GNUNET_OK if successful)
794 */
795static void
796revoke_result_cb (void *cls, int32_t success)
797{
798 struct TicketRevocationOperation *rop = cls;
799 struct GNUNET_MQ_Envelope *env;
800 struct RevokeTicketResultMessage *trm;
801
802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
803 "Sending REVOKE_TICKET_RESULT message\n");
804 rop->rh = NULL;
805 env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
806 trm->id = htonl (rop->r_id);
807 trm->success = htonl (success);
808 GNUNET_MQ_send (rop->client->mq, env);
809 GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
810 rop->client->revoke_op_tail,
811 rop);
812 GNUNET_free (rop);
813}
814
815
816/**
817 * Check revocation message format
818 *
819 * @param cls unused
820 * @param im the message to check
821 * @return GNUNET_OK if message is ok
822 */
823static int
824check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
825{
826 uint16_t size;
827
828 size = ntohs (im->header.size);
829 if (size != sizeof(struct RevokeTicketMessage))
830 {
831 GNUNET_break (0);
832 return GNUNET_SYSERR;
833 }
834 return GNUNET_OK;
835}
836
837
838/**
839 * Handle a revocation message to a ticket.
840 *
841 * @param cls our client
842 * @param rm the message to handle
843 */
844static void
845handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
846{
847 struct TicketRevocationOperation *rop;
848 struct IdpClient *idp = cls;
849
850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
851 rop = GNUNET_new (struct TicketRevocationOperation);
852 rop->r_id = ntohl (rm->id);
853 rop->client = idp;
854 GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
855 rop->rh
856 = RECLAIM_TICKETS_revoke (&rm->ticket, &rm->identity, &revoke_result_cb,
857 rop);
858 GNUNET_SERVICE_client_continue (idp->client);
859}
860
861
862/**
863 * Handle a ticket consume result
864 *
865 * @param cls our consume ticket operation handle
866 * @param identity the attribute authority
867 * @param attrs the attribute/claim list
868 * @param success GNUNET_OK if successful
869 * @param emsg error message (NULL if success=GNUNET_OK)
870 */
871static void
872consume_result_cb (void *cls,
873 const struct GNUNET_IDENTITY_PublicKey *identity,
874 const struct GNUNET_RECLAIM_AttributeList *attrs,
875 const struct GNUNET_RECLAIM_PresentationList *presentations,
876 int32_t success,
877 const char *emsg)
878{
879 struct ConsumeTicketOperation *cop = cls;
880 struct ConsumeTicketResultMessage *crm;
881 struct GNUNET_MQ_Envelope *env;
882 char *data_tmp;
883 size_t attrs_len = 0;
884 size_t pres_len = 0;
885
886 if (GNUNET_OK != success)
887 {
888 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
889 }
890 attrs_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
891 pres_len = GNUNET_RECLAIM_presentation_list_serialize_get_size (
892 presentations);
893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
894 "Sending CONSUME_TICKET_RESULT message\n");
895 env = GNUNET_MQ_msg_extra (crm,
896 attrs_len + pres_len,
897 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
898 crm->id = htonl (cop->r_id);
899 crm->attrs_len = htons (attrs_len);
900 crm->presentations_len = htons (pres_len);
901 crm->identity = *identity;
902 crm->result = htonl (success);
903 data_tmp = (char *) &crm[1];
904 GNUNET_RECLAIM_attribute_list_serialize (attrs, data_tmp);
905 data_tmp += attrs_len;
906 GNUNET_RECLAIM_presentation_list_serialize (presentations, data_tmp);
907 GNUNET_MQ_send (cop->client->mq, env);
908 GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
909 cop->client->consume_op_tail,
910 cop);
911 GNUNET_free (cop);
912}
913
914
915/**
916 * Check a consume ticket message
917 *
918 * @param cls unused
919 * @param cm the message to handle
920 */
921static int
922check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
923{
924 uint16_t size;
925
926 size = ntohs (cm->header.size);
927 if (size != sizeof(struct ConsumeTicketMessage))
928 {
929 GNUNET_break (0);
930 return GNUNET_SYSERR;
931 }
932 return GNUNET_OK;
933}
934
935
936/**
937 * Handle a consume ticket message
938 *
939 * @param cls our client handle
940 * @cm the message to handle
941 */
942static void
943handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
944{
945 struct ConsumeTicketOperation *cop;
946 struct IdpClient *idp = cls;
947
948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
949 cop = GNUNET_new (struct ConsumeTicketOperation);
950 cop->r_id = ntohl (cm->id);
951 cop->client = idp;
952 cop->ch
953 = RECLAIM_TICKETS_consume (&cm->identity, &cm->ticket, &consume_result_cb,
954 cop);
955 GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
956 GNUNET_SERVICE_client_continue (idp->client);
957}
958
959
960/*****************************************
961* Attribute store
962*****************************************/
963
964
965/**
966 * Attribute store result handler
967 *
968 * @param cls our attribute store handle
969 * @param success GNUNET_OK if successful
970 * @param emsg error message (NULL if success=GNUNET_OK)
971 */
972static void
973attr_store_cont (void *cls, int32_t success, const char *emsg)
974{
975 struct AttributeStoreHandle *ash = cls;
976 struct GNUNET_MQ_Envelope *env;
977 struct SuccessResultMessage *acr_msg;
978
979 ash->ns_qe = NULL;
980 GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
981 ash->client->store_op_tail,
982 ash);
983
984 if (GNUNET_SYSERR == success)
985 {
986 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
987 "Failed to store attribute %s\n",
988 emsg);
989 cleanup_as_handle (ash);
990 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
991 return;
992 }
993
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
995 env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
996 acr_msg->id = htonl (ash->r_id);
997 acr_msg->op_result = htonl (GNUNET_OK);
998 GNUNET_MQ_send (ash->client->mq, env);
999 cleanup_as_handle (ash);
1000}
1001
1002
1003/**
1004 * Add a new attribute
1005 *
1006 * @param cls the AttributeStoreHandle
1007 */
1008static void
1009attr_store_task (void *cls)
1010{
1011 struct AttributeStoreHandle *ash = cls;
1012 struct GNUNET_GNSRECORD_Data rd[1];
1013 char *buf;
1014 char *label;
1015 size_t buf_size;
1016
1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
1018 buf_size = GNUNET_RECLAIM_attribute_serialize_get_size (ash->claim);
1019 buf = GNUNET_malloc (buf_size);
1020 // Give the ash a new id if unset
1021 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->claim->id))
1022 GNUNET_RECLAIM_id_generate (&ash->claim->id);
1023 GNUNET_RECLAIM_attribute_serialize (ash->claim, buf);
1024 label
1025 = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id,
1026 sizeof (ash->claim->id));
1027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1028
1029 rd[0].data_size = buf_size;
1030 rd[0].data = buf;
1031 rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE;
1032 rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1033 rd[0].expiration_time = ash->exp.rel_value_us;
1034 ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1035 &ash->identity,
1036 label,
1037 1,
1038 rd,
1039 &attr_store_cont,
1040 ash);
1041 GNUNET_free (buf);
1042 GNUNET_free (label);
1043}
1044
1045
1046/**
1047 * Check an attribute store message
1048 *
1049 * @param cls unused
1050 * @param sam the message to check
1051 */
1052static int
1053check_attribute_store_message (void *cls,
1054 const struct AttributeStoreMessage *sam)
1055{
1056 uint16_t size;
1057
1058 size = ntohs (sam->header.size);
1059 if (size <= sizeof(struct AttributeStoreMessage))
1060 {
1061 GNUNET_break (0);
1062 return GNUNET_SYSERR;
1063 }
1064 return GNUNET_OK;
1065}
1066
1067
1068/**
1069 * Handle an attribute store message
1070 *
1071 * @param cls our client
1072 * @param sam the message to handle
1073 */
1074static void
1075handle_attribute_store_message (void *cls,
1076 const struct AttributeStoreMessage *sam)
1077{
1078 struct AttributeStoreHandle *ash;
1079 struct IdpClient *idp = cls;
1080 size_t data_len;
1081
1082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
1083
1084 data_len = ntohs (sam->attr_len);
1085
1086 ash = GNUNET_new (struct AttributeStoreHandle);
1087 GNUNET_RECLAIM_attribute_deserialize ((char *) &sam[1],
1088 data_len,
1089 &ash->claim);
1090
1091 ash->r_id = ntohl (sam->id);
1092 ash->identity = sam->identity;
1093 ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1094 GNUNET_IDENTITY_key_get_public (&sam->identity, &ash->identity_pkey);
1095
1096 GNUNET_SERVICE_client_continue (idp->client);
1097 ash->client = idp;
1098 GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1099 GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
1100}
1101
1102
1103/**
1104 * Credential store result handler
1105 *
1106 * @param cls our attribute store handle
1107 * @param success GNUNET_OK if successful
1108 * @param emsg error message (NULL if success=GNUNET_OK)
1109 */
1110static void
1111cred_store_cont (void *cls, int32_t success, const char *emsg)
1112{
1113 struct AttributeStoreHandle *ash = cls;
1114 struct GNUNET_MQ_Envelope *env;
1115 struct SuccessResultMessage *acr_msg;
1116
1117 ash->ns_qe = NULL;
1118 GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1119 ash->client->store_op_tail,
1120 ash);
1121
1122 if (GNUNET_SYSERR == success)
1123 {
1124 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1125 "Failed to store credential: %s\n",
1126 emsg);
1127 cleanup_as_handle (ash);
1128 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1129 return;
1130 }
1131
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1133 env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1134 acr_msg->id = htonl (ash->r_id);
1135 acr_msg->op_result = htonl (GNUNET_OK);
1136 GNUNET_MQ_send (ash->client->mq, env);
1137 cleanup_as_handle (ash);
1138}
1139
1140
1141/**
1142 * Error looking up potential credential. Abort.
1143 *
1144 * @param cls our attribute store handle
1145 */
1146static void
1147cred_error (void *cls)
1148{
1149 struct AttributeStoreHandle *ash = cls;
1150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1151 "Failed to check for existing credential.\n");
1152 cleanup_as_handle (ash);
1153 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1154 return;
1155}
1156
1157
1158/**
1159* Check for existing record before storing credential
1160*
1161* @param cls our attribute store handle
1162* @param zone zone we are iterating
1163* @param label label of the records
1164* @param rd_count record count
1165* @param rd records
1166*/
1167static void
1168cred_add_cb (void *cls,
1169 const struct GNUNET_IDENTITY_PrivateKey *zone,
1170 const char *label,
1171 unsigned int rd_count,
1172 const struct GNUNET_GNSRECORD_Data *rd)
1173{
1174 struct AttributeStoreHandle *ash = cls;
1175 struct GNUNET_GNSRECORD_Data rd_new[1];
1176 char *buf;
1177 size_t buf_size;
1178
1179 buf_size = GNUNET_RECLAIM_credential_serialize_get_size (ash->credential);
1180 buf = GNUNET_malloc (buf_size);
1181 GNUNET_RECLAIM_credential_serialize (ash->credential, buf);
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 "Storing new credential under `%s'.\n",
1184 label);
1185 rd_new[0].data_size = buf_size;
1186 rd_new[0].data = buf;
1187 rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL;
1188 rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1189 rd_new[0].expiration_time = ash->exp.rel_value_us;
1190 ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1191 &ash->identity,
1192 label,
1193 1,
1194 rd_new,
1195 &cred_store_cont,
1196 ash);
1197 GNUNET_free (buf);
1198 return;
1199}
1200
1201
1202/**
1203 * Add a new credential
1204 *
1205 * @param cls the AttributeStoreHandle
1206 */
1207static void
1208cred_store_task (void *cls)
1209{
1210 struct AttributeStoreHandle *ash = cls;
1211 char *label;
1212
1213 // Give the ash a new id if unset
1214 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->credential->id))
1215 GNUNET_RECLAIM_id_generate (&ash->credential->id);
1216 label = GNUNET_STRINGS_data_to_string_alloc (&ash->credential->id,
1217 sizeof (ash->credential->id));
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Looking up existing data under label `%s'\n", label);
1220 ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
1221 &ash->identity,
1222 label,
1223 &cred_error,
1224 ash,
1225 &cred_add_cb,
1226 ash);
1227 GNUNET_free (label);
1228}
1229
1230
1231/**
1232 * Check an credential store message
1233 *
1234 * @param cls unused
1235 * @param sam the message to check
1236 */
1237static int
1238check_credential_store_message (void *cls,
1239 const struct AttributeStoreMessage *sam)
1240{
1241 uint16_t size;
1242
1243 size = ntohs (sam->header.size);
1244 if (size <= sizeof(struct AttributeStoreMessage))
1245 {
1246 GNUNET_break (0);
1247 return GNUNET_SYSERR;
1248 }
1249 return GNUNET_OK;
1250}
1251
1252
1253/**
1254* Handle a credential store message
1255*
1256* @param cls our client
1257* @param sam the message to handle
1258*/
1259static void
1260handle_credential_store_message (void *cls,
1261 const struct AttributeStoreMessage *sam)
1262{
1263 struct AttributeStoreHandle *ash;
1264 struct IdpClient *idp = cls;
1265 size_t data_len;
1266
1267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CREDENTIAL_STORE message\n");
1268
1269 data_len = ntohs (sam->attr_len);
1270
1271 ash = GNUNET_new (struct AttributeStoreHandle);
1272 ash->credential = GNUNET_RECLAIM_credential_deserialize ((char *) &sam[1],
1273 data_len);
1274
1275 ash->r_id = ntohl (sam->id);
1276 ash->identity = sam->identity;
1277 ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1278 GNUNET_IDENTITY_key_get_public (&sam->identity, &ash->identity_pkey);
1279
1280 GNUNET_SERVICE_client_continue (idp->client);
1281 ash->client = idp;
1282 GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1283 GNUNET_SCHEDULER_add_now (&cred_store_task, ash);
1284}
1285
1286
1287/**
1288 * Send a deletion success response
1289 *
1290 * @param adh our attribute deletion handle
1291 * @param success the success status
1292 */
1293static void
1294send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
1295{
1296 struct GNUNET_MQ_Envelope *env;
1297 struct SuccessResultMessage *acr_msg;
1298
1299 GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
1300 adh->client->delete_op_tail,
1301 adh);
1302
1303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1304 env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1305 acr_msg->id = htonl (adh->r_id);
1306 acr_msg->op_result = htonl (success);
1307 GNUNET_MQ_send (adh->client->mq, env);
1308}
1309
1310
1311/**
1312 * Namestore iteration within attribute deletion.
1313 * We need to reissue tickets with the deleted attribute removed.
1314 *
1315 * @param cls our attribute deletion handle
1316 * @param zone the private key of the ticket issuer
1317 * @param label the label of the record
1318 * @param rd_count number of records
1319 * @param rd record data
1320 */
1321static void
1322consistency_iter (void *cls,
1323 const struct GNUNET_IDENTITY_PrivateKey *zone,
1324 const char *label,
1325 unsigned int rd_count,
1326 const struct GNUNET_GNSRECORD_Data *rd)
1327{
1328 struct AttributeDeleteHandle *adh = cls;
1329 struct TicketRecordsEntry *le;
1330 struct GNUNET_RECLAIM_AttributeListEntry *ale;
1331 struct GNUNET_RECLAIM_CredentialListEntry *cle;
1332 int is_ticket = GNUNET_NO;
1333 for (int i = 0; i < rd_count; i++)
1334 {
1335 switch (rd[i].record_type)
1336 {
1337 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE:
1338 ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1339 GNUNET_RECLAIM_attribute_deserialize (rd[i].data,
1340 rd[i].data_size,
1341 &ale->attribute);
1342 GNUNET_CONTAINER_DLL_insert (adh->existing_attributes->list_head,
1343 adh->existing_attributes->list_tail,
1344 ale);
1345 break;
1346 case GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL:
1347 cle = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry);
1348 cle->credential = GNUNET_RECLAIM_credential_deserialize (rd[i].data,
1349 rd[i].data_size);
1350 GNUNET_CONTAINER_DLL_insert (adh->existing_credentials->list_head,
1351 adh->existing_credentials->list_tail,
1352 cle);
1353 break;
1354 case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET:
1355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1356 "Ticket to delete found (%s)\n",
1357 label);
1358 is_ticket = GNUNET_YES;
1359 break;
1360 default:
1361 break;
1362 }
1363 if (GNUNET_YES == is_ticket)
1364 break;
1365 }
1366 if (GNUNET_YES == is_ticket)
1367 {
1368 le = GNUNET_new (struct TicketRecordsEntry);
1369 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1370 le->data = GNUNET_malloc (le->data_size);
1371 le->rd_count = rd_count;
1372 le->label = GNUNET_strdup (label);
1373 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
1374 GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
1375 adh->tickets_to_update_tail,
1376 le);
1377 }
1378 GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
1379}
1380
1381
1382/**
1383 * Recursion prototype for function
1384 * @param cls our deletion handle
1385 */
1386static void
1387update_tickets (void *cls);
1388
1389
1390/**
1391 * Callback called when a ticket was updated
1392 *
1393 * @param cls our attribute deletion handle
1394 * @param success GNUNET_OK if successful
1395 * @param emsg error message (NULL if success=GNUNET_OK)
1396 */
1397static void
1398ticket_updated (void *cls, int32_t success, const char *emsg)
1399{
1400 struct AttributeDeleteHandle *adh = cls;
1401
1402 adh->ns_qe = NULL;
1403 GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1404}
1405
1406
1407/**
1408 * Update tickets: Remove shared attribute which has just been deleted.
1409 * This method is called recursively until all tickets are processed.
1410 * Eventually, the updated tickets are stored using ``update_tickets''.
1411 *
1412 * @param cls our attribute deletion handle
1413 */
1414static void
1415update_tickets (void *cls)
1416{
1417 struct AttributeDeleteHandle *adh = cls;
1418 struct TicketRecordsEntry *le;
1419
1420 if (NULL == adh->tickets_to_update_head)
1421 {
1422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1423 "Finished updating tickets, success\n");
1424 send_delete_response (adh, GNUNET_OK);
1425 cleanup_adh (adh);
1426 return;
1427 }
1428 le = adh->tickets_to_update_head;
1429 GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
1430 adh->tickets_to_update_tail,
1431 le);
1432 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
1433 struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
1434 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
1435 le->data,
1436 le->rd_count,
1437 rd))
1438 {
1439 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1440 "Unable to deserialize record data!\n");
1441 send_delete_response (adh, GNUNET_SYSERR);
1442 cleanup_adh (adh);
1443 return;
1444 }
1445 int j = 0;
1446 int i = 0;
1447 struct GNUNET_RECLAIM_AttributeListEntry *ale;
1448 struct GNUNET_RECLAIM_CredentialListEntry *cle;
1449 struct GNUNET_RECLAIM_Presentation *presentation;
1450 for (i = 0; i < le->rd_count; i++)
1451 {
1452 switch (rd[i].record_type)
1453 {
1454 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF:
1455 for (ale = adh->existing_attributes->list_head; NULL != ale; ale =
1456 ale->next)
1457 {
1458 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1459 &ale->attribute->id))
1460 {
1461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1462 "Found attribute %s, readding...\n",
1463 ale->attribute->name);
1464 rd_new[j] = rd[i];
1465 j++;
1466 break; // Found and added
1467 }
1468 }
1469 break;
1470 case GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION:
1471 presentation = GNUNET_RECLAIM_presentation_deserialize (rd[i].data,
1472 rd[i].data_size);
1473 for (cle = adh->existing_credentials->list_head; NULL != cle; cle =
1474 cle->next)
1475 {
1476 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (
1477 &presentation->credential_id,
1478 &cle->credential->id))
1479 {
1480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1481 "Found presentation for credential %s, readding...\n",
1482 cle->credential->name);
1483 rd_new[j] = rd[i];
1484 j++;
1485 break; // Found and added
1486 }
1487 }
1488 GNUNET_free (presentation);
1489 break;
1490 case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET:
1491 rd_new[j] = rd[i];
1492 j++;
1493 break; // Found and added
1494 default:
1495 GNUNET_break (0);
1496 }
1497 }
1498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1499 "Updating ticket with %d entries (%d before)...\n",
1500 j, i);
1501 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1502 &adh->identity,
1503 le->label,
1504 j,
1505 rd_new,
1506 &ticket_updated,
1507 adh);
1508 GNUNET_free (le->label);
1509 GNUNET_free (le->data);
1510 GNUNET_free (le);
1511}
1512
1513
1514/**
1515 * Delete all attributes which reference credentials
1516 * that no longer exist
1517 */
1518static void
1519purge_attributes (void *cls);;
1520
1521static void
1522offending_attr_delete_cont (void *cls, int32_t success, const char *emsg)
1523{
1524 struct AttributeDeleteHandle *adh = cls;
1525
1526 adh->ns_qe = NULL;
1527 if (GNUNET_SYSERR == success)
1528 {
1529 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1530 "Error deleting attribute %s\n",
1531 adh->label);
1532 send_delete_response (adh, GNUNET_SYSERR);
1533 cleanup_adh (adh);
1534 return;
1535 }
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Continuing consistency check...\n");
1537 GNUNET_SCHEDULER_add_now (&purge_attributes, adh);
1538}
1539
1540
1541/**
1542 * Delete all attributes which reference credentials
1543 * that no longer exist
1544 */
1545static void
1546purge_attributes (void *cls)
1547{
1548 struct AttributeDeleteHandle *adh = cls;
1549 struct GNUNET_RECLAIM_AttributeListEntry *ale;
1550 struct GNUNET_RECLAIM_CredentialListEntry *cle;
1551
1552 for (ale = adh->existing_attributes->list_head; NULL != ale; ale = ale->next)
1553 {
1554 if (GNUNET_YES ==
1555 GNUNET_RECLAIM_id_is_zero (&ale->attribute->credential))
1556 continue;
1557
1558 for (cle = adh->existing_credentials->list_head;
1559 NULL != cle; cle = cle->next)
1560 {
1561 if (GNUNET_YES !=
1562 GNUNET_RECLAIM_id_is_equal (&cle->credential->id,
1563 &ale->attribute->credential))
1564 continue;
1565 break;
1566 }
1567 if (NULL == cle)
1568 {
1569 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1570 "Found attribute with missing credential\n");
1571 break;
1572 }
1573 }
1574 if (NULL == ale)
1575 {
1576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1577 "Attributes consistent, updating tickets.\n");
1578 GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1579 return;
1580 }
1581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1582 "Attributes inconsistent, deleting offending attribute.\n");
1583 char *label
1584 = GNUNET_STRINGS_data_to_string_alloc (&ale->attribute->id,
1585 sizeof(ale->attribute->id));
1586
1587 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1588 &adh->identity,
1589 label,
1590 0,
1591 NULL,
1592 &offending_attr_delete_cont,
1593 adh);
1594 GNUNET_CONTAINER_DLL_remove (adh->existing_attributes->list_head,
1595 adh->existing_attributes->list_tail,
1596 ale);
1597 GNUNET_free (ale);
1598 GNUNET_free (label);
1599}
1600
1601
1602/**
1603 * Done collecting affected tickets, start updating.
1604 *
1605 * @param cls our attribute deletion handle
1606 */
1607static void
1608consistency_iter_fin (void *cls)
1609{
1610 struct AttributeDeleteHandle *adh = cls;
1611 adh->ns_it = NULL;
1612 GNUNET_SCHEDULER_add_now (&purge_attributes, adh);
1613}
1614
1615
1616/**
1617 * Error collecting affected tickets. Abort.
1618 *
1619 * @param cls our attribute deletion handle
1620 */
1621static void
1622consistency_iter_err (void *cls)
1623{
1624 struct AttributeDeleteHandle *adh = cls;
1625
1626 adh->ns_it = NULL;
1627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1628 "Namestore error on consistency check\n");
1629 send_delete_response (adh, GNUNET_SYSERR);
1630 cleanup_adh (adh);
1631}
1632
1633
1634/**
1635 * Start processing tickets which may still contain reference to deleted
1636 * attribute.
1637 *
1638 * @param cls attribute deletion handle
1639 */
1640static void
1641start_consistency_update (void *cls)
1642{
1643 struct AttributeDeleteHandle *adh = cls;
1644
1645 adh->existing_attributes = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1646 adh->existing_credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
1647
1648 adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1649 &adh->identity,
1650 &consistency_iter_err,
1651 adh,
1652 &consistency_iter,
1653 adh,
1654 &consistency_iter_fin,
1655 adh);
1656}
1657
1658
1659/**
1660 * Attribute deleted callback
1661 *
1662 * @param cls our handle
1663 * @param success success status
1664 * @param emsg error message (NULL if success=GNUNET_OK)
1665 */
1666static void
1667attr_delete_cont (void *cls, int32_t success, const char *emsg)
1668{
1669 struct AttributeDeleteHandle *adh = cls;
1670
1671 adh->ns_qe = NULL;
1672 if (GNUNET_SYSERR == success)
1673 {
1674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1675 "Error deleting attribute %s\n",
1676 adh->label);
1677 send_delete_response (adh, GNUNET_SYSERR);
1678 cleanup_adh (adh);
1679 return;
1680 }
1681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1682 GNUNET_SCHEDULER_add_now (&start_consistency_update, adh);
1683}
1684
1685
1686/**
1687 * Check attribute delete message format
1688 *
1689 * @cls unused
1690 * @dam message to check
1691 */
1692static int
1693check_attribute_delete_message (void *cls,
1694 const struct AttributeDeleteMessage *dam)
1695{
1696 uint16_t size;
1697
1698 size = ntohs (dam->header.size);
1699 if (size <= sizeof(struct AttributeDeleteMessage))
1700 {
1701 GNUNET_break (0);
1702 return GNUNET_SYSERR;
1703 }
1704 return GNUNET_OK;
1705}
1706
1707
1708/**
1709 * Handle attribute deletion
1710 *
1711 * @param cls our client
1712 * @param dam deletion message
1713 */
1714static void
1715handle_attribute_delete_message (void *cls,
1716 const struct AttributeDeleteMessage *dam)
1717{
1718 struct AttributeDeleteHandle *adh;
1719 struct IdpClient *idp = cls;
1720 size_t data_len;
1721
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
1723
1724 data_len = ntohs (dam->attr_len);
1725
1726 adh = GNUNET_new (struct AttributeDeleteHandle);
1727 GNUNET_RECLAIM_attribute_deserialize ((char *) &dam[1],
1728 data_len,
1729 &adh->claim);
1730 adh->credential = NULL;
1731
1732 adh->r_id = ntohl (dam->id);
1733 adh->identity = dam->identity;
1734 adh->label
1735 = GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id,
1736 sizeof(adh->claim->id));
1737 GNUNET_SERVICE_client_continue (idp->client);
1738 adh->client = idp;
1739 GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1740 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1741 &adh->identity,
1742 adh->label,
1743 0,
1744 NULL,
1745 &attr_delete_cont,
1746 adh);
1747}
1748
1749
1750/**
1751 * Credential deleted callback
1752 *
1753 * @param cls our handle
1754 * @param success success status
1755 * @param emsg error message (NULL if success=GNUNET_OK)
1756 */
1757static void
1758cred_delete_cont (void *cls, int32_t success, const char *emsg)
1759{
1760 struct AttributeDeleteHandle *adh = cls;
1761
1762 adh->ns_qe = NULL;
1763 if (GNUNET_SYSERR == success)
1764 {
1765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1766 "Error deleting credential `%s'\n",
1767 adh->label);
1768 send_delete_response (adh, GNUNET_SYSERR);
1769 cleanup_adh (adh);
1770 return;
1771 }
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1773 GNUNET_SCHEDULER_add_now (&start_consistency_update, adh);
1774}
1775
1776
1777/**
1778 * Check credential delete message format
1779 *
1780 * @cls unused
1781 * @dam message to check
1782 */
1783static int
1784check_credential_delete_message (void *cls,
1785 const struct AttributeDeleteMessage *dam)
1786{
1787 uint16_t size;
1788
1789 size = ntohs (dam->header.size);
1790 if (size <= sizeof(struct AttributeDeleteMessage))
1791 {
1792 GNUNET_break (0);
1793 return GNUNET_SYSERR;
1794 }
1795 return GNUNET_OK;
1796}
1797
1798
1799/**
1800 * Handle credential deletion
1801 *
1802 * @param cls our client
1803 * @param dam deletion message
1804 */
1805static void
1806handle_credential_delete_message (void *cls,
1807 const struct AttributeDeleteMessage *dam)
1808{
1809 struct AttributeDeleteHandle *adh;
1810 struct IdpClient *idp = cls;
1811 size_t data_len;
1812
1813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CREDENTIAL_DELETE message\n");
1814
1815 data_len = ntohs (dam->attr_len);
1816
1817 adh = GNUNET_new (struct AttributeDeleteHandle);
1818 adh->credential = GNUNET_RECLAIM_credential_deserialize ((char *) &dam[1],
1819 data_len);
1820 adh->claim = NULL;
1821
1822 adh->r_id = ntohl (dam->id);
1823 adh->identity = dam->identity;
1824 adh->label
1825 = GNUNET_STRINGS_data_to_string_alloc (&adh->credential->id,
1826 sizeof(adh->credential->id));
1827 GNUNET_SERVICE_client_continue (idp->client);
1828 adh->client = idp;
1829 GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1830 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1831 &adh->identity,
1832 adh->label,
1833 0,
1834 NULL,
1835 &cred_delete_cont,
1836 adh);
1837}
1838
1839
1840/*************************************************
1841 * Attribute iteration
1842 *************************************************/
1843
1844
1845/**
1846 * Done iterating over attributes
1847 *
1848 * @param cls our iterator handle
1849 */
1850static void
1851attr_iter_finished (void *cls)
1852{
1853 struct Iterator *ai = cls;
1854 struct GNUNET_MQ_Envelope *env;
1855 struct AttributeResultMessage *arm;
1856
1857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1858 env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1859 arm->id = htonl (ai->request_id);
1860 arm->attr_len = htons (0);
1861 GNUNET_MQ_send (ai->client->mq, env);
1862 GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1863 ai->client->attr_iter_tail,
1864 ai);
1865 GNUNET_free (ai);
1866}
1867
1868
1869/**
1870 * Error iterating over attributes. Abort.
1871 *
1872 * @param cls our attribute iteration handle
1873 */
1874static void
1875attr_iter_error (void *cls)
1876{
1877 struct Iterator *ai = cls;
1878
1879 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1880 attr_iter_finished (ai);
1881}
1882
1883
1884/**
1885 * Got record. Return if it is an attribute.
1886 *
1887 * @param cls our attribute iterator
1888 * @param zone zone we are iterating
1889 * @param label label of the records
1890 * @param rd_count record count
1891 * @param rd records
1892 */
1893static void
1894attr_iter_cb (void *cls,
1895 const struct GNUNET_IDENTITY_PrivateKey *zone,
1896 const char *label,
1897 unsigned int rd_count,
1898 const struct GNUNET_GNSRECORD_Data *rd)
1899{
1900 struct Iterator *ai = cls;
1901 struct GNUNET_MQ_Envelope *env;
1902 char *data_tmp;
1903
1904 if ((rd_count != 1) ||
1905 (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE != rd->record_type))
1906 {
1907 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1908 return;
1909 }
1910 struct AttributeResultMessage *arm;
1911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n",
1912 label);
1913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1914 "Sending ATTRIBUTE_RESULT message\n");
1915 env = GNUNET_MQ_msg_extra (arm,
1916 rd->data_size,
1917 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1918 arm->id = htonl (ai->request_id);
1919 arm->attr_len = htons (rd->data_size);
1920 GNUNET_IDENTITY_key_get_public (zone, &arm->identity);
1921 data_tmp = (char *) &arm[1];
1922 GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1923 GNUNET_MQ_send (ai->client->mq, env);
1924}
1925
1926
1927/**
1928 * Iterate over zone to get attributes
1929 *
1930 * @param cls our client
1931 * @param ais_msg the iteration message to start
1932 */
1933static void
1934handle_iteration_start (void *cls,
1935 const struct AttributeIterationStartMessage *ais_msg)
1936{
1937 struct IdpClient *idp = cls;
1938 struct Iterator *ai;
1939
1940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1941 "Received ATTRIBUTE_ITERATION_START message\n");
1942 ai = GNUNET_new (struct Iterator);
1943 ai->request_id = ntohl (ais_msg->id);
1944 ai->client = idp;
1945 ai->identity = ais_msg->identity;
1946
1947 GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1948 ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1949 &ai->identity,
1950 &attr_iter_error,
1951 ai,
1952 &attr_iter_cb,
1953 ai,
1954 &attr_iter_finished,
1955 ai);
1956 GNUNET_SERVICE_client_continue (idp->client);
1957}
1958
1959
1960/**
1961 * Handle iteration stop message from client
1962 *
1963 * @param cls the client
1964 * @param ais_msg the stop message
1965 */
1966static void
1967handle_iteration_stop (void *cls,
1968 const struct AttributeIterationStopMessage *ais_msg)
1969{
1970 struct IdpClient *idp = cls;
1971 struct Iterator *ai;
1972 uint32_t rid;
1973
1974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1975 "Received `%s' message\n",
1976 "ATTRIBUTE_ITERATION_STOP");
1977 rid = ntohl (ais_msg->id);
1978 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1979 if (ai->request_id == rid)
1980 break;
1981 if (NULL == ai)
1982 {
1983 GNUNET_break (0);
1984 GNUNET_SERVICE_client_drop (idp->client);
1985 return;
1986 }
1987 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1988 GNUNET_free (ai);
1989 GNUNET_SERVICE_client_continue (idp->client);
1990}
1991
1992
1993/**
1994 * Client requests next attribute from iterator
1995 *
1996 * @param cls the client
1997 * @param ais_msg the message
1998 */
1999static void
2000handle_iteration_next (void *cls,
2001 const struct AttributeIterationNextMessage *ais_msg)
2002{
2003 struct IdpClient *idp = cls;
2004 struct Iterator *ai;
2005 uint32_t rid;
2006
2007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2008 "Received ATTRIBUTE_ITERATION_NEXT message\n");
2009 rid = ntohl (ais_msg->id);
2010 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
2011 if (ai->request_id == rid)
2012 break;
2013 if (NULL == ai)
2014 {
2015 GNUNET_break (0);
2016 GNUNET_SERVICE_client_drop (idp->client);
2017 return;
2018 }
2019 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2020 GNUNET_SERVICE_client_continue (idp->client);
2021}
2022
2023
2024/*************************************************
2025 * Credential iteration
2026 *************************************************/
2027
2028
2029/**
2030 * Done iterating over credentials
2031 *
2032 * @param cls our iterator handle
2033 */
2034static void
2035cred_iter_finished (void *cls)
2036{
2037 struct Iterator *ai = cls;
2038 struct GNUNET_MQ_Envelope *env;
2039 struct CredentialResultMessage *arm;
2040
2041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending CREDENTIAL_RESULT message\n");
2042 env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_RESULT);
2043 arm->id = htonl (ai->request_id);
2044 arm->credential_len = htons (0);
2045 GNUNET_MQ_send (ai->client->mq, env);
2046 GNUNET_CONTAINER_DLL_remove (ai->client->cred_iter_head,
2047 ai->client->cred_iter_tail,
2048 ai);
2049 GNUNET_free (ai);
2050}
2051
2052
2053/**
2054 * Error iterating over credentials. Abort.
2055 *
2056 * @param cls our attribute iteration handle
2057 */
2058static void
2059cred_iter_error (void *cls)
2060{
2061 struct Iterator *ai = cls;
2062
2063 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over credentials\n");
2064 cred_iter_finished (ai);
2065}
2066
2067
2068/**
2069 * Got record. Return credential.
2070 *
2071 * @param cls our attribute iterator
2072 * @param zone zone we are iterating
2073 * @param label label of the records
2074 * @param rd_count record count
2075 * @param rd records
2076 */
2077static void
2078cred_iter_cb (void *cls,
2079 const struct GNUNET_IDENTITY_PrivateKey *zone,
2080 const char *label,
2081 unsigned int rd_count,
2082 const struct GNUNET_GNSRECORD_Data *rd)
2083{
2084 struct Iterator *ai = cls;
2085 struct GNUNET_MQ_Envelope *env;
2086 struct CredentialResultMessage *arm;
2087 char *data_tmp;
2088
2089 if ((rd_count != 1) ||
2090 (GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL != rd->record_type))
2091 {
2092 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2093 return;
2094 }
2095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found credential under: %s\n",
2096 label);
2097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2098 "Sending CREDENTIAL_RESULT message\n");
2099 env = GNUNET_MQ_msg_extra (arm,
2100 rd->data_size,
2101 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_RESULT);
2102 arm->id = htonl (ai->request_id);
2103 arm->credential_len = htons (rd->data_size);
2104 GNUNET_IDENTITY_key_get_public (zone, &arm->identity);
2105 data_tmp = (char *) &arm[1];
2106 GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
2107
2108 GNUNET_MQ_send (ai->client->mq, env);
2109}
2110
2111
2112/**
2113 * Iterate over zone to get attributes
2114 *
2115 * @param cls our client
2116 * @param ais_msg the iteration message to start
2117 */
2118static void
2119handle_credential_iteration_start (void *cls,
2120 const struct
2121 CredentialIterationStartMessage *ais_msg)
2122{
2123 struct IdpClient *idp = cls;
2124 struct Iterator *ai;
2125
2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2127 "Received CREDENTIAL_ITERATION_START message\n");
2128 ai = GNUNET_new (struct Iterator);
2129 ai->request_id = ntohl (ais_msg->id);
2130 ai->client = idp;
2131 ai->identity = ais_msg->identity;
2132
2133 GNUNET_CONTAINER_DLL_insert (idp->cred_iter_head, idp->cred_iter_tail,
2134 ai);
2135 ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
2136 &ai->identity,
2137 &cred_iter_error,
2138 ai,
2139 &cred_iter_cb,
2140 ai,
2141 &cred_iter_finished,
2142 ai);
2143 GNUNET_SERVICE_client_continue (idp->client);
2144}
2145
2146
2147/**
2148 * Handle iteration stop message from client
2149 *
2150 * @param cls the client
2151 * @param ais_msg the stop message
2152 */
2153static void
2154handle_credential_iteration_stop (void *cls,
2155 const struct
2156 CredentialIterationStopMessage *ais_msg)
2157{
2158 struct IdpClient *idp = cls;
2159 struct Iterator *ai;
2160 uint32_t rid;
2161
2162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2163 "Received `%s' message\n",
2164 "CREDENTIAL_ITERATION_STOP");
2165 rid = ntohl (ais_msg->id);
2166 for (ai = idp->cred_iter_head; NULL != ai; ai = ai->next)
2167 if (ai->request_id == rid)
2168 break;
2169 if (NULL == ai)
2170 {
2171 GNUNET_break (0);
2172 GNUNET_SERVICE_client_drop (idp->client);
2173 return;
2174 }
2175 GNUNET_CONTAINER_DLL_remove (idp->cred_iter_head, idp->cred_iter_tail,
2176 ai);
2177 GNUNET_free (ai);
2178 GNUNET_SERVICE_client_continue (idp->client);
2179}
2180
2181
2182/**
2183 * Client requests next credential from iterator
2184 *
2185 * @param cls the client
2186 * @param ais_msg the message
2187 */
2188static void
2189handle_credential_iteration_next (void *cls,
2190 const struct
2191 CredentialIterationNextMessage *ais_msg)
2192{
2193 struct IdpClient *idp = cls;
2194 struct Iterator *ai;
2195 uint32_t rid;
2196
2197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2198 "Received CREDENTIAL_ITERATION_NEXT message\n");
2199 rid = ntohl (ais_msg->id);
2200 for (ai = idp->cred_iter_head; NULL != ai; ai = ai->next)
2201 if (ai->request_id == rid)
2202 break;
2203 if (NULL == ai)
2204 {
2205 GNUNET_break (0);
2206 GNUNET_SERVICE_client_drop (idp->client);
2207 return;
2208 }
2209 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
2210 GNUNET_SERVICE_client_continue (idp->client);
2211}
2212
2213
2214/******************************************************
2215 * Ticket iteration
2216 ******************************************************/
2217
2218/**
2219 * Got a ticket. Return to client
2220 *
2221 * @param cls our ticket iterator
2222 * @param ticket the ticket
2223 */
2224static void
2225ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
2226{
2227 struct TicketIteration *ti = cls;
2228 struct GNUNET_MQ_Envelope *env;
2229 struct TicketResultMessage *trm;
2230
2231 env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
2232 if (NULL == ticket)
2233 {
2234 /* send empty response to indicate end of list */
2235 GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
2236 ti->client->ticket_iter_tail,
2237 ti);
2238 }
2239 else
2240 {
2241 trm->ticket = *ticket;
2242 }
2243 trm->id = htonl (ti->r_id);
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
2245 GNUNET_MQ_send (ti->client->mq, env);
2246 if (NULL == ticket)
2247 GNUNET_free (ti);
2248}
2249
2250
2251/**
2252 * Client requests a ticket iteration
2253 *
2254 * @param cls the client
2255 * @param tis_msg the iteration request message
2256 */
2257static void
2258handle_ticket_iteration_start (
2259 void *cls,
2260 const struct TicketIterationStartMessage *tis_msg)
2261{
2262 struct IdpClient *client = cls;
2263 struct TicketIteration *ti;
2264
2265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2266 "Received TICKET_ITERATION_START message\n");
2267 ti = GNUNET_new (struct TicketIteration);
2268 ti->r_id = ntohl (tis_msg->id);
2269 ti->client = client;
2270
2271 GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
2272 client->ticket_iter_tail,
2273 ti);
2274 ti->iter
2275 = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
2276 GNUNET_SERVICE_client_continue (client->client);
2277}
2278
2279
2280/**
2281 * Client has had enough tickets
2282 *
2283 * @param cls the client
2284 * @param tis_msg the stop message
2285 */
2286static void
2287handle_ticket_iteration_stop (void *cls,
2288 const struct TicketIterationStopMessage *tis_msg)
2289{
2290 struct IdpClient *client = cls;
2291 struct TicketIteration *ti;
2292 uint32_t rid;
2293
2294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2295 "Received `%s' message\n",
2296 "TICKET_ITERATION_STOP");
2297 rid = ntohl (tis_msg->id);
2298 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2299 if (ti->r_id == rid)
2300 break;
2301 if (NULL == ti)
2302 {
2303 GNUNET_break (0);
2304 GNUNET_SERVICE_client_drop (client->client);
2305 return;
2306 }
2307 RECLAIM_TICKETS_iteration_stop (ti->iter);
2308 GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
2309 client->ticket_iter_tail,
2310 ti);
2311 GNUNET_free (ti);
2312 GNUNET_SERVICE_client_continue (client->client);
2313}
2314
2315
2316/**
2317 * Client requests next result.
2318 *
2319 * @param cls the client
2320 * @param tis_msg the message
2321 */
2322static void
2323handle_ticket_iteration_next (void *cls,
2324 const struct TicketIterationNextMessage *tis_msg)
2325{
2326 struct IdpClient *client = cls;
2327 struct TicketIteration *ti;
2328 uint32_t rid;
2329
2330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331 "Received TICKET_ITERATION_NEXT message\n");
2332 rid = ntohl (tis_msg->id);
2333 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2334 if (ti->r_id == rid)
2335 break;
2336 if (NULL == ti)
2337 {
2338 GNUNET_break (0);
2339 GNUNET_SERVICE_client_drop (client->client);
2340 return;
2341 }
2342 RECLAIM_TICKETS_iteration_next (ti->iter);
2343 GNUNET_SERVICE_client_continue (client->client);
2344}
2345
2346
2347/**
2348 * Main function that will be run
2349 *
2350 * @param cls closure
2351 * @param c the configuration used
2352 * @param server the service handle
2353 */
2354static void
2355run (void *cls,
2356 const struct GNUNET_CONFIGURATION_Handle *c,
2357 struct GNUNET_SERVICE_Handle *server)
2358{
2359 cfg = c;
2360
2361 if (GNUNET_OK != RECLAIM_TICKETS_init (cfg))
2362 {
2363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2364 "Unable to initialize TICKETS subsystem.\n");
2365 GNUNET_SCHEDULER_shutdown ();
2366 return;
2367 }
2368 // Connect to identity and namestore services
2369 nsh = GNUNET_NAMESTORE_connect (cfg);
2370 if (NULL == nsh)
2371 {
2372 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
2373 "error connecting to namestore");
2374 }
2375
2376 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
2377}
2378
2379
2380/**
2381 * Called whenever a client is disconnected.
2382 *
2383 * @param cls closure
2384 * @param client identification of the client
2385 * @param app_ctx @a client
2386 */
2387static void
2388client_disconnect_cb (void *cls,
2389 struct GNUNET_SERVICE_Client *client,
2390 void *app_ctx)
2391{
2392 struct IdpClient *idp = app_ctx;
2393
2394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
2395 GNUNET_CONTAINER_DLL_remove (client_list_head,
2396 client_list_tail,
2397 idp);
2398 cleanup_client (idp);
2399}
2400
2401
2402/**
2403 * Add a client to our list of active clients.
2404 *
2405 * @param cls NULL
2406 * @param client client to add
2407 * @param mq message queue for @a client
2408 * @return internal namestore client structure for this client
2409 */
2410static void *
2411client_connect_cb (void *cls,
2412 struct GNUNET_SERVICE_Client *client,
2413 struct GNUNET_MQ_Handle *mq)
2414{
2415 struct IdpClient *idp;
2416
2417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
2418 idp = GNUNET_new (struct IdpClient);
2419 idp->client = client;
2420 idp->mq = mq;
2421 GNUNET_CONTAINER_DLL_insert (client_list_head,
2422 client_list_tail,
2423 idp);
2424 return idp;
2425}
2426
2427
2428/**
2429 * Define "main" method using service macro.
2430 */
2431GNUNET_SERVICE_MAIN (
2432 "reclaim",
2433 GNUNET_SERVICE_OPTION_NONE,
2434 &run,
2435 &client_connect_cb,
2436 &client_disconnect_cb,
2437 NULL,
2438 GNUNET_MQ_hd_var_size (attribute_store_message,
2439 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
2440 struct AttributeStoreMessage,
2441 NULL),
2442 GNUNET_MQ_hd_var_size (credential_store_message,
2443 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_STORE,
2444 struct AttributeStoreMessage,
2445 NULL),
2446 GNUNET_MQ_hd_var_size (attribute_delete_message,
2447 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
2448 struct AttributeDeleteMessage,
2449 NULL),
2450 GNUNET_MQ_hd_var_size (credential_delete_message,
2451 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_DELETE,
2452 struct AttributeDeleteMessage,
2453 NULL),
2454 GNUNET_MQ_hd_fixed_size (iteration_start,
2455 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
2456 struct AttributeIterationStartMessage,
2457 NULL),
2458 GNUNET_MQ_hd_fixed_size (iteration_next,
2459 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
2460 struct AttributeIterationNextMessage,
2461 NULL),
2462 GNUNET_MQ_hd_fixed_size (iteration_stop,
2463 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
2464 struct AttributeIterationStopMessage,
2465 NULL),
2466 GNUNET_MQ_hd_fixed_size (credential_iteration_start,
2467 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_START,
2468 struct CredentialIterationStartMessage,
2469 NULL),
2470 GNUNET_MQ_hd_fixed_size (credential_iteration_next,
2471 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_NEXT,
2472 struct CredentialIterationNextMessage,
2473 NULL),
2474 GNUNET_MQ_hd_fixed_size (credential_iteration_stop,
2475 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_STOP,
2476 struct CredentialIterationStopMessage,
2477 NULL),
2478
2479 GNUNET_MQ_hd_var_size (issue_ticket_message,
2480 GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
2481 struct IssueTicketMessage,
2482 NULL),
2483 GNUNET_MQ_hd_var_size (consume_ticket_message,
2484 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
2485 struct ConsumeTicketMessage,
2486 NULL),
2487 GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2488 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
2489 struct TicketIterationStartMessage,
2490 NULL),
2491 GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2492 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
2493 struct TicketIterationNextMessage,
2494 NULL),
2495 GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2496 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
2497 struct TicketIterationStopMessage,
2498 NULL),
2499 GNUNET_MQ_hd_var_size (revoke_ticket_message,
2500 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
2501 struct RevokeTicketMessage,
2502 NULL),
2503 GNUNET_MQ_handler_end ());
2504/* end of gnunet-service-reclaim.c */
diff --git a/src/reclaim/gnunet-service-reclaim_tickets.c b/src/reclaim/gnunet-service-reclaim_tickets.c
deleted file mode 100644
index 5d3119c6f..000000000
--- a/src/reclaim/gnunet-service-reclaim_tickets.c
+++ /dev/null
@@ -1,1853 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.c
24 * @brief reclaim tickets
25 *
26 */
27#include <inttypes.h>
28#include "gnunet-service-reclaim_tickets.h"
29
30
31/**
32 * FIXME: the default ticket iteration interval should probably
33 * be the minimim attribute expiration.
34 */
35#define DEFAULT_TICKET_REFRESH_INTERVAL GNUNET_TIME_UNIT_HOURS
36
37/**
38 * Handle for a parallel GNS lookup job
39 * (Declaration further below)
40 */
41struct ParallelLookup;
42
43
44/**
45 * A reference to a ticket stored in GNS
46 */
47struct TicketReference
48{
49 /**
50 * DLL
51 */
52 struct TicketReference *next;
53
54 /**
55 * DLL
56 */
57 struct TicketReference *prev;
58
59 /**
60 * Attributes
61 */
62 struct GNUNET_RECLAIM_AttributeList *attrs;
63
64 /**
65 * Tickets
66 */
67 struct GNUNET_RECLAIM_Ticket ticket;
68};
69
70
71/**
72 * Handle to a consume operation
73 */
74struct RECLAIM_TICKETS_ConsumeHandle
75{
76 /**
77 * Ticket
78 */
79 struct GNUNET_RECLAIM_Ticket ticket;
80
81 /**
82 * LookupRequest
83 */
84 struct GNUNET_GNS_LookupRequest *lookup_request;
85
86 /**
87 * Audience Key
88 */
89 struct GNUNET_IDENTITY_PrivateKey identity;
90
91 /**
92 * Audience Key
93 */
94 struct GNUNET_IDENTITY_PublicKey identity_pub;
95
96 /**
97 * Lookup DLL
98 */
99 struct ParallelLookup *parallel_lookups_head;
100
101 /**
102 * Lookup DLL
103 */
104 struct ParallelLookup *parallel_lookups_tail;
105
106 /**
107 * Kill task
108 */
109 struct GNUNET_SCHEDULER_Task *kill_task;
110
111 /**
112 * Attributes
113 */
114 struct GNUNET_RECLAIM_AttributeList *attrs;
115
116 /**
117 * Presentations
118 */
119 struct GNUNET_RECLAIM_PresentationList *presentations;
120
121 /**
122 * Lookup time
123 */
124 struct GNUNET_TIME_Absolute lookup_start_time;
125
126 /**
127 * Callback
128 */
129 RECLAIM_TICKETS_ConsumeCallback cb;
130
131 /**
132 * Callback closure
133 */
134 void *cb_cls;
135};
136
137
138/**
139 * Handle for a parallel GNS lookup job
140 */
141struct ParallelLookup
142{
143 /* DLL */
144 struct ParallelLookup *next;
145
146 /* DLL */
147 struct ParallelLookup *prev;
148
149 /* The GNS request */
150 struct GNUNET_GNS_LookupRequest *lookup_request;
151
152 /* The handle the return to */
153 struct RECLAIM_TICKETS_ConsumeHandle *handle;
154
155 /**
156 * Lookup time
157 */
158 struct GNUNET_TIME_Absolute lookup_start_time;
159
160 /* The label to look up */
161 char *label;
162};
163
164
165/**
166 * Ticket issue request handle
167 */
168struct TicketIssueHandle
169{
170 /**
171 * Attributes to issue
172 */
173 struct GNUNET_RECLAIM_AttributeList *attrs;
174
175 /**
176 * Presentations to add
177 */
178 struct GNUNET_RECLAIM_PresentationList *presentations;
179
180 /**
181 * Issuer Key
182 */
183 struct GNUNET_IDENTITY_PrivateKey identity;
184
185 /**
186 * Ticket to issue
187 */
188 struct GNUNET_RECLAIM_Ticket ticket;
189
190 /**
191 * QueueEntry
192 */
193 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
194
195 /**
196 * Namestore Iterator
197 */
198 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
199
200 /**
201 * Callback
202 */
203 RECLAIM_TICKETS_TicketResult cb;
204
205 /**
206 * Callback cls
207 */
208 void *cb_cls;
209};
210
211
212/**
213 * Ticket iterator
214 */
215struct RECLAIM_TICKETS_Iterator
216{
217 /**
218 * Namestore queue entry
219 */
220 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
221
222 /**
223 * Iter callback
224 */
225 RECLAIM_TICKETS_TicketIter cb;
226
227 /**
228 * Iter cls
229 */
230 void *cb_cls;
231};
232
233
234struct RevokedAttributeEntry
235{
236 /**
237 * DLL
238 */
239 struct RevokedAttributeEntry *next;
240
241 /**
242 * DLL
243 */
244 struct RevokedAttributeEntry *prev;
245
246 /**
247 * Old ID of the attribute
248 */
249 struct GNUNET_RECLAIM_Identifier old_id;
250
251 /**
252 * New ID of the attribute
253 */
254 struct GNUNET_RECLAIM_Identifier new_id;
255};
256
257
258/**
259 * Ticket revocation request handle
260 */
261struct RECLAIM_TICKETS_RevokeHandle
262{
263 /**
264 * Issuer Key
265 */
266 struct GNUNET_IDENTITY_PrivateKey identity;
267
268 /**
269 * Callback
270 */
271 RECLAIM_TICKETS_RevokeCallback cb;
272
273 /**
274 * Callback cls
275 */
276 void *cb_cls;
277
278 /**
279 * Ticket to issue
280 */
281 struct GNUNET_RECLAIM_Ticket ticket;
282
283 /**
284 * QueueEntry
285 */
286 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
287
288 /**
289 * Namestore iterator
290 */
291 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
292
293 /**
294 * Revoked attributes
295 */
296 struct RevokedAttributeEntry *attrs_head;
297
298 /**
299 * Revoked attributes
300 */
301 struct RevokedAttributeEntry *attrs_tail;
302
303 /**
304 * Current attribute to move
305 */
306 struct RevokedAttributeEntry *move_attr;
307
308 /**
309 * Number of attributes in ticket
310 */
311 unsigned int ticket_attrs;
312
313 /**
314 * Tickets to update
315 */
316 struct TicketRecordsEntry *tickets_to_update_head;
317
318 /**
319 * Tickets to update
320 */
321 struct TicketRecordsEntry *tickets_to_update_tail;
322};
323
324
325/**
326 * Ticket expiration interval
327 */
328static struct GNUNET_TIME_Relative ticket_refresh_interval;
329
330
331/* Namestore handle */
332static struct GNUNET_NAMESTORE_Handle *nsh;
333
334
335/* GNS handle */
336static struct GNUNET_GNS_Handle *gns;
337
338
339/* Handle to the statistics service */
340static struct GNUNET_STATISTICS_Handle *stats;
341
342
343/**
344 * Cleanup revoke handle
345 *
346 * @param rh the ticket revocation handle
347 */
348static void
349cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
350{
351 struct RevokedAttributeEntry *ae;
352 struct TicketRecordsEntry *le;
353
354 if (NULL != rh->ns_qe)
355 GNUNET_NAMESTORE_cancel (rh->ns_qe);
356 if (NULL != rh->ns_it)
357 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
358 while (NULL != (ae = rh->attrs_head))
359 {
360 GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
361 GNUNET_free (ae);
362 }
363 while (NULL != (le = rh->tickets_to_update_head))
364 {
365 GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
366 rh->tickets_to_update_head,
367 le);
368 if (NULL != le->data)
369 GNUNET_free (le->data);
370 if (NULL != le->label)
371 GNUNET_free (le->label);
372 GNUNET_free (le);
373 }
374 GNUNET_free (rh);
375}
376
377
378/**
379 * For each ticket, store new, updated attribute references
380 * (Implementation further below)
381 *
382 * @param cls handle to the operation
383 */
384static void
385process_tickets (void *cls);
386
387
388/**
389 * Finished storing updated attribute references.
390 * Abort on error, else continue processing tickets
391 *
392 * @param cls handle to the operation
393 * @param success result of namestore operation
394 * @param emsg (NULL on success)
395 */
396static void
397ticket_processed (void *cls, int32_t success, const char *emsg)
398{
399 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
400
401 rvk->ns_qe = NULL;
402 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
403}
404
405
406/**
407 * For each ticket, store new, updated attribute references
408 *
409 * @param cls handle to the operation
410 */
411static void
412process_tickets (void *cls)
413{
414 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
415 struct TicketRecordsEntry *le;
416 struct RevokedAttributeEntry *ae;
417
418 if (NULL == rvk->tickets_to_update_head)
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Finished updatding tickets, success\n");
422 rvk->cb (rvk->cb_cls, GNUNET_OK);
423 cleanup_rvk (rvk);
424 return;
425 }
426 le = rvk->tickets_to_update_head;
427 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
428 rvk->tickets_to_update_tail,
429 le);
430 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
431 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
432 le->data,
433 le->rd_count,
434 rd))
435 {
436 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
437 "Unable to deserialize ticket record(s)\n");
438 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
439 cleanup_rvk (rvk);
440 return;
441 }
442 for (int i = 0; i < le->rd_count; i++)
443 {
444 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
445 continue;
446 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
447 {
448 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
449 continue;
450 rd[i].data = &ae->new_id;
451 }
452 }
453 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
454 &rvk->identity,
455 le->label,
456 le->rd_count,
457 rd,
458 &ticket_processed,
459 rvk);
460 GNUNET_free (le->label);
461 GNUNET_free (le->data);
462 GNUNET_free (le);
463}
464
465
466/**
467 * Done collecting tickets. Start processing.
468 *
469 * @param cls handle to the operation
470 */
471static void
472rvk_ticket_update_finished (void *cls)
473{
474 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
475
476 rvk->ns_it = NULL;
477 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
478}
479
480
481/**
482 * We need to update all other tickets with the new attribute IDs.
483 * We first collect them all. Processing after.
484 *
485 * @param cls handle to the operation
486 * @param zone ticket issuer private key
487 * @param label ticket rnd
488 * @param rd_cound size of record set
489 * @param rd record set
490 */
491static void
492rvk_ticket_update (void *cls,
493 const struct GNUNET_IDENTITY_PrivateKey *zone,
494 const char *label,
495 unsigned int rd_count,
496 const struct GNUNET_GNSRECORD_Data *rd)
497{
498 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
499 struct TicketRecordsEntry *le;
500 struct RevokedAttributeEntry *ae;
501 int has_changed = GNUNET_NO;
502
503 /** Let everything point to the old record **/
504 for (int i = 0; i < rd_count; i++)
505 {
506 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
507 continue;
508 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
509 {
510 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
511 continue;
512 has_changed = GNUNET_YES;
513 break;
514 }
515 if (GNUNET_YES == has_changed)
516 break;
517 }
518 if (GNUNET_YES == has_changed)
519 {
520 le = GNUNET_new (struct TicketRecordsEntry);
521 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
522 le->data = GNUNET_malloc (le->data_size);
523 le->rd_count = rd_count;
524 le->label = GNUNET_strdup (label);
525 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
526 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
527 rvk->tickets_to_update_tail,
528 le);
529 }
530 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
531}
532
533
534/**
535 * Error iterating namestore. Abort.
536 *
537 * @param cls handle to the operation
538 */
539static void
540rvk_ns_iter_err (void *cls)
541{
542 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
543
544 rvk->ns_it = NULL;
545 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
546 cleanup_rvk (rvk);
547}
548
549
550/**
551 * Error storing new attribute in namestore. Abort
552 *
553 * @param cls handle to the operation
554 */
555static void
556rvk_ns_err (void *cls)
557{
558 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
559
560 rvk->ns_qe = NULL;
561 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
562 cleanup_rvk (rvk);
563}
564
565
566/**
567 * We change every attribute ID of the ticket attributes we
568 * want to revoke.
569 * When we are done, we need to update any other ticket which
570 * included references to any of the changed attributes.
571 * (Implementation further below)
572 *
573 * @param rvk handle to the operation
574 */
575static void
576move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
577
578
579/**
580 * Delayed continuation for move_attrs
581 *
582 * @param cls handle to the operation.
583 */
584static void
585move_attrs_cont (void *cls)
586{
587 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
588}
589
590
591/**
592 * Done deleting the old record. Abort on error.
593 * Else, continue updating attribute IDs.
594 *
595 * @param cls handle to the operation
596 * @param success result of the namestore operation
597 * @param emsg error message (NULL on success)
598 */
599static void
600del_attr_finished (void *cls, int32_t success, const char *emsg)
601{
602 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
603
604 rvk->ns_qe = NULL;
605 if (GNUNET_SYSERR == success)
606 {
607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608 "Error removing attribute: %s\n",
609 emsg);
610 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
611 cleanup_rvk (rvk);
612 return;
613 }
614 rvk->move_attr = rvk->move_attr->next;
615 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
616}
617
618
619/**
620 * Updated an attribute ID.
621 * Abort on error if namestore operation failed.
622 * Else, we have to delete the old record.
623 *
624 * @param cls handle to the operation
625 * @param success result of the store operation
626 * @param emsg error message (NULL on success)
627 */
628static void
629move_attr_finished (void *cls, int32_t success, const char *emsg)
630{
631 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
632 char *label;
633
634 rvk->ns_qe = NULL;
635 if (GNUNET_SYSERR == success)
636 {
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
638 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
639 cleanup_rvk (rvk);
640 return;
641 }
642 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
643 sizeof(rvk->move_attr->old_id));
644 GNUNET_assert (NULL != label);
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
646 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
647 &rvk->identity,
648 label,
649 0,
650 NULL,
651 &del_attr_finished,
652 rvk);
653 GNUNET_free (label);
654}
655
656
657/**
658 * Got the referenced attribute. Updating the ID
659 *
660 * @param cls handle to the operation
661 * @param zone issuer identity
662 * @param label attribute ID
663 * @param rd_count size of record set (should be 1)
664 * @param rd record set (the attribute)
665 */
666static void
667rvk_move_attr_cb (void *cls,
668 const struct GNUNET_IDENTITY_PrivateKey *zone,
669 const char *label,
670 unsigned int rd_count,
671 const struct GNUNET_GNSRECORD_Data *rd)
672{
673 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
674 struct GNUNET_GNSRECORD_Data new_rd[rd_count];
675 struct RevokedAttributeEntry *le;
676 char *new_label;
677 char *attr_data;
678
679 rvk->ns_qe = NULL;
680 if (0 == rd_count)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683 "The claim %s no longer exists!\n",
684 label);
685 le = rvk->move_attr;
686 rvk->move_attr = le->next;
687 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
688 GNUNET_free (le);
689 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
690 return;
691 }
692 GNUNET_RECLAIM_id_generate (&rvk->move_attr->new_id);
693 new_label =
694 GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
695 sizeof (rvk->move_attr->new_id));
696
697 attr_data = NULL;
698 // new_rd = *rd;
699 for (int i = 0; i < rd_count; i++)
700 {
701 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE == rd[i].record_type)
702 {
703 /** find a new place for this attribute **/
704 struct GNUNET_RECLAIM_Attribute *claim;
705 GNUNET_RECLAIM_attribute_deserialize (rd[i].data,
706 rd[i].data_size,
707 &claim);
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Attribute to update: Name=%s\n",
710 claim->name);
711 claim->id = rvk->move_attr->new_id;
712 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize_get_size (claim);
713 attr_data = GNUNET_malloc (rd[i].data_size);
714 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize (claim,
715 attr_data);
716 new_rd[i].data = attr_data;
717 new_rd[i].record_type = rd[i].record_type;
718 new_rd[i].flags = rd[i].flags;
719 new_rd[i].expiration_time = rd[i].expiration_time;
720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
721 GNUNET_free (claim);
722 }
723 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL == rd[i].record_type)
724 {
725 struct GNUNET_RECLAIM_Credential *credential;
726 credential = GNUNET_RECLAIM_credential_deserialize (rd[i].data,
727 rd[i].data_size);
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Credential to update: Name=%s\n",
730 credential->name);
731 credential->id = rvk->move_attr->new_id;
732 new_rd[i].data_size =
733 GNUNET_RECLAIM_credential_serialize_get_size (credential);
734 attr_data = GNUNET_malloc (rd[i].data_size);
735 new_rd[i].data_size = GNUNET_RECLAIM_credential_serialize (credential,
736 attr_data);
737 new_rd[i].data = attr_data;
738 new_rd[i].record_type = rd[i].record_type;
739 new_rd[i].flags = rd[i].flags;
740 new_rd[i].expiration_time = rd[i].expiration_time;
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding credential %s\n",
742 new_label);
743 GNUNET_free (credential);
744 }
745 }
746 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
747 &rvk->identity,
748 new_label,
749 rd_count,
750 new_rd,
751 &move_attr_finished,
752 rvk);
753 GNUNET_free (new_label);
754 GNUNET_free (attr_data);
755}
756
757
758/**
759 * We change every attribute ID of the ticket attributes we
760 * want to revoke.
761 * When we are done, we need to update any other ticket which
762 * included references to any of the changed attributes.
763 *
764 * @param rvk handle to the operation
765 */
766static void
767move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
768{
769 char *label;
770
771 if (NULL == rvk->move_attr)
772 {
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
774 rvk->ns_it =
775 GNUNET_NAMESTORE_zone_iteration_start (nsh,
776 &rvk->identity,
777 &rvk_ns_iter_err,
778 rvk,
779 &rvk_ticket_update,
780 rvk,
781 &rvk_ticket_update_finished,
782 rvk);
783 return;
784 }
785 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
786 sizeof (rvk->move_attr->old_id));
787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving claim %s\n", label);
788
789 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
790 &rvk->identity,
791 label,
792 &rvk_ns_err,
793 rvk,
794 &rvk_move_attr_cb,
795 rvk);
796 GNUNET_free (label);
797}
798
799
800/**
801 * Finished deleting ticket and attribute references.
802 * Abort on failure.
803 * Else, we start changing every attribute ID in the
804 * found attribute references so that access is no longer
805 * possible.
806 *
807 * @param cls handle to the operation
808 * @param success Namestore operation return value
809 * @param emsg error message (NULL on success)
810 */
811static void
812remove_ticket_cont (void *cls, int32_t success, const char *emsg)
813{
814 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
815
816 rvk->ns_qe = NULL;
817 if (GNUNET_SYSERR == success)
818 {
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
820 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
821 cleanup_rvk (rvk);
822 return;
823 }
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
825 if (0 == rvk->ticket_attrs)
826 {
827 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
828 "No attributes to move... strange\n");
829 rvk->cb (rvk->cb_cls, GNUNET_OK);
830 cleanup_rvk (rvk);
831 return;
832 }
833 rvk->move_attr = rvk->attrs_head;
834 move_attrs (rvk);
835}
836
837
838/**
839 * We found the attribute references.
840 * Store them for later and remove the record set.
841 *
842 * @param cls handle to the operation
843 * @param zone the issuer key
844 * @param label ticket rnd
845 * @param rd_cound size of record set
846 * @param rd record set
847 */
848static void
849revoke_attrs_cb (void *cls,
850 const struct GNUNET_IDENTITY_PrivateKey *zone,
851 const char *label,
852 unsigned int rd_count,
853 const struct GNUNET_GNSRECORD_Data *rd)
854
855{
856 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
857 struct RevokedAttributeEntry *le;
858
859 rvk->ns_qe = NULL;
860 /**
861 * Temporarily store attribute references.
862 * We need it later.
863 */
864 for (int i = 0; i < rd_count; i++)
865 {
866 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
867 continue;
868 le = GNUNET_new (struct RevokedAttributeEntry);
869 le->old_id = *((struct GNUNET_RECLAIM_Identifier *) rd[i].data);
870 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
871 rvk->ticket_attrs++;
872 }
873
874 /** Remove attribute references **/
875 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
876 &rvk->identity,
877 label,
878 0,
879 NULL,
880 &remove_ticket_cont,
881 rvk);
882}
883
884
885/**
886 * Failed to query namestore. Abort operation
887 *
888 * @param cls handle to the operation
889 */
890static void
891rvk_attrs_err_cb (void *cls)
892{
893 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
894
895 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
896 cleanup_rvk (rvk);
897}
898
899
900/**
901 * Revoke a ticket.
902 * We start by looking up attribute references in order
903 * to change attribute IDs.
904 *
905 * @param ticket ticket to revoke
906 * @param identity private key of issuer
907 * @param cb revocation status callback
908 * @param cb_cls callback closure
909 * @return handle to the operation
910 */
911struct RECLAIM_TICKETS_RevokeHandle *
912RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
913 const struct GNUNET_IDENTITY_PrivateKey *identity,
914 RECLAIM_TICKETS_RevokeCallback cb,
915 void *cb_cls)
916{
917 struct RECLAIM_TICKETS_RevokeHandle *rvk;
918 char *label;
919
920 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
921 rvk->cb = cb;
922 rvk->cb_cls = cb_cls;
923 rvk->identity = *identity;
924 rvk->ticket = *ticket;
925 GNUNET_IDENTITY_key_get_public (&rvk->identity, &rvk->ticket.identity);
926 /** Get shared attributes **/
927 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
928 sizeof(ticket->rnd));
929 GNUNET_assert (NULL != label);
930 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
931 identity,
932 label,
933 &rvk_attrs_err_cb,
934 rvk,
935 &revoke_attrs_cb,
936 rvk);
937 GNUNET_free (label);
938 return rvk;
939}
940
941
942/**
943 * Cancel a revocation.
944 *
945 * @param rh handle to the operation
946 */
947void
948RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
949{
950 GNUNET_assert (NULL != rh);
951 cleanup_rvk (rh);
952}
953
954
955/*******************************
956* Ticket consume
957*******************************/
958
959/**
960 * Cleanup ticket consume handle
961 *
962 * @param cth the handle to clean up
963 */
964static void
965cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
966{
967 struct ParallelLookup *lu;
968
969 if (NULL != cth->lookup_request)
970 GNUNET_GNS_lookup_cancel (cth->lookup_request);
971 if (NULL != cth->kill_task)
972 GNUNET_SCHEDULER_cancel (cth->kill_task);
973 while (NULL != (lu = cth->parallel_lookups_head))
974 {
975 if (NULL != lu->lookup_request)
976 GNUNET_GNS_lookup_cancel (lu->lookup_request);
977 GNUNET_free (lu->label);
978 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
979 cth->parallel_lookups_tail,
980 lu);
981 GNUNET_free (lu);
982 }
983
984 if (NULL != cth->attrs)
985 GNUNET_RECLAIM_attribute_list_destroy (cth->attrs);
986 if (NULL != cth->presentations)
987 GNUNET_RECLAIM_presentation_list_destroy (cth->presentations);
988 GNUNET_free (cth);
989}
990
991
992/**
993 * We found an attribute record.
994 *
995 * @param cls handle to the operation
996 * @param rd_cound size of record set
997 * @param rd record set
998 */
999static void
1000process_parallel_lookup_result (void *cls,
1001 uint32_t rd_count,
1002 const struct GNUNET_GNSRECORD_Data *rd)
1003{
1004 struct ParallelLookup *parallel_lookup = cls;
1005 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
1006 struct GNUNET_RECLAIM_AttributeListEntry *attr_le;
1007
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 "Parallel lookup finished (count=%u)\n",
1010 rd_count);
1011
1012 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1013 cth->parallel_lookups_tail,
1014 parallel_lookup);
1015 GNUNET_free (parallel_lookup->label);
1016
1017 GNUNET_STATISTICS_update (stats,
1018 "attribute_lookup_time_total",
1019 GNUNET_TIME_absolute_get_duration (
1020 parallel_lookup->lookup_start_time)
1021 .rel_value_us,
1022 GNUNET_YES);
1023 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
1024
1025
1026 GNUNET_free (parallel_lookup);
1027 if (0 == rd_count)
1028 GNUNET_break (0);
1029 // REMARK: It is possible now to find rd_count > 1
1030 for (int i = 0; i < rd_count; i++)
1031 {
1032 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE != rd[i].record_type)
1033 continue;
1034 attr_le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1035 GNUNET_RECLAIM_attribute_deserialize (rd[i].data, rd[i].data_size,
1036 &attr_le->attribute);
1037 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1038 cth->attrs->list_tail,
1039 attr_le);
1040 }
1041 if (NULL != cth->parallel_lookups_head)
1042 return; // Wait for more
1043 /* Else we are done */
1044 cth->cb (cth->cb_cls, &cth->ticket.identity,
1045 cth->attrs, cth->presentations, GNUNET_OK, NULL);
1046 cleanup_cth (cth);
1047}
1048
1049
1050/**
1051 * Cancel the lookups for attribute records
1052 *
1053 * @param cls handle to the operation
1054 */
1055static void
1056abort_parallel_lookups (void *cls)
1057{
1058 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1059 struct ParallelLookup *lu;
1060 struct ParallelLookup *tmp;
1061
1062 cth->kill_task = NULL;
1063 for (lu = cth->parallel_lookups_head; NULL != lu;)
1064 {
1065 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1066 GNUNET_free (lu->label);
1067 tmp = lu->next;
1068 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1069 cth->parallel_lookups_tail,
1070 lu);
1071 GNUNET_free (lu);
1072 lu = tmp;
1073 }
1074 cth->cb (cth->cb_cls, NULL, NULL, NULL, GNUNET_SYSERR, "Aborted");
1075}
1076
1077
1078/**
1079 * GNS result with attribute references.
1080 * For each result, we start a (parallel) lookup of the actual
1081 * attribute record under the referenced label.
1082 *
1083 * @param cls handle to the operation
1084 * @param rd_cound size of the record set
1085 * @param rd record set
1086 */
1087static void
1088lookup_authz_cb (void *cls,
1089 uint32_t rd_count,
1090 const struct GNUNET_GNSRECORD_Data *rd)
1091{
1092 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1093 struct ParallelLookup *parallel_lookup;
1094 char *lbl;
1095 struct GNUNET_RECLAIM_PresentationListEntry *ale;
1096
1097 cth->lookup_request = NULL;
1098
1099 GNUNET_STATISTICS_update (stats,
1100 "reclaim_authz_lookup_time_total",
1101 GNUNET_TIME_absolute_get_duration (
1102 cth->lookup_start_time)
1103 .rel_value_us,
1104 GNUNET_YES);
1105 GNUNET_STATISTICS_update (stats,
1106 "reclaim_authz_lookups_count",
1107 1,
1108 GNUNET_YES);
1109
1110 for (int i = 0; i < rd_count; i++)
1111 {
1112 /**
1113 * Check if record is a credential presentation or an attribute
1114 * reference.
1115 */
1116 switch (rd[i].record_type)
1117 {
1118 case GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION:
1119 ale = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1120 ale->presentation =
1121 GNUNET_RECLAIM_presentation_deserialize (rd[i].data,
1122 rd[i].data_size);
1123 GNUNET_CONTAINER_DLL_insert (cth->presentations->list_head,
1124 cth->presentations->list_tail,
1125 ale);
1126 break;
1127 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF:
1128 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ticket reference found %s\n", lbl);
1130 parallel_lookup = GNUNET_new (struct ParallelLookup);
1131 parallel_lookup->handle = cth;
1132 parallel_lookup->label = lbl;
1133 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1134 parallel_lookup->lookup_request =
1135 GNUNET_GNS_lookup (gns,
1136 lbl,
1137 &cth->ticket.identity,
1138 GNUNET_GNSRECORD_TYPE_ANY,
1139 GNUNET_GNS_LO_DEFAULT,
1140 &process_parallel_lookup_result,
1141 parallel_lookup);
1142 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1143 cth->parallel_lookups_tail,
1144 parallel_lookup);
1145 break;
1146 default:
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "Ignoring unknown record type %d", rd[i].record_type);
1149 }
1150 }
1151 /**
1152 * We started lookups. Add a timeout task.
1153 * FIXME: Really needed here?
1154 */
1155 if (NULL != cth->parallel_lookups_head)
1156 {
1157 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1158 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1159 &abort_parallel_lookups,
1160 cth);
1161 return;
1162 }
1163 /**
1164 * No references found, return empty attribute list
1165 */
1166 cth->cb (cth->cb_cls, &cth->ticket.identity,
1167 cth->attrs, NULL, GNUNET_OK, NULL);
1168 cleanup_cth (cth);
1169}
1170
1171
1172/**
1173 * Consume a ticket.
1174 * We first looking attribute references under the label
1175 * ticket.rnd in GNS.
1176 *
1177 * @param id the audience of the ticket
1178 * @param ticket the ticket to consume
1179 * @param cb callback to call with attributes of ticket
1180 * @param cb_cls callback closure
1181 * @return handle to the operation
1182 */
1183struct RECLAIM_TICKETS_ConsumeHandle *
1184RECLAIM_TICKETS_consume (const struct GNUNET_IDENTITY_PrivateKey *id,
1185 const struct GNUNET_RECLAIM_Ticket *ticket,
1186 RECLAIM_TICKETS_ConsumeCallback cb,
1187 void *cb_cls)
1188{
1189 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1190 char *label;
1191
1192 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1193
1194 cth->identity = *id;
1195 GNUNET_IDENTITY_key_get_public (&cth->identity, &cth->identity_pub);
1196 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1197 cth->presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1198 cth->ticket = *ticket;
1199 cth->cb = cb;
1200 cth->cb_cls = cb_cls;
1201 label =
1202 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd,
1203 sizeof(cth->ticket.rnd));
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "Looking for AuthZ info under %s\n",
1206 label);
1207 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1208 cth->lookup_request =
1209 GNUNET_GNS_lookup (gns,
1210 label,
1211 &cth->ticket.identity,
1212 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF,
1213 GNUNET_GNS_LO_DEFAULT,
1214 &lookup_authz_cb,
1215 cth);
1216 GNUNET_free (label);
1217 return cth;
1218}
1219
1220
1221/**
1222 * Cancel a consume operation
1223 *
1224 * @param cth the operation to cancel
1225 */
1226void
1227RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1228{
1229 cleanup_cth (cth);
1230 return;
1231}
1232
1233
1234/*******************************
1235 * Ticket issue
1236 *******************************/
1237
1238/**
1239 * Cleanup ticket consume handle
1240 * @param handle the handle to clean up
1241 */
1242static void
1243cleanup_issue_handle (struct TicketIssueHandle *handle)
1244{
1245 if (NULL != handle->ns_qe)
1246 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1247 GNUNET_free (handle);
1248}
1249
1250
1251/**
1252 * Store finished, abort on error.
1253 * Else, return new ticket to caller.
1254 *
1255 * @param cls handle to the operation
1256 * @param success store operation result
1257 * @param emsg error message (or NULL on success)
1258 */
1259static void
1260store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1261{
1262 struct TicketIssueHandle *handle = cls;
1263
1264 handle->ns_qe = NULL;
1265 if (GNUNET_SYSERR == success)
1266 {
1267 handle->cb (handle->cb_cls,
1268 &handle->ticket,
1269 NULL,
1270 GNUNET_SYSERR,
1271 "Error storing AuthZ ticket in GNS");
1272 return;
1273 }
1274 handle->cb (handle->cb_cls,
1275 &handle->ticket,
1276 handle->presentations,
1277 GNUNET_OK, NULL);
1278 cleanup_issue_handle (handle);
1279}
1280
1281
1282/**
1283 * Issue a new ticket.
1284 * We store references to attribute record labels and the ticket itself
1285 * under the label base64(ticket.rnd).
1286 *
1287 * @param ih handle to the operation containing relevant metadata
1288 */
1289static void
1290issue_ticket (struct TicketIssueHandle *ih)
1291{
1292 struct GNUNET_RECLAIM_AttributeListEntry *le;
1293 struct GNUNET_RECLAIM_PresentationListEntry *ple;
1294 struct GNUNET_GNSRECORD_Data *attrs_record;
1295 char *label;
1296 int i;
1297 int j;
1298 int attrs_count = 0;
1299
1300 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1301 attrs_count++;
1302
1303 // Worst case we have one presentation per attribute
1304 attrs_record =
1305 GNUNET_malloc (2 * attrs_count * sizeof(struct GNUNET_GNSRECORD_Data));
1306 i = 0;
1307 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1308 {
1309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1310 "Adding list entry: %s\n", le->attribute->name);
1311
1312 attrs_record[i].data = &le->attribute->id;
1313 attrs_record[i].data_size = sizeof(le->attribute->id);
1314 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1315 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF;
1316 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1317 i++;
1318 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
1319 {
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "Attribute is backed by credential. Adding...\n");
1322 struct GNUNET_RECLAIM_Presentation *presentation = NULL;
1323 for (j = 0; j < i; j++)
1324 {
1325 if (attrs_record[j].record_type
1326 != GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION)
1327 continue;
1328 presentation = GNUNET_RECLAIM_presentation_deserialize (
1329 attrs_record[j].data,
1330 attrs_record[j].
1331 data_size);
1332 if (NULL == presentation)
1333 {
1334 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1335 "Failed to deserialize presentation\n");
1336 continue;
1337 }
1338 if (0 == memcmp (&presentation->credential_id,
1339 &le->attribute->credential,
1340 sizeof (le->attribute->credential)))
1341 break;
1342 GNUNET_free (presentation);
1343 presentation = NULL;
1344 }
1345 if (NULL != presentation)
1346 {
1347 GNUNET_free (presentation);
1348 continue; // Skip as we have already added this credential presentation.
1349 }
1350 for (ple = ih->presentations->list_head; NULL != ple; ple = ple->next)
1351 {
1352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353 "Checking presentation....\n");
1354
1355 if (0 != memcmp (&le->attribute->credential,
1356 &ple->presentation->credential_id,
1357 sizeof (le->attribute->credential)))
1358 {
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1360 "Presentation does not match credential ID.\n");
1361 continue;
1362 }
1363 char *pres_buf;
1364 size_t pres_size;
1365
1366 pres_size =
1367 GNUNET_RECLAIM_presentation_serialize_get_size (ple->presentation);
1368 pres_buf = GNUNET_malloc (pres_size);
1369 GNUNET_RECLAIM_presentation_serialize (ple->presentation,
1370 pres_buf);
1371 attrs_record[i].data = pres_buf;
1372 attrs_record[i].data_size = pres_size;
1373 attrs_record[i].expiration_time =
1374 ticket_refresh_interval.rel_value_us;
1375 attrs_record[i].record_type =
1376 GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION;
1377 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1378 i++;
1379 break;
1380 }
1381 }
1382 }
1383 attrs_record[i].data = &ih->ticket;
1384 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1385 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1386 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1387 attrs_record[i].flags =
1388 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1389 i++;
1390
1391 label =
1392 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
1393 sizeof(ih->ticket.rnd));
1394 // Publish record
1395 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1396 &ih->identity,
1397 label,
1398 i,
1399 attrs_record,
1400 &store_ticket_issue_cont,
1401 ih);
1402 for (j = 0; j < i; j++)
1403 {
1404 if (attrs_record[j].record_type
1405 != GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION)
1406 continue;
1407 // Yes, we are allowed to do this because we allocated it above
1408 char *ptr = (char*) attrs_record[j].data;
1409 GNUNET_free (ptr);
1410 }
1411 GNUNET_free (attrs_record);
1412 GNUNET_free (label);
1413}
1414
1415
1416/*************************************************
1417 * Ticket iteration (finding a specific ticket)
1418 *************************************************/
1419
1420
1421/**
1422 * Namestore error on issue. Abort.
1423 *
1424 * @param cls handle to the operation
1425 */
1426static void
1427filter_tickets_error_cb (void *cls)
1428{
1429 struct TicketIssueHandle *tih = cls;
1430
1431 tih->ns_it = NULL;
1432 tih->cb (tih->cb_cls,
1433 &tih->ticket,
1434 NULL,
1435 GNUNET_SYSERR,
1436 "Error storing AuthZ ticket in GNS");
1437 cleanup_issue_handle (tih);
1438}
1439
1440
1441/**
1442 * Iterator over records.
1443 * Check if any previously issued ticket already
1444 * matches what we need to prevent duplicates and
1445 * improve resolution synergy.
1446 *
1447 * @param cls handle to the operation
1448 * @param zone issuer identity
1449 * @param label ticket rnd
1450 * @param rd_count size of record set
1451 * @param rd record set
1452 */
1453static void
1454filter_tickets_cb (void *cls,
1455 const struct GNUNET_IDENTITY_PrivateKey *zone,
1456 const char *label,
1457 unsigned int rd_count,
1458 const struct GNUNET_GNSRECORD_Data *rd)
1459{
1460 struct TicketIssueHandle *tih = cls;
1461 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1462 struct GNUNET_RECLAIM_Presentation *presentation;
1463 struct GNUNET_RECLAIM_PresentationList *ticket_presentations;
1464 struct GNUNET_RECLAIM_Credential *cred;
1465 struct GNUNET_RECLAIM_PresentationListEntry *ple;
1466 struct GNUNET_RECLAIM_AttributeListEntry *le;
1467 unsigned int attr_cnt = 0;
1468 unsigned int pres_cnt = 0;
1469
1470 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1471 {
1472 attr_cnt++;
1473 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
1474 pres_cnt++;
1475 }
1476
1477 // ticket search
1478 unsigned int found_attrs_cnt = 0;
1479 unsigned int found_pres_cnt = 0;
1480 ticket_presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1481
1482 for (int i = 0; i < rd_count; i++)
1483 {
1484 // found ticket
1485 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1486 {
1487 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1488 // cmp audience
1489 if (0 == memcmp (&tih->ticket.audience,
1490 &ticket->audience,
1491 sizeof(struct GNUNET_IDENTITY_PublicKey)))
1492 {
1493 tih->ticket = *ticket;
1494 continue;
1495 }
1496 ticket = NULL;
1497 }
1498
1499 // cmp requested attributes with ticket attributes
1500 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF == rd[i].record_type)
1501 {
1502 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1503 {
1504 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1505 &le->attribute->id))
1506 found_attrs_cnt++;
1507 }
1508 }
1509 if (GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL == rd[i].record_type)
1510 {
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "Found credential...\n");
1513
1514 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1515 {
1516 cred = GNUNET_RECLAIM_credential_deserialize (rd[i].data,
1517 rd[i].data_size);
1518 if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (&cred->id,
1519 &le->attribute->credential))
1520 {
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 "No match.\n");
1523 GNUNET_free (cred);
1524 continue;
1525 }
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 "Match, creating presentation...\n");
1528 if (GNUNET_OK != GNUNET_RECLAIM_credential_get_presentation (
1529 cred,
1530 tih->attrs,
1531 &presentation))
1532 {
1533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1534 "Unable to retrieve presentation from credential\n");
1535 GNUNET_free (cred);
1536 continue;
1537 }
1538 ple = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1539 ple->presentation = presentation;
1540 GNUNET_CONTAINER_DLL_insert (tih->presentations->list_head,
1541 tih->presentations->list_tail,
1542 ple);
1543 GNUNET_free (cred);
1544 break;
1545 }
1546 }
1547 if (GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION == rd[i].record_type)
1548 {
1549 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1550 {
1551 presentation = GNUNET_RECLAIM_presentation_deserialize (rd[i].data,
1552 rd[i].data_size);
1553 if (NULL == presentation)
1554 {
1555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1556 "Failed to deserialize presentation\n");
1557 continue;
1558 }
1559 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (
1560 &presentation->credential_id,
1561 &le->attribute->credential))
1562 {
1563 found_pres_cnt++;
1564 ple = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1565 ple->presentation = presentation;
1566 GNUNET_CONTAINER_DLL_insert (ticket_presentations->list_head,
1567 ticket_presentations->list_tail,
1568 ple);
1569 }
1570 }
1571 }
1572 }
1573
1574 /**
1575 * If we found a matching ticket, return that to the caller and
1576 * we are done.
1577 */
1578 if ((attr_cnt == found_attrs_cnt) &&
1579 (pres_cnt == found_pres_cnt) &&
1580 (NULL != ticket))
1581 {
1582 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1583 tih->cb (tih->cb_cls, &tih->ticket, ticket_presentations, GNUNET_OK, NULL);
1584 GNUNET_RECLAIM_presentation_list_destroy (ticket_presentations);
1585 cleanup_issue_handle (tih);
1586 return;
1587 }
1588 GNUNET_RECLAIM_presentation_list_destroy (ticket_presentations);
1589 // ticket not found in current record, checking next record set
1590 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1591}
1592
1593
1594/**
1595 * Done iterating over tickets and we apparently did
1596 * not find an existing, matching ticket.
1597 * Continue by issuing a new ticket.
1598 *
1599 * @param cls handle to the operation
1600 */
1601static void
1602filter_tickets_finished_cb (void *cls)
1603{
1604 struct TicketIssueHandle *tih = cls;
1605
1606 GNUNET_IDENTITY_key_get_public (&tih->identity, &tih->ticket.identity);
1607 GNUNET_RECLAIM_id_generate (&tih->ticket.rnd);
1608 issue_ticket (tih);
1609}
1610
1611
1612/**
1613 * Issue a new reclaim ticket, thereby authorizing
1614 * the audience to access the set of provided attributes.
1615 *
1616 * @param identity the issuer
1617 * @param attrs the attributes to share
1618 * @param audience the audience to share the attributes with
1619 * @param cb the callback to call with the ticket result
1620 * @param cb_cls the callback closure
1621 * FIXME: Return handle??
1622 */
1623void
1624RECLAIM_TICKETS_issue (const struct GNUNET_IDENTITY_PrivateKey *identity,
1625 const struct GNUNET_RECLAIM_AttributeList *attrs,
1626 const struct GNUNET_IDENTITY_PublicKey *audience,
1627 RECLAIM_TICKETS_TicketResult cb,
1628 void *cb_cls)
1629{
1630 struct TicketIssueHandle *tih;
1631
1632 tih = GNUNET_new (struct TicketIssueHandle);
1633 tih->cb = cb;
1634 tih->cb_cls = cb_cls;
1635 tih->attrs = GNUNET_RECLAIM_attribute_list_dup (attrs);
1636 tih->presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1637 tih->identity = *identity;
1638 tih->ticket.audience = *audience;
1639
1640 // First check whether the ticket has already been issued
1641 tih->ns_it =
1642 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1643 &tih->identity,
1644 &filter_tickets_error_cb,
1645 tih,
1646 &filter_tickets_cb,
1647 tih,
1648 &filter_tickets_finished_cb,
1649 tih);
1650}
1651
1652
1653/************************************
1654 * Ticket iteration
1655 ************************************/
1656
1657/**
1658 * Cleanup ticket iterator
1659 *
1660 * @param iter handle to the iteration
1661 */
1662static void
1663cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1664{
1665 if (NULL != iter->ns_it)
1666 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1667 GNUNET_free (iter);
1668}
1669
1670
1671/**
1672 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1673 * to the caller and proceed with the iteration.
1674 * FIXME: Should we _not_ proceed automatically here?
1675 *
1676 * @param cls handle to the iteration
1677 * @param zone the ticket issuer
1678 * @param label the ticket rnd
1679 * @param rd_count number of records in record set
1680 * @param rd record set containing a ticket
1681 */
1682static void
1683collect_tickets_cb (void *cls,
1684 const struct GNUNET_IDENTITY_PrivateKey *zone,
1685 const char *label,
1686 unsigned int rd_count,
1687 const struct GNUNET_GNSRECORD_Data *rd)
1688{
1689 struct RECLAIM_TICKETS_Iterator *iter = cls;
1690
1691 for (int i = 0; i < rd_count; i++)
1692 {
1693 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1694 continue;
1695 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1696 return;
1697 }
1698 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1699}
1700
1701
1702/**
1703 * Signal ticket iteration has finished
1704 *
1705 * @param cls handle to the iteration
1706 */
1707static void
1708collect_tickets_finished_cb (void *cls)
1709{
1710 struct RECLAIM_TICKETS_Iterator *iter = cls;
1711
1712 iter->ns_it = NULL;
1713 iter->cb (iter->cb_cls, NULL);
1714 cleanup_iter (iter);
1715}
1716
1717
1718/**
1719 * Cancel ticket iteration on namestore error
1720 *
1721 * @param cls the iteration handle
1722 */
1723static void
1724collect_tickets_error_cb (void *cls)
1725{
1726 struct RECLAIM_TICKETS_Iterator *iter = cls;
1727
1728 iter->ns_it = NULL;
1729 iter->cb (iter->cb_cls, NULL);
1730 cleanup_iter (iter);
1731}
1732
1733
1734/**
1735 * Continue ticket iteration
1736 *
1737 * @param iter the iteration to continue
1738 */
1739void
1740RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1741{
1742 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1743}
1744
1745
1746/**
1747 * Stop a running ticket iteration
1748 *
1749 * @param iter iteration to cancel
1750 */
1751void
1752RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1753{
1754 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1755 cleanup_iter (iter);
1756}
1757
1758
1759/**
1760 * Iterate over all tickets issued by an identity
1761 *
1762 * @param identity the issuing identity
1763 * @param cb ticket callback function
1764 * @param cb_cls callback closure
1765 * @return a handle to the iteration
1766 */
1767struct RECLAIM_TICKETS_Iterator *
1768RECLAIM_TICKETS_iteration_start (
1769 const struct GNUNET_IDENTITY_PrivateKey *identity,
1770 RECLAIM_TICKETS_TicketIter cb,
1771 void *cb_cls)
1772{
1773 struct RECLAIM_TICKETS_Iterator *iter;
1774
1775 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1776 iter->cb = cb;
1777 iter->cb_cls = cb_cls;
1778 iter->ns_it =
1779 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1780 identity,
1781 &collect_tickets_error_cb,
1782 iter,
1783 &collect_tickets_cb,
1784 iter,
1785 &collect_tickets_finished_cb,
1786 iter);
1787 return iter;
1788}
1789
1790
1791/**
1792 * Initialize tickets component
1793 *
1794 * @param c the configuration
1795 * @return GNUNET_SYSERR on error
1796 */
1797int
1798RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1799{
1800 // Get ticket expiration time (relative) from config
1801 if (GNUNET_OK ==
1802 GNUNET_CONFIGURATION_get_value_time (c,
1803 "reclaim",
1804 "TICKET_REFRESH_INTERVAL",
1805 &ticket_refresh_interval))
1806 {
1807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1808 "Configured refresh interval for tickets: %s\n",
1809 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1810 GNUNET_YES));
1811 }
1812 else
1813 {
1814 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1815 }
1816 // Connect to identity and namestore services
1817 nsh = GNUNET_NAMESTORE_connect (c);
1818 if (NULL == nsh)
1819 {
1820 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1821 "error connecting to namestore");
1822 return GNUNET_SYSERR;
1823 }
1824 gns = GNUNET_GNS_connect (c);
1825 if (NULL == gns)
1826 {
1827 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1828 return GNUNET_SYSERR;
1829 }
1830 stats = GNUNET_STATISTICS_create ("reclaim", c);
1831 return GNUNET_OK;
1832}
1833
1834
1835/**
1836 * Close handles and clean up.
1837 * FIXME: cancel all pending operations (gns, ns etc)
1838 */
1839void
1840RECLAIM_TICKETS_deinit (void)
1841{
1842 if (NULL != nsh)
1843 GNUNET_NAMESTORE_disconnect (nsh);
1844 nsh = NULL;
1845 if (NULL != gns)
1846 GNUNET_GNS_disconnect (gns);
1847 gns = NULL;
1848 if (NULL != stats)
1849 {
1850 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1851 stats = NULL;
1852 }
1853}
diff --git a/src/reclaim/gnunet-service-reclaim_tickets.h b/src/reclaim/gnunet-service-reclaim_tickets.h
deleted file mode 100644
index 9c31a6143..000000000
--- a/src/reclaim/gnunet-service-reclaim_tickets.h
+++ /dev/null
@@ -1,280 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.h
24 * @brief reclaim tickets
25 *
26 */
27
28#ifndef GNUNET_SERVICE_RECLAIM_TICKETS_H
29#define GNUNET_SERVICE_RECLAIM_TICKETS_H
30
31#include "platform.h"
32
33#include "gnunet_util_lib.h"
34
35#include "gnunet_constants.h"
36#include "gnunet_gns_service.h"
37#include "gnunet_gnsrecord_lib.h"
38#include "gnunet_protocols.h"
39#include "gnunet_reclaim_lib.h"
40#include "gnunet_reclaim_service.h"
41#include "gnunet_signatures.h"
42#include "gnunet_statistics_service.h"
43#include "reclaim.h"
44
45/**
46 * Ticket iterator
47 */
48struct RECLAIM_TICKETS_Iterator;
49
50
51/**
52 * Handle to a consume operation
53 */
54struct RECLAIM_TICKETS_ConsumeHandle;
55
56
57/**
58 * Ticket revocation request handle
59 */
60struct RECLAIM_TICKETS_RevokeHandle;
61
62
63/**
64 * List of tickets
65 */
66struct TicketRecordsEntry
67{
68 /**
69 * DLL
70 */
71 struct TicketRecordsEntry *next;
72
73 /**
74 * DLL
75 */
76 struct TicketRecordsEntry *prev;
77
78 /**
79 * Record count
80 */
81 unsigned int rd_count;
82
83 /**
84 * Data
85 */
86 char *data;
87
88 /**
89 * Data size
90 */
91 size_t data_size;
92
93 /**
94 * Label
95 */
96 char *label;
97};
98
99
100/**
101 * Continuation called with ticket.
102 *
103 * @param cls closure
104 * @param ticket the ticket
105 */
106typedef void (*RECLAIM_TICKETS_TicketIter) (
107 void *cls,
108 struct GNUNET_RECLAIM_Ticket *ticket);
109
110
111/**
112 * Continuation called with ticket.
113 *
114 * @param cls closure
115 * @param ticket the ticket
116 * @param presentations new presentations for ticket (NULL on error)
117 * @param success #GNUNET_SYSERR on failure (including timeout/queue
118 * drop/failure to validate) #GNUNET_OK on success
119 * @param emsg NULL on success, otherwise an error message
120 */
121typedef void (*RECLAIM_TICKETS_TicketResult) (
122 void *cls,
123 struct GNUNET_RECLAIM_Ticket *ticket,
124 struct GNUNET_RECLAIM_PresentationList *presentations,
125 int32_t success,
126 const char *emsg);
127
128
129/**
130 * Consume callback.
131 *
132 * @param cls closure
133 * @param identity the issuer of the ticket/attributes
134 * @param attributes attribute list retrieved through ticket
135 * @param presentations attribute presentations (may be NULL)
136 * @param success GNUNET_OK on success
137 * @param emsg error message (NULL on success)
138 */
139typedef void (*RECLAIM_TICKETS_ConsumeCallback) (
140 void *cls,
141 const struct GNUNET_IDENTITY_PublicKey *identity,
142 const struct GNUNET_RECLAIM_AttributeList *attributes,
143 const struct GNUNET_RECLAIM_PresentationList *presentations,
144 int32_t success,
145 const char *emsg);
146
147
148/**
149 * Revocation callback.
150 *
151 * @param cls closure
152 * @param success GNUNET_OK on success
153 */
154typedef void (*RECLAIM_TICKETS_RevokeCallback) (void *cls, int32_t success);
155
156
157/**
158 * Revoke a ticket.
159 * We start by looking up attribute references in order
160 * to change attribute IDs.
161 *
162 * @param ticket ticket to revoke
163 * @param identity private key of issuer
164 * @param cb revocation status callback
165 * @param cb_cls callback closure
166 * @return handle to the operation
167 */
168struct RECLAIM_TICKETS_RevokeHandle *
169RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
170 const struct GNUNET_IDENTITY_PrivateKey *identity,
171 RECLAIM_TICKETS_RevokeCallback cb,
172 void *cb_cls);
173
174
175/**
176 * Cancel a revocation.
177 *
178 * @param rh handle to the operation
179 */
180void
181RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh);
182
183
184/**
185 * Consume a ticket.
186 * We first looking attribute references under the label
187 * ticket.rnd in GNS.
188 *
189 * @param id the audience of the ticket
190 * @param ticket the ticket to consume
191 * @param cb callback to call with attributes of ticket
192 * @param cb_cls callback closure
193 * @return handle to the operation
194 */
195struct RECLAIM_TICKETS_ConsumeHandle *
196RECLAIM_TICKETS_consume (const struct GNUNET_IDENTITY_PrivateKey *id,
197 const struct GNUNET_RECLAIM_Ticket *ticket,
198 RECLAIM_TICKETS_ConsumeCallback cb,
199 void *cb_cls);
200
201
202/**
203 * Cancel a consume operation
204 *
205 * @param cth the operation to cancel
206 */
207void
208RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth);
209
210
211/**
212 * Issue a new reclaim ticket, thereby authorizing
213 * the audience to access the set of provided attributes.
214 *
215 * @param identity the issuer
216 * @param attrs the attributes to share
217 * @param audience the audience to share the attributes with
218 * @param cb the callback to call with the ticket result
219 * @param cb_cls the callback closure
220 * FIXME: Return handle??
221 */
222void
223RECLAIM_TICKETS_issue (const struct GNUNET_IDENTITY_PrivateKey *identity,
224 const struct GNUNET_RECLAIM_AttributeList *attrs,
225 const struct GNUNET_IDENTITY_PublicKey *audience,
226 RECLAIM_TICKETS_TicketResult cb,
227 void *cb_cls);
228
229
230/**
231 * Continue ticket iteration
232 *
233 * @param iter the iteration to continue
234 */
235void
236RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter);
237
238
239/**
240 * Stop a running ticket iteration
241 *
242 * @param iter iteration to cancel
243 */
244void
245RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter);
246
247
248/**
249 * Iterate over all tickets issued by an identity
250 *
251 * @param identity the issuing identity
252 * @param cb ticket callback function
253 * @param cb_cls callback closure
254 * @return a handle to the iteration
255 */
256struct RECLAIM_TICKETS_Iterator *
257RECLAIM_TICKETS_iteration_start (
258 const struct GNUNET_IDENTITY_PrivateKey *identity,
259 RECLAIM_TICKETS_TicketIter cb,
260 void *cb_cls);
261
262
263/**
264 * Initialize tickets component
265 *
266 * @param c the configuration
267 * @return GNUNET_SYSERR on error
268 */
269int
270RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c);
271
272
273/**
274 * Close handles and clean up.
275 * FIXME: cancel all pending operations (gns, ns etc)
276 */
277void
278RECLAIM_TICKETS_deinit (void);
279
280#endif
diff --git a/src/reclaim/json_reclaim.c b/src/reclaim/json_reclaim.c
deleted file mode 100644
index b1ca7a4a5..000000000
--- a/src/reclaim/json_reclaim.c
+++ /dev/null
@@ -1,398 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2018 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 rest-plugins/json_reclaim.c
23 * @brief JSON handling of reclaim data
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_json_lib.h"
29#include "gnunet_reclaim_lib.h"
30#include "gnunet_reclaim_service.h"
31
32
33/**
34 * Parse given JSON object to a claim
35 *
36 * @param cls closure, NULL
37 * @param root the json object representing data
38 * @param spec where to write the data
39 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
40 */
41static int
42parse_attr (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec)
43{
44 struct GNUNET_RECLAIM_Attribute *attr;
45 const char *name_str = NULL;
46 const char *val_str = NULL;
47 const char *type_str = NULL;
48 const char *id_str = NULL;
49 const char *cred_str = NULL;
50 const char *flag_str = NULL;
51 char *data;
52 int unpack_state;
53 uint32_t type;
54 size_t data_size;
55
56 GNUNET_assert (NULL != root);
57
58 if (! json_is_object (root))
59 {
60 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
61 "Error json is not array nor object!\n");
62 return GNUNET_SYSERR;
63 }
64 // interpret single attribute
65 unpack_state = json_unpack (root,
66 "{s:s, s?s, s?s, s:s, s:s, s?s!}",
67 "name",
68 &name_str,
69 "id",
70 &id_str,
71 "credential",
72 &cred_str,
73 "type",
74 &type_str,
75 "value",
76 &val_str,
77 "flag",
78 &flag_str);
79 if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_str) ||
80 (NULL == type_str))
81 {
82 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
83 "Error json object has a wrong format!\n");
84 return GNUNET_SYSERR;
85 }
86 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
87 if (GNUNET_SYSERR ==
88 (GNUNET_RECLAIM_attribute_string_to_value (type,
89 val_str,
90 (void **) &data,
91 &data_size)))
92 {
93 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute value invalid!\n");
94 return GNUNET_SYSERR;
95 }
96 attr = GNUNET_RECLAIM_attribute_new (name_str, NULL,
97 type, data, data_size);
98 GNUNET_free (data);
99 if ((NULL != cred_str) && (0 != strlen (cred_str)))
100 {
101 GNUNET_STRINGS_string_to_data (cred_str,
102 strlen (cred_str),
103 &attr->credential,
104 sizeof(attr->credential));
105 }
106 if ((NULL == id_str) || (0 == strlen (id_str)))
107 memset (&attr->id, 0, sizeof (attr->id));
108 else
109 GNUNET_STRINGS_string_to_data (id_str,
110 strlen (id_str),
111 &attr->id,
112 sizeof(attr->id));
113
114 *(struct GNUNET_RECLAIM_Attribute **) spec->ptr = attr;
115 return GNUNET_OK;
116}
117
118
119/**
120 * Cleanup data left from parsing RSA public key.
121 *
122 * @param cls closure, NULL
123 * @param[out] spec where to free the data
124 */
125static void
126clean_attr (void *cls, struct GNUNET_JSON_Specification *spec)
127{
128 struct GNUNET_RECLAIM_Attribute **attr;
129
130 attr = (struct GNUNET_RECLAIM_Attribute **) spec->ptr;
131 if (NULL != *attr)
132 {
133 GNUNET_free (*attr);
134 *attr = NULL;
135 }
136}
137
138
139/**
140 * JSON Specification for Reclaim claims.
141 *
142 * @param ticket struct of GNUNET_RECLAIM_Attribute to fill
143 * @return JSON Specification
144 */
145struct GNUNET_JSON_Specification
146GNUNET_RECLAIM_JSON_spec_attribute (struct GNUNET_RECLAIM_Attribute **attr)
147{
148 struct GNUNET_JSON_Specification ret = { .parser = &parse_attr,
149 .cleaner = &clean_attr,
150 .cls = NULL,
151 .field = NULL,
152 .ptr = attr,
153 .ptr_size = 0,
154 .size_ptr = NULL };
155
156 *attr = NULL;
157 return ret;
158}
159
160
161/**
162 * Parse given JSON object to a ticket
163 *
164 * @param cls closure, NULL
165 * @param root the json object representing data
166 * @param spec where to write the data
167 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
168 */
169static int
170parse_ticket (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec)
171{
172 struct GNUNET_RECLAIM_Ticket *ticket;
173 const char *rnd_str;
174 const char *aud_str;
175 const char *id_str;
176 int unpack_state;
177
178 GNUNET_assert (NULL != root);
179
180 if (! json_is_object (root))
181 {
182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
183 "Error json is not array nor object!\n");
184 return GNUNET_SYSERR;
185 }
186 // interpret single ticket
187 unpack_state = json_unpack (root,
188 "{s:s, s:s, s:s!}",
189 "rnd",
190 &rnd_str,
191 "audience",
192 &aud_str,
193 "issuer",
194 &id_str);
195 if (0 != unpack_state)
196 {
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198 "Error json object has a wrong format!\n");
199 return GNUNET_SYSERR;
200 }
201 ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
202 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (rnd_str,
203 strlen (rnd_str),
204 &ticket->rnd,
205 sizeof(ticket->rnd)))
206 {
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Rnd invalid\n");
208 GNUNET_free (ticket);
209 return GNUNET_SYSERR;
210 }
211 if (GNUNET_OK !=
212 GNUNET_STRINGS_string_to_data (id_str,
213 strlen (id_str),
214 &ticket->identity,
215 sizeof(ticket->identity)))
216 {
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Identity invalid\n");
218 GNUNET_free (ticket);
219 return GNUNET_SYSERR;
220 }
221
222 if (GNUNET_OK !=
223 GNUNET_STRINGS_string_to_data (aud_str,
224 strlen (aud_str),
225 &ticket->audience,
226 sizeof(ticket->audience)))
227 {
228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience invalid\n");
229 GNUNET_free (ticket);
230 return GNUNET_SYSERR;
231 }
232
233 *(struct GNUNET_RECLAIM_Ticket **) spec->ptr = ticket;
234 return GNUNET_OK;
235}
236
237
238/**
239 * Cleanup data left from parsing RSA public key.
240 *
241 * @param cls closure, NULL
242 * @param[out] spec where to free the data
243 */
244static void
245clean_ticket (void *cls, struct GNUNET_JSON_Specification *spec)
246{
247 struct GNUNET_RECLAIM_Ticket **ticket;
248
249 ticket = (struct GNUNET_RECLAIM_Ticket **) spec->ptr;
250 if (NULL != *ticket)
251 {
252 GNUNET_free (*ticket);
253 *ticket = NULL;
254 }
255}
256
257
258/**
259 * JSON Specification for Reclaim tickets.
260 *
261 * @param ticket struct of GNUNET_RECLAIM_Ticket to fill
262 * @return JSON Specification
263 */
264struct GNUNET_JSON_Specification
265GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket)
266{
267 struct GNUNET_JSON_Specification ret = { .parser = &parse_ticket,
268 .cleaner = &clean_ticket,
269 .cls = NULL,
270 .field = NULL,
271 .ptr = ticket,
272 .ptr_size = 0,
273 .size_ptr = NULL };
274
275 *ticket = NULL;
276 return ret;
277}
278
279
280/**
281 * Parse given JSON object to a credential claim
282 *
283 * @param cls closure, NULL
284 * @param root the json object representing data
285 * @param spec where to write the data
286 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
287 */
288static int
289parse_credential (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec)
290{
291 struct GNUNET_RECLAIM_Credential *cred;
292 const char *name_str = NULL;
293 const char *type_str = NULL;
294 const char *id_str = NULL;
295 json_t *val_json;
296 char *data = NULL;
297 char *val_str = NULL;
298 int unpack_state;
299 uint32_t type;
300 size_t data_size;
301
302 GNUNET_assert (NULL != root);
303
304 if (! json_is_object (root))
305 {
306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 "Error json is not array nor object!\n");
308 return GNUNET_SYSERR;
309 }
310 // interpret single attribute
311 unpack_state = json_unpack (root,
312 "{s:s, s?s, s:s, s:o!}",
313 "name",
314 &name_str,
315 "id",
316 &id_str,
317 "type",
318 &type_str,
319 "value",
320 &val_json);
321 if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_json) ||
322 (NULL == type_str))
323 {
324 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
325 "Error json object has a wrong format!\n");
326 return GNUNET_SYSERR;
327 }
328 if (json_is_string (val_json)) {
329 val_str = GNUNET_strdup (json_string_value (val_json));
330 } else {
331 val_str = json_dumps (val_json, JSON_COMPACT);
332 }
333 type = GNUNET_RECLAIM_credential_typename_to_number (type_str);
334 if (GNUNET_SYSERR ==
335 (GNUNET_RECLAIM_credential_string_to_value (type,
336 val_str,
337 (void **) &data,
338 &data_size)))
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Credential value invalid!\n");
341 return GNUNET_SYSERR;
342 }
343 cred = GNUNET_RECLAIM_credential_new (name_str, type, data, data_size);
344 GNUNET_free (data);
345 if ((NULL == id_str) || (0 == strlen (id_str)))
346 memset (&cred->id, 0, sizeof (cred->id));
347 else
348 GNUNET_STRINGS_string_to_data (id_str,
349 strlen (id_str),
350 &cred->id,
351 sizeof(cred->id));
352
353 *(struct GNUNET_RECLAIM_Credential **) spec->ptr = cred;
354 return GNUNET_OK;
355}
356
357
358/**
359 * Cleanup data left from parsing RSA public key.
360 *
361 * @param cls closure, NULL
362 * @param[out] spec where to free the data
363 */
364static void
365clean_credential (void *cls, struct GNUNET_JSON_Specification *spec)
366{
367 struct GNUNET_RECLAIM_Credential **attr;
368
369 attr = (struct GNUNET_RECLAIM_Credential **) spec->ptr;
370 if (NULL != *attr)
371 {
372 GNUNET_free (*attr);
373 *attr = NULL;
374 }
375}
376
377
378/**
379 * JSON Specification for credential claims.
380 *
381 * @param attr struct of GNUNET_RECLAIM_Credential to fill
382 * @return JSON Specification
383 */
384struct GNUNET_JSON_Specification
385GNUNET_RECLAIM_JSON_spec_credential (struct
386 GNUNET_RECLAIM_Credential **cred)
387{
388 struct GNUNET_JSON_Specification ret = { .parser = &parse_credential,
389 .cleaner = &clean_credential,
390 .cls = NULL,
391 .field = NULL,
392 .ptr = cred,
393 .ptr_size = 0,
394 .size_ptr = NULL };
395
396 *cred = NULL;
397 return ret;
398}
diff --git a/src/reclaim/json_reclaim.h b/src/reclaim/json_reclaim.h
deleted file mode 100644
index 613ddf873..000000000
--- a/src/reclaim/json_reclaim.h
+++ /dev/null
@@ -1,57 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2018 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 rest-plugins/json_reclaim.h
23 * @brief JSON handling of reclaim data
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_json_lib.h"
29#include "gnunet_reclaim_service.h"
30#include "gnunet_reclaim_lib.h"
31
32/**
33 * JSON Specification for Reclaim claims.
34 *
35 * @param attr struct of GNUNET_RECLAIM_Attribute to fill
36 * @return JSON Specification
37 */
38struct GNUNET_JSON_Specification
39GNUNET_RECLAIM_JSON_spec_attribute (struct GNUNET_RECLAIM_Attribute **attr);
40
41/**
42 * JSON Specification for Reclaim tickets.
43 *
44 * @param ticket struct of GNUNET_RECLAIM_Ticket to fill
45 * @return JSON Specification
46 */
47struct GNUNET_JSON_Specification
48GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket);
49
50/**
51 * JSON Specification for credentials.
52 *
53 * @param cred struct of GNUNET_RECLAIM_Credential to fill
54 * @return JSON Specification
55 */
56struct GNUNET_JSON_Specification
57GNUNET_RECLAIM_JSON_spec_credential (struct GNUNET_RECLAIM_Credential **cred);
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c
deleted file mode 100644
index 9237902ce..000000000
--- a/src/reclaim/oidc_helper.c
+++ /dev/null
@@ -1,934 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 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 reclaim/oidc_helper.c
23 * @brief helper library for OIDC related functions
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include <inttypes.h>
28#include <jansson.h>
29#include "gnunet_util_lib.h"
30#include "gnunet_reclaim_lib.h"
31#include "gnunet_reclaim_service.h"
32#include "gnunet_signatures.h"
33#include "oidc_helper.h"
34// #include "benchmark.h"
35#include <gcrypt.h>
36
37GNUNET_NETWORK_STRUCT_BEGIN
38
39/**
40 * The signature used to generate the authorization code
41 */
42struct OIDC_Parameters
43{
44 /**
45 * The reclaim ticket
46 */
47 struct GNUNET_RECLAIM_Ticket ticket;
48
49 /**
50 * The nonce length
51 */
52 uint32_t nonce_len GNUNET_PACKED;
53
54 /**
55 * The length of the PKCE code_challenge
56 */
57 uint32_t code_challenge_len GNUNET_PACKED;
58
59 /**
60 * The length of the attributes list
61 */
62 uint32_t attr_list_len GNUNET_PACKED;
63
64 /**
65 * The length of the presentation list
66 */
67 uint32_t pres_list_len GNUNET_PACKED;
68};
69
70GNUNET_NETWORK_STRUCT_END
71
72/**
73 * Standard claims represented by the "profile" scope in OIDC
74 */
75static char OIDC_profile_claims[14][32] = {
76 "name", "family_name", "given_name", "middle_name", "nickname",
77 "preferred_username", "profile", "picture", "website", "gender", "birthdate",
78 "zoneinfo", "locale", "updated_at"
79};
80
81/**
82 * Standard claims represented by the "email" scope in OIDC
83 */
84static char OIDC_email_claims[2][16] = {
85 "email", "email_verified"
86};
87
88/**
89 * Standard claims represented by the "phone" scope in OIDC
90 */
91static char OIDC_phone_claims[2][32] = {
92 "phone_number", "phone_number_verified"
93};
94
95/**
96 * Standard claims represented by the "address" scope in OIDC
97 */
98static char OIDC_address_claims[5][32] = {
99 "street_address", "locality", "region", "postal_code", "country"
100};
101
102static enum GNUNET_GenericReturnValue
103is_claim_in_address_scope (const char *claim)
104{
105 int i;
106 for (i = 0; i < 5; i++)
107 {
108 if (0 == strcmp (claim, OIDC_address_claims[i]))
109 {
110 return GNUNET_YES;
111 }
112 }
113 return GNUNET_NO;
114}
115
116
117static char *
118create_jwt_header (void)
119{
120 json_t *root;
121 char *json_str;
122
123 root = json_object ();
124 json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
125 json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
126
127 json_str = json_dumps (root, JSON_INDENT (0) | JSON_COMPACT);
128 json_decref (root);
129 return json_str;
130}
131
132
133static void
134replace_char (char *str, char find, char replace)
135{
136 char *current_pos = strchr (str, find);
137
138 while (current_pos)
139 {
140 *current_pos = replace;
141 current_pos = strchr (current_pos, find);
142 }
143}
144
145
146// RFC4648
147static void
148fix_base64 (char *str)
149{
150 // Replace + with -
151 replace_char (str, '+', '-');
152
153 // Replace / with _
154 replace_char (str, '/', '_');
155}
156
157
158static json_t*
159generate_userinfo_json (const struct GNUNET_IDENTITY_PublicKey *sub_key,
160 const struct GNUNET_RECLAIM_AttributeList *attrs,
161 const struct
162 GNUNET_RECLAIM_PresentationList *presentations)
163{
164 struct GNUNET_RECLAIM_AttributeListEntry *le;
165 struct GNUNET_RECLAIM_PresentationListEntry *ple;
166 char *subject;
167 char *source_name;
168 char *attr_val_str;
169 char *pres_val_str;
170 json_t *body;
171 json_t *aggr_names;
172 json_t *aggr_sources;
173 json_t *aggr_sources_jwt;
174 json_t *addr_claim = NULL;
175 int num_presentations = 0;
176 for (le = attrs->list_head; NULL != le; le = le->next)
177 {
178 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
179 num_presentations++;
180 }
181
182 subject =
183 GNUNET_STRINGS_data_to_string_alloc (sub_key,
184 sizeof(struct
185 GNUNET_IDENTITY_PublicKey));
186 body = json_object ();
187 aggr_names = json_object ();
188 aggr_sources = json_object ();
189
190 // iss REQUIRED case sensitive server uri with https
191 // The issuer is the local reclaim instance (e.g.
192 // https://reclaim.id/api/openid)
193 json_object_set_new (body, "iss", json_string (SERVER_ADDRESS));
194 // sub REQUIRED public key identity, not exceed 255 ASCII length
195 json_object_set_new (body, "sub", json_string (subject));
196 GNUNET_free (subject);
197 pres_val_str = NULL;
198 source_name = NULL;
199 int i = 0;
200 for (ple = presentations->list_head; NULL != ple; ple = ple->next)
201 {
202 // New presentation
203 GNUNET_asprintf (&source_name,
204 "src%d",
205 i);
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "Adding new presentation source #%d\n", i);
208 aggr_sources_jwt = json_object ();
209 pres_val_str =
210 GNUNET_RECLAIM_presentation_value_to_string (ple->presentation->type,
211 ple->presentation->data,
212 ple->presentation->data_size);
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Presentation is: %s\n", pres_val_str);
215 json_object_set_new (aggr_sources_jwt,
216 GNUNET_RECLAIM_presentation_number_to_typename (
217 ple->presentation->type),
218 json_string (pres_val_str) );
219 json_object_set_new (aggr_sources, source_name, aggr_sources_jwt);
220 GNUNET_free (pres_val_str);
221 GNUNET_free (source_name);
222 source_name = NULL;
223 i++;
224 }
225
226 int addr_is_aggregated = GNUNET_NO;
227 int addr_is_normal = GNUNET_NO;
228 for (le = attrs->list_head; NULL != le; le = le->next)
229 {
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Processing %s for userinfo body\n",
232 le->attribute->name);
233 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
234 {
235 attr_val_str =
236 GNUNET_RECLAIM_attribute_value_to_string (le->attribute->type,
237 le->attribute->data,
238 le->attribute->data_size);
239 /**
240 * There is this weird quirk that the individual address claim(s) must be
241 * inside a JSON object of the "address" claim.
242 */
243 if (GNUNET_YES == is_claim_in_address_scope (le->attribute->name))
244 {
245 if (GNUNET_YES == addr_is_aggregated)
246 {
247 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
248 "Address is set as aggregated claim. Skipping self-issued value...\n");
249 GNUNET_free (attr_val_str);
250 continue;
251 }
252 addr_is_normal = GNUNET_YES;
253
254 if (NULL == addr_claim)
255 {
256 addr_claim = json_object ();
257 json_object_set_new (body, "address", addr_claim);
258 }
259 json_object_set_new (addr_claim, le->attribute->name,
260 json_string (attr_val_str));
261
262 }
263 else
264 {
265 json_object_set_new (body, le->attribute->name,
266 json_string (attr_val_str));
267 }
268 GNUNET_free (attr_val_str);
269 }
270 else
271 {
272 // Check if presentation is there
273 int j = 0;
274 for (ple = presentations->list_head; NULL != ple; ple = ple->next)
275 {
276 if (GNUNET_YES ==
277 GNUNET_RECLAIM_id_is_equal (&ple->presentation->credential_id,
278 &le->attribute->credential))
279 break;
280 j++;
281 }
282 if (NULL == ple)
283 {
284 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
285 "Presentation for `%s' missing...\n",
286 le->attribute->name);
287 continue;
288 }
289 /**
290 * There is this weird quirk that the individual address claim(s) must be
291 * inside a JSON object of the "address" claim.
292 */
293 if (GNUNET_YES == is_claim_in_address_scope (le->attribute->name))
294 {
295 if (GNUNET_YES == addr_is_normal)
296 {
297 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
298 "Address is already set as normal claim. Skipping attested value...\n");
299 continue;
300 }
301 addr_is_aggregated = GNUNET_YES;
302 /** This is/can only be set once! **/
303 if (NULL != addr_claim)
304 continue;
305 addr_claim = json_object ();
306 GNUNET_asprintf (&source_name,
307 "src%d",
308 j);
309 json_object_set_new (aggr_names, "address",
310 json_string (source_name));
311 GNUNET_free (source_name);
312 }
313 else
314 {
315 // Presentation exists, hence take the respective source str
316 GNUNET_asprintf (&source_name,
317 "src%d",
318 j);
319 json_object_set_new (aggr_names, le->attribute->name,
320 json_string (source_name));
321 GNUNET_free (source_name);
322 }
323 }
324 }
325 if (0 != i)
326 {
327 json_object_set_new (body, "_claim_names", aggr_names);
328 json_object_set_new (body, "_claim_sources", aggr_sources);
329 }
330
331 return body;
332}
333
334
335/**
336 * Generate userinfo JSON as string
337 *
338 * @param sub_key the subject (user)
339 * @param attrs user attribute list
340 * @param presentations credential presentation list (may be empty)
341 * @return Userinfo JSON
342 */
343char *
344OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key,
345 const struct GNUNET_RECLAIM_AttributeList *attrs,
346 const struct
347 GNUNET_RECLAIM_PresentationList *presentations)
348{
349 char *body_str;
350 json_t*body = generate_userinfo_json (sub_key,
351 attrs,
352 presentations);
353 body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
354 json_decref (body);
355 return body_str;
356}
357
358
359/**
360 * Create a JWT from attributes
361 *
362 * @param aud_key the public of the audience
363 * @param sub_key the public key of the subject
364 * @param attrs the attribute list
365 * @param presentations credential presentation list (may be empty)
366 * @param expiration_time the validity of the token
367 * @param secret_key the key used to sign the JWT
368 * @return a new base64-encoded JWT string.
369 */
370char *
371OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key,
372 const struct GNUNET_IDENTITY_PublicKey *sub_key,
373 const struct GNUNET_RECLAIM_AttributeList *attrs,
374 const struct
375 GNUNET_RECLAIM_PresentationList *presentations,
376 const struct GNUNET_TIME_Relative *expiration_time,
377 const char *nonce,
378 const char *secret_key)
379{
380 struct GNUNET_HashCode signature;
381 struct GNUNET_TIME_Absolute exp_time;
382 struct GNUNET_TIME_Absolute time_now;
383 char *audience;
384 char *subject;
385 char *header;
386 char *body_str;
387 char *result;
388 char *header_base64;
389 char *body_base64;
390 char *signature_target;
391 char *signature_base64;
392 json_t *body;
393
394 body = generate_userinfo_json (sub_key,
395 attrs,
396 presentations);
397 // iat REQUIRED time now
398 time_now = GNUNET_TIME_absolute_get ();
399 // exp REQUIRED time expired from config
400 exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time);
401 // auth_time only if max_age
402 // nonce only if nonce
403 // OPTIONAL acr,amr,azp
404 subject =
405 GNUNET_STRINGS_data_to_string_alloc (sub_key,
406 sizeof(struct
407 GNUNET_IDENTITY_PublicKey));
408 audience =
409 GNUNET_STRINGS_data_to_string_alloc (aud_key,
410 sizeof(struct
411 GNUNET_IDENTITY_PublicKey));
412 header = create_jwt_header ();
413
414 // aud REQUIRED public key client_id must be there
415 json_object_set_new (body, "aud", json_string (audience));
416 // iat
417 json_object_set_new (body,
418 "iat",
419 json_integer (time_now.abs_value_us / (1000 * 1000)));
420 // exp
421 json_object_set_new (body,
422 "exp",
423 json_integer (exp_time.abs_value_us / (1000 * 1000)));
424 // nbf
425 json_object_set_new (body,
426 "nbf",
427 json_integer (time_now.abs_value_us / (1000 * 1000)));
428 // nonce
429 if (NULL != nonce)
430 json_object_set_new (body, "nonce", json_string (nonce));
431
432 body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT);
433 json_decref (body);
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str);
435
436 GNUNET_STRINGS_base64url_encode (header, strlen (header), &header_base64);
437 fix_base64 (header_base64);
438
439 GNUNET_STRINGS_base64url_encode (body_str, strlen (body_str), &body_base64);
440 fix_base64 (body_base64);
441
442 GNUNET_free (subject);
443 GNUNET_free (audience);
444
445 /**
446 * Creating the JWT signature. This might not be
447 * standards compliant, check.
448 */
449 GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
450 GNUNET_CRYPTO_hmac_raw (secret_key,
451 strlen (secret_key),
452 signature_target,
453 strlen (signature_target),
454 &signature);
455 GNUNET_STRINGS_base64url_encode ((const char *) &signature,
456 sizeof(struct GNUNET_HashCode),
457 &signature_base64);
458 fix_base64 (signature_base64);
459
460 GNUNET_asprintf (&result,
461 "%s.%s.%s",
462 header_base64,
463 body_base64,
464 signature_base64);
465
466 GNUNET_free (signature_target);
467 GNUNET_free (header);
468 GNUNET_free (body_str);
469 GNUNET_free (signature_base64);
470 GNUNET_free (body_base64);
471 GNUNET_free (header_base64);
472 return result;
473}
474
475
476/**
477 * Builds an OIDC authorization code including
478 * a reclaim ticket and nonce
479 *
480 * @param issuer the issuer of the ticket, used to sign the ticket and nonce
481 * @param ticket the ticket to include in the code
482 * @param attrs list of attributes which are shared
483 * @param presentations credential presentation list (may be empty)
484 * @param nonce the nonce to include in the code
485 * @param code_challenge PKCE code challenge
486 * @return a new authorization code (caller must free)
487 */
488char *
489OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer,
490 const struct GNUNET_RECLAIM_Ticket *ticket,
491 const struct GNUNET_RECLAIM_AttributeList *attrs,
492 const struct
493 GNUNET_RECLAIM_PresentationList *presentations,
494 const char *nonce_str,
495 const char *code_challenge)
496{
497 struct OIDC_Parameters params;
498 char *code_payload;
499 char *payload;
500 char *tmp;
501 char *code_str;
502 char *buf_ptr = NULL;
503 size_t payload_len;
504 size_t code_payload_len;
505 size_t attr_list_len = 0;
506 size_t pres_list_len = 0;
507 size_t code_challenge_len = 0;
508 uint32_t nonce_len = 0;
509 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
510
511 /** PLAINTEXT **/
512 // Assign ticket
513 memset (&params, 0, sizeof(params));
514 params.ticket = *ticket;
515 // Assign nonce
516 payload_len = sizeof(struct OIDC_Parameters);
517 if ((NULL != nonce_str) && (strcmp ("", nonce_str) != 0))
518 {
519 nonce_len = strlen (nonce_str);
520 payload_len += nonce_len;
521 }
522 params.nonce_len = htonl (nonce_len);
523 // Assign code challenge
524 if (NULL != code_challenge)
525 code_challenge_len = strlen (code_challenge);
526 payload_len += code_challenge_len;
527 params.code_challenge_len = htonl (code_challenge_len);
528 // Assign attributes
529 if (NULL != attrs)
530 {
531 // Get length
532 attr_list_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
533 params.attr_list_len = htonl (attr_list_len);
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535 "Length of serialized attributes: %lu\n",
536 attr_list_len);
537 // Get serialized attributes
538 payload_len += attr_list_len;
539 }
540 if (NULL != presentations)
541 {
542 // Get length
543 // FIXME only add presentations relevant for attribute list!!!
544 // This is important because of the distinction between id_token and
545 // userinfo in OIDC
546 pres_list_len =
547 GNUNET_RECLAIM_presentation_list_serialize_get_size (presentations);
548 params.pres_list_len = htonl (pres_list_len);
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Length of serialized presentations: %lu\n",
551 pres_list_len);
552 // Get serialized attributes
553 payload_len += pres_list_len;
554 }
555
556 // Get plaintext length
557 payload = GNUNET_malloc (payload_len);
558 memcpy (payload, &params, sizeof(params));
559 tmp = payload + sizeof(params);
560 if (0 < code_challenge_len)
561 {
562 memcpy (tmp, code_challenge, code_challenge_len);
563 tmp += code_challenge_len;
564 }
565 if (0 < nonce_len)
566 {
567 memcpy (tmp, nonce_str, nonce_len);
568 tmp += nonce_len;
569 }
570 if (0 < attr_list_len)
571 GNUNET_RECLAIM_attribute_list_serialize (attrs, tmp);
572 tmp += attr_list_len;
573 if (0 < pres_list_len)
574 GNUNET_RECLAIM_presentation_list_serialize (presentations, tmp);
575 tmp += pres_list_len;
576
577 /** END **/
578
579 // Get length
580 code_payload_len = sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
581 + payload_len + sizeof(struct
582 GNUNET_IDENTITY_Signature);
583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
584 "Length of data to encode: %lu\n",
585 code_payload_len);
586
587 // Initialize code payload
588 code_payload = GNUNET_malloc (code_payload_len);
589 GNUNET_assert (NULL != code_payload);
590 purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
591 purpose->size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
592 + payload_len);
593 purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
594 // Store pubkey
595 buf_ptr = (char *) &purpose[1];
596 memcpy (buf_ptr, payload, payload_len);
597 GNUNET_free (payload);
598 buf_ptr += payload_len;
599 // Sign and store signature
600 if (GNUNET_SYSERR ==
601 GNUNET_IDENTITY_sign_ (issuer,
602 purpose,
603 (struct GNUNET_IDENTITY_Signature *)
604 buf_ptr))
605 {
606 GNUNET_break (0);
607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to sign code\n");
608 GNUNET_free (code_payload);
609 return NULL;
610 }
611 GNUNET_STRINGS_base64url_encode (code_payload, code_payload_len, &code_str);
612 GNUNET_free (code_payload);
613 return code_str;
614}
615
616
617enum GNUNET_GenericReturnValue
618check_code_challenge (const char *code_challenge,
619 uint32_t code_challenge_len,
620 const char *code_verifier)
621{
622 char *code_verifier_hash;
623 char *expected_code_challenge;
624
625 if (0 == code_challenge_len) /* Only check if this code requires a CV */
626 return GNUNET_OK;
627 if (NULL == code_verifier)
628 {
629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630 "Expected code verifier!\n");
631 return GNUNET_SYSERR;
632 }
633 code_verifier_hash = GNUNET_malloc (256 / 8);
634 // hash code verifier
635 gcry_md_hash_buffer (GCRY_MD_SHA256,
636 code_verifier_hash,
637 code_verifier,
638 strlen (code_verifier));
639 // encode code verifier
640 GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8,
641 &expected_code_challenge);
642 GNUNET_free (code_verifier_hash);
643 if (0 !=
644 strncmp (expected_code_challenge, code_challenge, code_challenge_len))
645 {
646 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
647 "Invalid code verifier! Expected: %s, Got: %.*s\n",
648 expected_code_challenge,
649 code_challenge_len,
650 code_challenge);
651 GNUNET_free (expected_code_challenge);
652 return GNUNET_SYSERR;
653 }
654 GNUNET_free (expected_code_challenge);
655 return GNUNET_OK;
656}
657
658
659/**
660 * Parse reclaim ticket and nonce from
661 * authorization code.
662 * This also verifies the signature in the code.
663 *
664 * @param audience the expected audience of the code
665 * @param code the string representation of the code
666 * @param code_verfier PKCE code verifier. Optional, must be provided
667 * if used in request.
668 * @param ticket where to store the ticket
669 * @param attrs the attributes in the code
670 * @param presentations credential presentation list
671 * @param nonce_str where to store the nonce (if contained)
672 * @return GNUNET_OK if successful, else GNUNET_SYSERR
673 */
674int
675OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *audience,
676 const char *code,
677 const char *code_verifier,
678 struct GNUNET_RECLAIM_Ticket *ticket,
679 struct GNUNET_RECLAIM_AttributeList **attrs,
680 struct GNUNET_RECLAIM_PresentationList **presentations,
681 char **nonce_str,
682 enum OIDC_VerificationOptions opts)
683{
684 char *code_payload;
685 char *ptr;
686 char *plaintext;
687 char *attrs_ser;
688 char *presentations_ser;
689 char *code_challenge;
690 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
691 struct GNUNET_IDENTITY_Signature *signature;
692 uint32_t code_challenge_len;
693 uint32_t attrs_ser_len;
694 uint32_t pres_ser_len;
695 size_t plaintext_len;
696 size_t code_payload_len;
697 uint32_t nonce_len = 0;
698 struct OIDC_Parameters *params;
699
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to decode `%s'\n", code);
701 code_payload = NULL;
702 code_payload_len =
703 GNUNET_STRINGS_base64url_decode (code, strlen (code),
704 (void **) &code_payload);
705 if (code_payload_len < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
706 + sizeof(struct OIDC_Parameters)
707 + sizeof(struct GNUNET_IDENTITY_Signature))
708 {
709 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Authorization code malformed\n");
710 GNUNET_free (code_payload);
711 return GNUNET_SYSERR;
712 }
713
714 purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) code_payload;
715 plaintext_len = code_payload_len;
716 plaintext_len -= sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose);
717 ptr = (char *) &purpose[1];
718 plaintext_len -= sizeof(struct GNUNET_IDENTITY_Signature);
719 plaintext = ptr;
720 ptr += plaintext_len;
721 signature = (struct GNUNET_IDENTITY_Signature *) ptr;
722 params = (struct OIDC_Parameters *) plaintext;
723
724 // cmp code_challenge code_verifier
725 code_challenge_len = ntohl (params->code_challenge_len);
726 code_challenge = ((char *) &params[1]);
727 if (! (opts & OIDC_VERIFICATION_NO_CODE_VERIFIER))
728 {
729 if (GNUNET_OK != check_code_challenge (code_challenge,
730 code_challenge_len,
731 code_verifier))
732 {
733 GNUNET_free (code_payload);
734 return GNUNET_SYSERR;
735 }
736 }
737 nonce_len = ntohl (params->nonce_len);
738 if (0 != nonce_len)
739 {
740 *nonce_str = GNUNET_strndup (code_challenge + code_challenge_len,
741 nonce_len);
742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got nonce: %s\n", *nonce_str);
743 }
744
745 // Ticket
746 memcpy (ticket, &params->ticket, sizeof(params->ticket));
747 // Signature
748 // GNUNET_CRYPTO_ecdsa_key_get_public (ecdsa_priv, &ecdsa_pub);
749 if (0 != GNUNET_memcmp (audience, &ticket->audience))
750 {
751 GNUNET_free (code_payload);
752 if (NULL != *nonce_str)
753 GNUNET_free (*nonce_str);
754 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
755 "Audience in ticket does not match client!\n");
756 return GNUNET_SYSERR;
757 }
758 if (GNUNET_OK !=
759 GNUNET_IDENTITY_signature_verify_ (
760 GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
761 purpose,
762 signature,
763 &(ticket->identity)))
764 {
765 GNUNET_free (code_payload);
766 if (NULL != *nonce_str)
767 GNUNET_free (*nonce_str);
768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signature of AuthZ code invalid!\n");
769 return GNUNET_SYSERR;
770 }
771 // Attributes
772 attrs_ser = ((char *) &params[1]) + code_challenge_len + nonce_len;
773 attrs_ser_len = ntohl (params->attr_list_len);
774 *attrs = GNUNET_RECLAIM_attribute_list_deserialize (attrs_ser, attrs_ser_len);
775 presentations_ser = ((char*) attrs_ser) + attrs_ser_len;
776 pres_ser_len = ntohl (params->pres_list_len);
777 *presentations =
778 GNUNET_RECLAIM_presentation_list_deserialize (presentations_ser,
779 pres_ser_len);
780
781 GNUNET_free (code_payload);
782 return GNUNET_OK;
783}
784
785
786/**
787 * Build a token response for a token request
788 * TODO: Maybe we should add the scope here?
789 *
790 * @param access_token the access token to include
791 * @param id_token the id_token to include
792 * @param expiration_time the expiration time of the token(s)
793 * @param token_response where to store the response
794 */
795void
796OIDC_build_token_response (const char *access_token,
797 const char *id_token,
798 const struct GNUNET_TIME_Relative *expiration_time,
799 char **token_response)
800{
801 json_t *root_json;
802
803 root_json = json_object ();
804
805 GNUNET_assert (NULL != access_token);
806 GNUNET_assert (NULL != id_token);
807 GNUNET_assert (NULL != expiration_time);
808 json_object_set_new (root_json, "access_token", json_string (access_token));
809 json_object_set_new (root_json, "token_type", json_string ("Bearer"));
810 json_object_set_new (root_json,
811 "expires_in",
812 json_integer (expiration_time->rel_value_us
813 / (1000 * 1000)));
814 json_object_set_new (root_json, "id_token", json_string (id_token));
815 *token_response = json_dumps (root_json, JSON_INDENT (0) | JSON_COMPACT);
816 json_decref (root_json);
817}
818
819
820/**
821 * Generate a new access token
822 */
823char *
824OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket)
825{
826 char *access_token;
827
828 GNUNET_STRINGS_base64_encode (ticket,
829 sizeof(*ticket),
830 &access_token);
831 return access_token;
832}
833
834
835/**
836 * Parse an access token
837 */
838int
839OIDC_access_token_parse (const char *token,
840 struct GNUNET_RECLAIM_Ticket **ticket)
841{
842 size_t sret;
843 char *decoded;
844 sret = GNUNET_STRINGS_base64_decode (token,
845 strlen (token),
846 (void**) &decoded);
847 if (sizeof (struct GNUNET_RECLAIM_Ticket) != sret)
848 {
849 GNUNET_free (decoded);
850 return GNUNET_SYSERR;
851 }
852 *ticket = (struct GNUNET_RECLAIM_Ticket *) decoded;
853 return GNUNET_OK;
854}
855
856
857/**
858 * Checks if a claim is implicitly requested through standard
859 * scope(s) or explicitly through non-standard scope.
860 *
861 * @param scopes the scopes which have been requested
862 * @param attr the attribute name to check
863 * @return GNUNET_YES if attribute is implcitly requested
864 */
865enum GNUNET_GenericReturnValue
866OIDC_check_scopes_for_claim_request (const char*scopes,
867 const char*attr)
868{
869 char *scope_variables;
870 char *scope_variable;
871 char delimiter[] = " ";
872 int i;
873
874 scope_variables = GNUNET_strdup (scopes);
875 scope_variable = strtok (scope_variables, delimiter);
876 while (NULL != scope_variable)
877 {
878 if (0 == strcmp ("profile", scope_variable))
879 {
880 for (i = 0; i < 14; i++)
881 {
882 if (0 == strcmp (attr, OIDC_profile_claims[i]))
883 {
884 GNUNET_free (scope_variables);
885 return GNUNET_YES;
886 }
887 }
888 }
889 else if (0 == strcmp ("address", scope_variable))
890 {
891 for (i = 0; i < 5; i++)
892 {
893 if (0 == strcmp (attr, OIDC_address_claims[i]))
894 {
895 GNUNET_free (scope_variables);
896 return GNUNET_YES;
897 }
898 }
899 }
900 else if (0 == strcmp ("email", scope_variable))
901 {
902 for (i = 0; i < 2; i++)
903 {
904 if (0 == strcmp (attr, OIDC_email_claims[i]))
905 {
906 GNUNET_free (scope_variables);
907 return GNUNET_YES;
908 }
909 }
910 }
911 else if (0 == strcmp ("phone", scope_variable))
912 {
913 for (i = 0; i < 2; i++)
914 {
915 if (0 == strcmp (attr, OIDC_phone_claims[i]))
916 {
917 GNUNET_free (scope_variables);
918 return GNUNET_YES;
919 }
920 }
921
922 }
923 else if (0 == strcmp (attr, scope_variable))
924 {
925 /** attribute matches requested scope **/
926 GNUNET_free (scope_variables);
927 return GNUNET_YES;
928 }
929 scope_variable = strtok (NULL, delimiter);
930 }
931 GNUNET_free (scope_variables);
932 return GNUNET_NO;
933
934}
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h
deleted file mode 100644
index 2a8b7bbae..000000000
--- a/src/reclaim/oidc_helper.h
+++ /dev/null
@@ -1,177 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 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 reclaim/oidc_helper.h
23 * @brief helper library for OIDC related functions
24 * @author Martin Schanzenbach
25 */
26
27#ifndef JWT_H
28#define JWT_H
29
30#define JWT_ALG "alg"
31
32/* Use 512bit HMAC */
33#define JWT_ALG_VALUE "HS512"
34
35#define JWT_TYP "typ"
36
37#define JWT_TYP_VALUE "jwt"
38
39#define SERVER_ADDRESS "https://api.reclaim"
40
41enum OIDC_VerificationOptions
42{
43 /**
44 * Strict verification
45 */
46 OIDC_VERIFICATION_DEFAULT = 0,
47
48 /**
49 * Do not check code verifier even if expected
50 */
51 OIDC_VERIFICATION_NO_CODE_VERIFIER = 1
52};
53
54/**
55 * Create a JWT from attributes
56 *
57 * @param aud_key the public of the audience
58 * @param sub_key the public key of the subject
59 * @param attrs the attribute list
60 * @param presentations credential presentation list (may be empty)
61 * @param expiration_time the validity of the token
62 * @param secret_key the key used to sign the JWT
63 * @return a new base64-encoded JWT string.
64 */
65char*
66OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key,
67 const struct GNUNET_IDENTITY_PublicKey *sub_key,
68 const struct GNUNET_RECLAIM_AttributeList *attrs,
69 const struct
70 GNUNET_RECLAIM_PresentationList *presentations,
71 const struct GNUNET_TIME_Relative *expiration_time,
72 const char *nonce,
73 const char *secret_key);
74
75/**
76 * Builds an OIDC authorization code including
77 * a reclaim ticket and nonce
78 *
79 * @param issuer the issuer of the ticket, used to sign the ticket and nonce
80 * @param ticket the ticket to include in the code
81 * @param attrs list of attributes to share
82 * @param presentations credential presentation list
83 * @param nonce the nonce to include in the code
84 * @param code_challenge PKCE code challenge
85 * @param opts verification options
86 * @return a new authorization code (caller must free)
87 */
88char*
89OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer,
90 const struct GNUNET_RECLAIM_Ticket *ticket,
91 const struct GNUNET_RECLAIM_AttributeList *attrs,
92 const struct
93 GNUNET_RECLAIM_PresentationList *presentations,
94 const char *nonce,
95 const char *code_challenge);
96
97/**
98 * Parse reclaim ticket and nonce from
99 * authorization code.
100 * This also verifies the signature in the code.
101 *
102 * @param ecdsa_priv the audience of the ticket
103 * @param code the string representation of the code
104 * @param code_verfier PKCE code verifier
105 * @param ticket where to store the ticket
106 * @param attrs the attributes found in the code
107 * @param presentations credential presentation list
108 * @param nonce where to store the nonce
109 * @return GNUNET_OK if successful, else GNUNET_SYSERR
110 */
111int
112OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *ecdsa_pub,
113 const char *code,
114 const char *code_verifier,
115 struct GNUNET_RECLAIM_Ticket *ticket,
116 struct GNUNET_RECLAIM_AttributeList **attrs,
117 struct GNUNET_RECLAIM_PresentationList **presentations,
118 char **nonce,
119 enum OIDC_VerificationOptions opts);
120
121/**
122 * Build a token response for a token request
123 * TODO: Maybe we should add the scope here?
124 *
125 * @param access_token the access token to include
126 * @param id_token the id_token to include
127 * @param expiration_time the expiration time of the token(s)
128 * @param token_response where to store the response
129 */
130void
131OIDC_build_token_response (const char *access_token,
132 const char *id_token,
133 const struct GNUNET_TIME_Relative *expiration_time,
134 char **token_response);
135
136/**
137 * Generate a new access token
138 */
139char*
140OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket);
141
142/**
143 * Parse an access token
144 */
145int
146OIDC_access_token_parse (const char*token,
147 struct GNUNET_RECLAIM_Ticket **ticket);
148
149
150/**
151 * Checks if a claim is implicitly requested through standard
152 * scope(s)
153 *
154 * @param scopes the scopes which have been requested
155 * @param attr the attribute name to check
156 * @return GNUNET_YES if attribute is implcitly requested
157 */
158enum GNUNET_GenericReturnValue
159OIDC_check_scopes_for_claim_request (const char *scopes,
160 const char *attr);
161
162
163/**
164 * Generate userinfo JSON as string
165 *
166 * @param sub_key the subject (user)
167 * @param attrs user attribute list
168 * @param presentations credential presentation list
169 * @return Userinfo JSON
170 */
171char *
172OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key,
173 const struct GNUNET_RECLAIM_AttributeList *attrs,
174 const struct
175 GNUNET_RECLAIM_PresentationList *presentations);
176
177#endif
diff --git a/src/reclaim/pabc_helper.c b/src/reclaim/pabc_helper.c
deleted file mode 100644
index e58b8a4f7..000000000
--- a/src/reclaim/pabc_helper.c
+++ /dev/null
@@ -1,365 +0,0 @@
1// maximilian.kaul@aisec.fraunhofer.de
2
3// WIP implementation of
4// https://github.com/ontio/ontology-crypto/wiki/Anonymous-Credential
5// using the relic library https://github.com/relic-toolkit/relic/
6
7#include "pabc_helper.h"
8#include <pwd.h>
9#include <stdlib.h>
10#include <unistd.h>
11
12static char pabc_dir[PATH_MAX + 1];
13
14static const char *
15get_homedir ()
16{
17 const char *homedir;
18 if ((homedir = getenv ("HOME")) == NULL)
19 {
20 homedir = getpwuid (getuid ())->pw_dir;
21 }
22 return homedir;
23}
24
25
26static enum GNUNET_GenericReturnValue
27write_file (char const *const filename, const char *buffer)
28{
29 struct GNUNET_DISK_FileHandle *fh;
30 fh = GNUNET_DISK_file_open (filename,
31 GNUNET_DISK_OPEN_WRITE
32 | GNUNET_DISK_OPEN_TRUNCATE
33 | GNUNET_DISK_OPEN_CREATE,
34 GNUNET_DISK_PERM_USER_WRITE
35 | GNUNET_DISK_PERM_USER_READ);
36 if (fh == NULL)
37 return GNUNET_SYSERR;
38 if (GNUNET_SYSERR == GNUNET_DISK_file_write (fh,
39 buffer, strlen (buffer) + 1))
40 goto fail;
41 GNUNET_DISK_file_close (fh);
42 return GNUNET_OK;
43
44fail:
45 GNUNET_DISK_file_close (fh);
46 return GNUNET_SYSERR;
47}
48
49
50static enum GNUNET_GenericReturnValue
51init_pabc_dir ()
52{
53 size_t filename_size = strlen (get_homedir ()) + 1 + strlen (".local") + 1
54 + strlen ("pabc-reclaim") + 1;
55 snprintf (pabc_dir, filename_size, "%s/%s/%s",
56 get_homedir (), ".local", "pabc-reclaim");
57 return GNUNET_DISK_directory_create (pabc_dir);
58}
59
60
61static const char *
62get_pabcdir ()
63{
64 init_pabc_dir ();
65 return pabc_dir;
66}
67
68
69enum GNUNET_GenericReturnValue
70read_file (char const *const filename, char **buffer)
71{
72 struct GNUNET_DISK_FileHandle *fh;
73 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
74 return GNUNET_SYSERR;
75
76 fh = GNUNET_DISK_file_open (filename,
77 GNUNET_DISK_OPEN_READ,
78 GNUNET_DISK_PERM_USER_READ);
79 if (fh == NULL)
80 return GNUNET_SYSERR;
81 long lSize = GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_END);
82 if (lSize < 0)
83 goto fail;
84 GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET);
85 *buffer = calloc ((size_t) lSize + 1, sizeof(char));
86 if (*buffer == NULL)
87 goto fail;
88
89 // copy the file into the buffer:
90 size_t r = GNUNET_DISK_file_read (fh, *buffer, (size_t) lSize);
91 if (r != (size_t) lSize)
92 goto fail;
93
94 GNUNET_DISK_file_close (fh);
95 return GNUNET_OK;
96
97fail:
98 GNUNET_DISK_file_close (fh);
99 GNUNET_free (*buffer);
100 return GNUNET_SYSERR;
101}
102
103
104struct pabc_public_parameters *
105PABC_read_issuer_ppfile (const char *f, struct pabc_context *const ctx)
106{
107 if (NULL == ctx)
108 {
109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No global context provided\n");
110 return NULL;
111 }
112 struct pabc_public_parameters *pp;
113 char *buffer;
114 int r;
115 r = read_file (f, &buffer);
116 if (GNUNET_OK != r)
117 {
118 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error reading file\n");
119 return NULL;
120 }
121 if (PABC_OK != pabc_decode_and_new_public_parameters (ctx, &pp, buffer))
122 {
123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
124 "Failed to decode public parameters\n");
125 PABC_FREE_NULL (buffer);
126 return NULL;
127 }
128 PABC_FREE_NULL (buffer);
129 return pp;
130}
131
132
133enum GNUNET_GenericReturnValue
134PABC_load_public_parameters (struct pabc_context *const ctx,
135 char const *const pp_name,
136 struct pabc_public_parameters **pp)
137{
138 char fname[PATH_MAX];
139 char *pp_filename;
140 const char *pdir = get_pabcdir ();
141
142 if (ctx == NULL)
143 return GNUNET_SYSERR;
144 if (pp_name == NULL)
145 return GNUNET_SYSERR;
146
147 GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename);
148 if (GNUNET_YES != GNUNET_DISK_directory_test (pdir, GNUNET_YES))
149 {
150 GNUNET_free (pp_filename);
151 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error reading %s\n", pdir);
152 return GNUNET_SYSERR;
153 }
154 snprintf (fname, PATH_MAX, "%s/%s%s", pdir, pp_filename, PABC_PP_EXT);
155 if (GNUNET_YES != GNUNET_DISK_file_test (fname))
156 {
157 GNUNET_free (pp_filename);
158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error testing %s\n", fname);
159 return GNUNET_SYSERR;
160 }
161 *pp = PABC_read_issuer_ppfile (fname, ctx);
162 if (*pp)
163 return GNUNET_OK;
164 else
165 return GNUNET_SYSERR;
166}
167
168
169enum GNUNET_GenericReturnValue
170PABC_write_public_parameters (char const *const pp_name,
171 struct pabc_public_parameters *const pp)
172{
173 char *json;
174 char *filename;
175 char *pp_filename;
176 enum pabc_status status;
177 struct pabc_context *ctx = NULL;
178
179 GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename);
180 PABC_ASSERT (pabc_new_ctx (&ctx));
181 // store in json file
182 status = pabc_encode_public_parameters (ctx, pp, &json);
183 if (status != PABC_OK)
184 {
185 GNUNET_free (pp_filename);
186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
187 "Failed to encode public parameters.\n");
188 pabc_free_ctx (&ctx);
189 return GNUNET_SYSERR;
190 }
191
192 size_t filename_size =
193 strlen (get_pabcdir ()) + 1 + strlen (pp_filename) + strlen (PABC_PP_EXT)
194 + 1;
195 filename = GNUNET_malloc (filename_size);
196 if (! filename)
197 {
198 GNUNET_free (pp_filename);
199 PABC_FREE_NULL (json);
200 pabc_free_ctx (&ctx);
201 return GNUNET_SYSERR;
202 }
203 snprintf (filename, filename_size, "%s/%s%s", get_pabcdir (), pp_filename,
204 PABC_PP_EXT);
205
206 GNUNET_free (pp_filename);
207 if (GNUNET_OK != write_file (filename, json))
208 {
209 PABC_FREE_NULL (filename);
210 PABC_FREE_NULL (json);
211 pabc_free_ctx (&ctx);
212 return GNUNET_SYSERR;
213 }
214 PABC_FREE_NULL (filename);
215 PABC_FREE_NULL (json);
216 pabc_free_ctx (&ctx);
217 return GNUNET_OK;
218}
219
220
221enum GNUNET_GenericReturnValue
222PABC_write_usr_ctx (char const *const usr_name,
223 char const *const pp_name,
224 struct pabc_context const *const ctx,
225 struct pabc_public_parameters const *const pp,
226 struct pabc_user_context *const usr_ctx)
227{
228
229 char *pp_filename;
230 char *json = NULL;
231 enum pabc_status status;
232 char *fname = NULL;
233
234 if (NULL == usr_name)
235 {
236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer given.\n");
237 return GNUNET_SYSERR;
238 }
239 if (NULL == pp_name)
240 {
241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user given.\n");
242 return GNUNET_SYSERR;
243 }
244 if (NULL == ctx)
245 {
246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No context given.\n");
247 return GNUNET_SYSERR;
248 }
249 if (NULL == pp)
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No public parameters given.\n");
252 return GNUNET_SYSERR;
253 }
254 if (NULL == usr_ctx)
255 {
256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user context given.\n");
257 return GNUNET_SYSERR;
258 }
259
260 GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename);
261 status = pabc_encode_user_ctx (ctx, pp, usr_ctx, &json);
262 if (PABC_OK != status)
263 {
264 GNUNET_free (pp_filename);
265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to encode user context.\n");
266 return status;
267 }
268
269 size_t fname_size = strlen (get_pabcdir ()) + 1 + strlen (usr_name) + 1
270 + strlen (pp_filename) + strlen (PABC_USR_EXT) + 1;
271 fname = GNUNET_malloc (fname_size);
272
273 snprintf (fname, fname_size, "%s/%s_%s%s", get_pabcdir (), usr_name,
274 pp_filename,
275 PABC_USR_EXT);
276
277 GNUNET_free (pp_filename);
278 if (GNUNET_OK == write_file (fname, json))
279 {
280 GNUNET_free (fname);
281 GNUNET_free (json);
282 return GNUNET_OK;
283 }
284 else
285 {
286 GNUNET_free (fname);
287 GNUNET_free (json);
288 return GNUNET_SYSERR;
289 }
290}
291
292
293enum GNUNET_GenericReturnValue
294PABC_read_usr_ctx (char const *const usr_name,
295 char const *const pp_name,
296 struct pabc_context const *const ctx,
297 struct pabc_public_parameters const *const pp,
298 struct pabc_user_context **usr_ctx)
299{
300 char *json = NULL;
301 char *pp_filename;
302 enum pabc_status status;
303
304 char *fname = NULL;
305
306 if (NULL == usr_name)
307 {
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer given.\n");
309 return GNUNET_SYSERR;
310 }
311 if (NULL == pp_name)
312 {
313 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user given.\n");
314 return GNUNET_SYSERR;
315 }
316 if (NULL == ctx)
317 {
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No context given.\n");
319 return GNUNET_SYSERR;
320 }
321 if (NULL == pp)
322 {
323 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No public parameters given.\n");
324 return GNUNET_SYSERR;
325 }
326 if (NULL == usr_ctx)
327 {
328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user context given.\n");
329 return GNUNET_SYSERR;
330 }
331 GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename);
332
333 size_t fname_size = strlen (get_pabcdir ()) + 1 + strlen (usr_name) + 1
334 + strlen (pp_filename) + strlen (PABC_USR_EXT) + 1;
335 fname = GNUNET_malloc (fname_size);
336 snprintf (fname, fname_size, "%s/%s_%s%s", get_pabcdir (), usr_name,
337 pp_filename,
338 PABC_USR_EXT);
339 GNUNET_free (pp_filename);
340 if (GNUNET_OK != read_file (fname, &json))
341 {
342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
343 "Failed to read `%s'\n", fname);
344 PABC_FREE_NULL (fname);
345 return GNUNET_SYSERR;
346 }
347 GNUNET_free (fname);
348
349 status = pabc_new_user_context (ctx, pp, usr_ctx);
350 if (PABC_OK != status)
351 {
352 GNUNET_free (json);
353 return GNUNET_SYSERR;
354 }
355 status = pabc_decode_user_ctx (ctx, pp, *usr_ctx, json);
356 GNUNET_free (json);
357 if (PABC_OK != status)
358 {
359 pabc_free_user_context (ctx, pp, usr_ctx);
360 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to encode user context.\n");
361 return GNUNET_SYSERR;
362 }
363
364 return GNUNET_OK;
365}
diff --git a/src/reclaim/pabc_helper.h b/src/reclaim/pabc_helper.h
deleted file mode 100644
index 045ad5dda..000000000
--- a/src/reclaim/pabc_helper.h
+++ /dev/null
@@ -1,41 +0,0 @@
1#include "platform.h"
2#include "gnunet_util_lib.h"
3#include <pabc/pabc.h>
4
5#ifndef PATH_MAX
6#define PATH_MAX 4096
7#endif
8
9#define PABC_ISK_EXT ".isk"
10
11#define PABC_PP_EXT ".pp"
12
13#define PABC_USR_EXT ".usr"
14
15#define PABC_ATTR_DELIM "="
16
17enum GNUNET_GenericReturnValue
18PABC_write_public_parameters (char const *const pp_name,
19 struct pabc_public_parameters *const pp);
20
21
22enum GNUNET_GenericReturnValue
23PABC_load_public_parameters (struct pabc_context *const ctx,
24 char const *const pp_name,
25 struct pabc_public_parameters **pp);
26
27enum GNUNET_GenericReturnValue
28PABC_write_usr_ctx (char const *const user_name,
29 char const *const pp_name,
30 struct pabc_context const *const ctx,
31 struct pabc_public_parameters const *const
32 pp,
33 struct pabc_user_context *const usr_ctx);
34
35enum GNUNET_GenericReturnValue
36PABC_read_usr_ctx (char const *const user_name,
37 char const *const pp_name,
38 struct pabc_context const *const ctx,
39 struct pabc_public_parameters const *const
40 pp,
41 struct pabc_user_context **usr_ctx);
diff --git a/src/reclaim/plugin_gnsrecord_reclaim.c b/src/reclaim/plugin_gnsrecord_reclaim.c
deleted file mode 100644
index ce6fe483d..000000000
--- a/src/reclaim/plugin_gnsrecord_reclaim.c
+++ /dev/null
@@ -1,195 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014 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 reclaim/plugin_gnsrecord_reclaim.c
23 * @brief gnsrecord plugin to provide the API for identity records
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27
28#include "gnunet_util_lib.h"
29
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_gnsrecord_plugin.h"
32
33/**
34 * Convert the 'value' of a record to a string.
35 *
36 * @param cls closure, unused
37 * @param type type of the record
38 * @param data value in binary encoding
39 * @param data_size number of bytes in @a data
40 * @return NULL on error, otherwise human-readable representation of the value
41 */
42static char *
43value_to_string (void *cls, uint32_t type, const void *data, size_t data_size)
44{
45 switch (type)
46 {
47 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT:
48 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT:
49 return GNUNET_strndup (data, data_size);
50 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE:
51 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF:
52 case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET:
53 case GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL:
54 case GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION:
55 return GNUNET_STRINGS_data_to_string_alloc (data, data_size);
56
57 default:
58 return NULL;
59 }
60}
61
62
63/**
64 * Convert human-readable version of a 'value' of a record to the binary
65 * representation.
66 *
67 * @param cls closure, unused
68 * @param type type of the record
69 * @param s human-readable string
70 * @param data set to value in binary encoding (will be allocated)
71 * @param data_size set to number of bytes in @a data
72 * @return #GNUNET_OK on success
73 */
74static int
75string_to_value (void *cls, uint32_t type, const char *s, void **data,
76 size_t *data_size)
77{
78 if (NULL == s)
79 return GNUNET_SYSERR;
80 switch (type)
81 {
82 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT:
83 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT:
84 *data = GNUNET_strdup (s);
85 *data_size = strlen (s);
86 return GNUNET_OK;
87 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE:
88 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF:
89 case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET:
90 case GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL:
91 case GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION:
92 return GNUNET_STRINGS_string_to_data (s, strlen (s), *data, *data_size);
93
94 default:
95 return GNUNET_SYSERR;
96 }
97}
98
99
100/**
101 * Mapping of record type numbers to human-readable
102 * record type names.
103 */
104static struct
105{
106 const char *name;
107 uint32_t number;
108} name_map[] = {
109 { "RECLAIM_ATTRIBUTE", GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE },
110 { "RECLAIM_ATTRIBUTE_REF", GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF },
111 { "RECLAIM_CREDENTIAL", GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL },
112 { "RECLAIM_PRESENTATION", GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION },
113 { "RECLAIM_OIDC_CLIENT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT },
114 { "RECLAIM_OIDC_REDIRECT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT },
115 { "RECLAIM_TICKET", GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET },
116 { NULL, UINT32_MAX }
117};
118
119
120/**
121 * Convert a type name (e.g. "AAAA") to the corresponding number.
122 *
123 * @param cls closure, unused
124 * @param dns_typename name to convert
125 * @return corresponding number, UINT32_MAX on error
126 */
127static uint32_t
128typename_to_number (void *cls, const char *dns_typename)
129{
130 unsigned int i;
131
132 i = 0;
133 while ((NULL != name_map[i].name) &&
134 (0 != strcasecmp (dns_typename, name_map[i].name)))
135 i++;
136 return name_map[i].number;
137}
138
139
140/**
141 * Convert a type number to the corresponding type string (e.g. 1 to "A")
142 *
143 * @param cls closure, unused
144 * @param type number of a type to convert
145 * @return corresponding typestring, NULL on error
146 */
147static const char *
148number_to_typename (void *cls, uint32_t type)
149{
150 unsigned int i;
151
152 i = 0;
153 while ((NULL != name_map[i].name) && (type != name_map[i].number))
154 i++;
155 return name_map[i].name;
156}
157
158
159/**
160 * Entry point for the plugin.
161 *
162 * @param cls NULL
163 * @return the exported block API
164 */
165void *
166libgnunet_plugin_gnsrecord_reclaim_init (void *cls)
167{
168 struct GNUNET_GNSRECORD_PluginFunctions *api;
169
170 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
171 api->value_to_string = &value_to_string;
172 api->string_to_value = &string_to_value;
173 api->typename_to_number = &typename_to_number;
174 api->number_to_typename = &number_to_typename;
175 return api;
176}
177
178
179/**
180 * Exit point from the plugin.
181 *
182 * @param cls the return value from #libgnunet_plugin_block_test_init
183 * @return NULL
184 */
185void *
186libgnunet_plugin_gnsrecord_reclaim_done (void *cls)
187{
188 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
189
190 GNUNET_free (api);
191 return NULL;
192}
193
194
195/* end of plugin_gnsrecord_dns.c */
diff --git a/src/reclaim/plugin_reclaim_attribute_basic.c b/src/reclaim/plugin_reclaim_attribute_basic.c
deleted file mode 100644
index 66f59998a..000000000
--- a/src/reclaim/plugin_reclaim_attribute_basic.c
+++ /dev/null
@@ -1,181 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014, 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 reclaim-attribute/plugin_reclaim_attribute_gnuid.c
23 * @brief reclaim-attribute-plugin-gnuid attribute plugin to provide the API for
24 * fundamental
25 * attribute types.
26 *
27 * @author Martin Schanzenbach
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_reclaim_plugin.h"
32#include <inttypes.h>
33
34
35/**
36 * Convert the 'value' of an attribute to a string.
37 *
38 * @param cls closure, unused
39 * @param type type of the attribute
40 * @param data value in binary encoding
41 * @param data_size number of bytes in @a data
42 * @return NULL on error, otherwise human-readable representation of the value
43 */
44static char *
45basic_value_to_string (void *cls,
46 uint32_t type,
47 const void *data,
48 size_t data_size)
49{
50 switch (type)
51 {
52 case GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING:
53 return GNUNET_strndup (data, data_size);
54
55 default:
56 return NULL;
57 }
58}
59
60
61/**
62 * Convert human-readable version of a 'value' of an attribute to the binary
63 * representation.
64 *
65 * @param cls closure, unused
66 * @param type type of the attribute
67 * @param s human-readable string
68 * @param data set to value in binary encoding (will be allocated)
69 * @param data_size set to number of bytes in @a data
70 * @return #GNUNET_OK on success
71 */
72static int
73basic_string_to_value (void *cls,
74 uint32_t type,
75 const char *s,
76 void **data,
77 size_t *data_size)
78{
79 if (NULL == s)
80 return GNUNET_SYSERR;
81 switch (type)
82 {
83 case GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING:
84 *data = GNUNET_strdup (s);
85 *data_size = strlen (s) + 1;
86 return GNUNET_OK;
87
88 default:
89 return GNUNET_SYSERR;
90 }
91}
92
93
94/**
95 * Mapping of attribute type numbers to human-readable
96 * attribute type names.
97 */
98static struct
99{
100 const char *name;
101 uint32_t number;
102} basic_name_map[] = { { "STRING", GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING },
103 { NULL, UINT32_MAX } };
104
105
106/**
107 * Convert a type name to the corresponding number.
108 *
109 * @param cls closure, unused
110 * @param basic_typename name to convert
111 * @return corresponding number, UINT32_MAX on error
112 */
113static uint32_t
114basic_typename_to_number (void *cls, const char *basic_typename)
115{
116 unsigned int i;
117
118 i = 0;
119 while ((NULL != basic_name_map[i].name) &&
120 (0 != strcasecmp (basic_typename, basic_name_map[i].name)))
121 i++;
122 return basic_name_map[i].number;
123}
124
125
126/**
127 * Convert a type number to the corresponding type string (e.g. 1 to "A")
128 *
129 * @param cls closure, unused
130 * @param type number of a type to convert
131 * @return corresponding typestring, NULL on error
132 */
133static const char *
134basic_number_to_typename (void *cls, uint32_t type)
135{
136 unsigned int i;
137
138 i = 0;
139 while ((NULL != basic_name_map[i].name) && (type != basic_name_map[i].number))
140 i++;
141 return basic_name_map[i].name;
142}
143
144
145/**
146 * Entry point for the plugin.
147 *
148 * @param cls NULL
149 * @return the exported block API
150 */
151void *
152libgnunet_plugin_reclaim_attribute_basic_init (void *cls)
153{
154 struct GNUNET_RECLAIM_AttributePluginFunctions *api;
155
156 api = GNUNET_new (struct GNUNET_RECLAIM_AttributePluginFunctions);
157 api->value_to_string = &basic_value_to_string;
158 api->string_to_value = &basic_string_to_value;
159 api->typename_to_number = &basic_typename_to_number;
160 api->number_to_typename = &basic_number_to_typename;
161 return api;
162}
163
164
165/**
166 * Exit point from the plugin.
167 *
168 * @param cls the return value from #libgnunet_plugin_block_test_init()
169 * @return NULL
170 */
171void *
172libgnunet_plugin_reclaim_attribute_basic_done (void *cls)
173{
174 struct GNUNET_RECLAIM_AttributePluginFunctions *api = cls;
175
176 GNUNET_free (api);
177 return NULL;
178}
179
180
181/* end of plugin_reclaim_attribute_type_gnuid.c */
diff --git a/src/reclaim/plugin_reclaim_credential_jwt.c b/src/reclaim/plugin_reclaim_credential_jwt.c
deleted file mode 100644
index 5d5e221f9..000000000
--- a/src/reclaim/plugin_reclaim_credential_jwt.c
+++ /dev/null
@@ -1,499 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014, 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 reclaim/plugin_reclaim_credential_jwt.c
23 * @brief reclaim-credential-plugin-jwt attribute plugin to provide the API for
24 * JWT credentials.
25 *
26 * @author Martin Schanzenbach
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_reclaim_plugin.h"
31#include <inttypes.h>
32#include <jansson.h>
33
34/**
35 * Convert the 'value' of an credential to a string.
36 *
37 * @param cls closure, unused
38 * @param type type of the credential
39 * @param data value in binary encoding
40 * @param data_size number of bytes in @a data
41 * @return NULL on error, otherwise human-readable representation of the value
42 */
43static char *
44jwt_value_to_string (void *cls,
45 uint32_t type,
46 const void *data,
47 size_t data_size)
48{
49 switch (type)
50 {
51 case GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT:
52 return GNUNET_strndup (data, data_size);
53
54 default:
55 return NULL;
56 }
57}
58
59
60/**
61 * Convert human-readable version of a 'value' of an credential to the binary
62 * representation.
63 *
64 * @param cls closure, unused
65 * @param type type of the credential
66 * @param s human-readable string
67 * @param data set to value in binary encoding (will be allocated)
68 * @param data_size set to number of bytes in @a data
69 * @return #GNUNET_OK on success
70 */
71static int
72jwt_string_to_value (void *cls,
73 uint32_t type,
74 const char *s,
75 void **data,
76 size_t *data_size)
77{
78 if (NULL == s)
79 return GNUNET_SYSERR;
80 switch (type)
81 {
82 case GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT:
83 *data = GNUNET_strdup (s);
84 *data_size = strlen (s) + 1;
85 return GNUNET_OK;
86
87 default:
88 return GNUNET_SYSERR;
89 }
90}
91
92
93/**
94 * Mapping of credential type numbers to human-readable
95 * credential type names.
96 */
97static struct
98{
99 const char *name;
100 uint32_t number;
101} jwt_cred_name_map[] = { { "JWT", GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT },
102 { NULL, UINT32_MAX } };
103
104/**
105 * Convert a type name to the corresponding number.
106 *
107 * @param cls closure, unused
108 * @param jwt_typename name to convert
109 * @return corresponding number, UINT32_MAX on error
110 */
111static uint32_t
112jwt_typename_to_number (void *cls, const char *jwt_typename)
113{
114 unsigned int i;
115
116 i = 0;
117 while ((NULL != jwt_cred_name_map[i].name) &&
118 (0 != strcasecmp (jwt_typename, jwt_cred_name_map[i].name)))
119 i++;
120 return jwt_cred_name_map[i].number;
121}
122
123
124/**
125 * Convert a type number to the corresponding type string (e.g. 1 to "A")
126 *
127 * @param cls closure, unused
128 * @param type number of a type to convert
129 * @return corresponding typestring, NULL on error
130 */
131static const char *
132jwt_number_to_typename (void *cls, uint32_t type)
133{
134 unsigned int i;
135
136 i = 0;
137 while ((NULL != jwt_cred_name_map[i].name) && (type !=
138 jwt_cred_name_map[i].
139 number))
140 i++;
141 return jwt_cred_name_map[i].name;
142}
143
144
145/**
146 * Parse a JWT and return the respective claim value as Attribute
147 *
148 * @param cls the plugin
149 * @param cred the jwt credential
150 * @return a GNUNET_RECLAIM_Attribute, containing the new value
151 */
152struct GNUNET_RECLAIM_AttributeList *
153jwt_parse_attributes (void *cls,
154 const char *data,
155 size_t data_size)
156{
157 char *jwt_string;
158 struct GNUNET_RECLAIM_AttributeList *attrs;
159 char delim[] = ".";
160 char *val_str = NULL;
161 char *decoded_jwt;
162 char *tmp;
163 json_t *json_val;
164 json_error_t json_err;
165
166 attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
167
168 jwt_string = GNUNET_strndup (data, data_size);
169 const char *jwt_body = strtok (jwt_string, delim);
170 jwt_body = strtok (NULL, delim);
171 GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
172 (void **) &decoded_jwt);
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decoded JWT: %s\n", decoded_jwt);
174 GNUNET_assert (NULL != decoded_jwt);
175 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
176 GNUNET_free (decoded_jwt);
177 const char *key;
178 const char *addr_key;
179 json_t *value;
180 json_t *addr_value;
181
182 json_object_foreach (json_val, key, value) {
183 if (0 == strcmp ("iss", key))
184 continue;
185 if (0 == strcmp ("jti", key))
186 continue;
187 if (0 == strcmp ("exp", key))
188 continue;
189 if (0 == strcmp ("iat", key))
190 continue;
191 if (0 == strcmp ("nbf", key))
192 continue;
193 if (0 == strcmp ("aud", key))
194 continue;
195 if (0 == strcmp ("address", key))
196 {
197 if (! json_is_object (value))
198 {
199 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
200 "address claim in wrong format!");
201 continue;
202 }
203 json_object_foreach (value, addr_key, addr_value) {
204 val_str = json_dumps (addr_value, JSON_ENCODE_ANY);
205 tmp = val_str;
206 // Remove leading " from jasson conversion
207 if (tmp[0] == '"')
208 tmp++;
209 // Remove trailing " from jansson conversion
210 if (tmp[strlen (tmp) - 1] == '"')
211 tmp[strlen (tmp) - 1] = '\0';
212 GNUNET_RECLAIM_attribute_list_add (attrs,
213 addr_key,
214 NULL,
215 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
216 tmp,
217 strlen (val_str));
218 GNUNET_free (val_str);
219 }
220 continue;
221 }
222 val_str = json_dumps (value, JSON_ENCODE_ANY);
223 tmp = val_str;
224 // Remove leading " from jasson conversion
225 if (tmp[0] == '"')
226 tmp++;
227 // Remove trailing " from jansson conversion
228 if (tmp[strlen (tmp) - 1] == '"')
229 tmp[strlen (tmp) - 1] = '\0';
230 GNUNET_RECLAIM_attribute_list_add (attrs,
231 key,
232 NULL,
233 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,// FIXME
234 tmp,
235 strlen (val_str));
236 GNUNET_free (val_str);
237 }
238 json_decref (json_val);
239 GNUNET_free (jwt_string);
240 return attrs;
241}
242
243
244/**
245 * Parse a JWT and return the respective claim value as Attribute
246 *
247 * @param cls the plugin
248 * @param cred the jwt credential
249 * @return a GNUNET_RECLAIM_Attribute, containing the new value
250 */
251struct GNUNET_RECLAIM_AttributeList *
252jwt_parse_attributes_c (void *cls,
253 const struct GNUNET_RECLAIM_Credential *cred)
254{
255 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT)
256 return NULL;
257 return jwt_parse_attributes (cls, cred->data, cred->data_size);
258}
259
260
261/**
262 * Parse a JWT and return the respective claim value as Attribute
263 *
264 * @param cls the plugin
265 * @param cred the jwt credential
266 * @return a GNUNET_RECLAIM_Attribute, containing the new value
267 */
268struct GNUNET_RECLAIM_AttributeList *
269jwt_parse_attributes_p (void *cls,
270 const struct GNUNET_RECLAIM_Presentation *cred)
271{
272 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT)
273 return NULL;
274 return jwt_parse_attributes (cls, cred->data, cred->data_size);
275}
276
277
278/**
279 * Parse a JWT and return the issuer
280 *
281 * @param cls the plugin
282 * @param cred the jwt credential
283 * @return a string, containing the isser
284 */
285char *
286jwt_get_issuer (void *cls,
287 const char *data,
288 size_t data_size)
289{
290 const char *jwt_body;
291 char *jwt_string;
292 char delim[] = ".";
293 char *issuer = NULL;
294 char *decoded_jwt;
295 json_t *issuer_json;
296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
297 json_t *json_val;
298 json_error_t json_err;
299
300 jwt_string = GNUNET_strndup (data, data_size);
301 jwt_body = strtok (jwt_string, delim);
302 jwt_body = strtok (NULL, delim);
303 GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
304 (void **) &decoded_jwt);
305 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
306 GNUNET_free (decoded_jwt);
307 GNUNET_free (jwt_string);
308 if (NULL == json_val)
309 return NULL;
310 issuer_json = json_object_get (json_val, "iss");
311 if ((NULL == issuer_json) || (! json_is_string (issuer_json)))
312 {
313 json_decref (json_val);
314 return NULL;
315 }
316 issuer = GNUNET_strdup (json_string_value (issuer_json));
317 json_decref (json_val);
318 return issuer;
319}
320
321
322/**
323 * Parse a JWT and return the issuer
324 *
325 * @param cls the plugin
326 * @param cred the jwt credential
327 * @return a string, containing the isser
328 */
329char *
330jwt_get_issuer_c (void *cls,
331 const struct GNUNET_RECLAIM_Credential *cred)
332{
333 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT != cred->type)
334 return NULL;
335 return jwt_get_issuer (cls, cred->data, cred->data_size);
336}
337
338
339/**
340 * Parse a JWT and return the issuer
341 *
342 * @param cls the plugin
343 * @param cred the jwt credential
344 * @return a string, containing the isser
345 */
346char *
347jwt_get_issuer_p (void *cls,
348 const struct GNUNET_RECLAIM_Presentation *cred)
349{
350 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT != cred->type)
351 return NULL;
352 return jwt_get_issuer (cls, cred->data, cred->data_size);
353}
354
355
356/**
357 * Parse a JWT and return the expiration
358 *
359 * @param cls the plugin
360 * @param cred the jwt credential
361 * @return a string, containing the isser
362 */
363enum GNUNET_GenericReturnValue
364jwt_get_expiration (void *cls,
365 const char *data,
366 size_t data_size,
367 struct GNUNET_TIME_Absolute *exp)
368{
369 const char *jwt_body;
370 char *jwt_string;
371 char delim[] = ".";
372 char *decoded_jwt;
373 json_t *exp_json;
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
375 json_t *json_val;
376 json_error_t json_err;
377
378 jwt_string = GNUNET_strndup (data, data_size);
379 jwt_body = strtok (jwt_string, delim);
380 jwt_body = strtok (NULL, delim);
381 GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
382 (void **) &decoded_jwt);
383 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
384 GNUNET_free (decoded_jwt);
385 GNUNET_free (jwt_string);
386 if (NULL == json_val)
387 return GNUNET_SYSERR;
388 exp_json = json_object_get (json_val, "exp");
389 if ((NULL == exp_json) || (! json_is_integer (exp_json)))
390 {
391 json_decref (json_val);
392 return GNUNET_SYSERR;
393 }
394 exp->abs_value_us = json_integer_value (exp_json) * 1000 * 1000;
395 json_decref (json_val);
396 return GNUNET_OK;
397}
398
399
400/**
401 * Parse a JWT and return the expiration
402 *
403 * @param cls the plugin
404 * @param cred the jwt credential
405 * @return the expirati
406 */
407enum GNUNET_GenericReturnValue
408jwt_get_expiration_c (void *cls,
409 const struct GNUNET_RECLAIM_Credential *cred,
410 struct GNUNET_TIME_Absolute *exp)
411{
412 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT != cred->type)
413 return GNUNET_NO;
414 return jwt_get_expiration (cls, cred->data, cred->data_size, exp);
415}
416
417
418/**
419 * Parse a JWT and return the expiration
420 *
421 * @param cls the plugin
422 * @param cred the jwt credential
423 * @return a string, containing the isser
424 */
425enum GNUNET_GenericReturnValue
426jwt_get_expiration_p (void *cls,
427 const struct GNUNET_RECLAIM_Presentation *cred,
428 struct GNUNET_TIME_Absolute *exp)
429{
430 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT != cred->type)
431 return GNUNET_NO;
432 return jwt_get_expiration (cls, cred->data, cred->data_size, exp);
433}
434
435
436enum GNUNET_GenericReturnValue
437jwt_create_presentation (void *cls,
438 const struct GNUNET_RECLAIM_Credential *cred,
439 const struct GNUNET_RECLAIM_AttributeList *attrs,
440 struct GNUNET_RECLAIM_Presentation **presentation)
441{
442 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT != cred->type)
443 return GNUNET_NO;
444 *presentation = GNUNET_RECLAIM_presentation_new (
445 GNUNET_RECLAIM_CREDENTIAL_TYPE_JWT,
446 cred->data,
447 cred->data_size);
448 return GNUNET_OK;
449}
450
451
452/**
453 * Entry point for the plugin.
454 *
455 * @param cls NULL
456 * @return the exported block API
457 */
458void *
459libgnunet_plugin_reclaim_credential_jwt_init (void *cls)
460{
461 struct GNUNET_RECLAIM_CredentialPluginFunctions *api;
462
463 api = GNUNET_new (struct GNUNET_RECLAIM_CredentialPluginFunctions);
464 api->value_to_string = &jwt_value_to_string;
465 api->string_to_value = &jwt_string_to_value;
466 api->typename_to_number = &jwt_typename_to_number;
467 api->number_to_typename = &jwt_number_to_typename;
468 api->get_attributes = &jwt_parse_attributes_c;
469 api->get_issuer = &jwt_get_issuer_c;
470 api->get_expiration = &jwt_get_expiration_c;
471 api->value_to_string_p = &jwt_value_to_string;
472 api->string_to_value_p = &jwt_string_to_value;
473 api->typename_to_number_p = &jwt_typename_to_number;
474 api->number_to_typename_p = &jwt_number_to_typename;
475 api->get_attributes_p = &jwt_parse_attributes_p;
476 api->get_issuer_p = &jwt_get_issuer_p;
477 api->get_expiration_p = &jwt_get_expiration_p;
478 api->create_presentation = &jwt_create_presentation;
479 return api;
480}
481
482
483/**
484 * Exit point from the plugin.
485 *
486 * @param cls the return value from #libgnunet_plugin_block_test_init()
487 * @return NULL
488 */
489void *
490libgnunet_plugin_reclaim_credential_jwt_done (void *cls)
491{
492 struct GNUNET_RECLAIM_CredentialPluginFunctions *api = cls;
493
494 GNUNET_free (api);
495 return NULL;
496}
497
498
499/* end of plugin_reclaim_credential_type_jwt.c */
diff --git a/src/reclaim/plugin_reclaim_credential_pabc.c b/src/reclaim/plugin_reclaim_credential_pabc.c
deleted file mode 100644
index a906805fb..000000000
--- a/src/reclaim/plugin_reclaim_credential_pabc.c
+++ /dev/null
@@ -1,572 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014, 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 reclaim/plugin_reclaim_credential_pabc.c
23 * @brief reclaim-credential-plugin-pabc attribute plugin to provide the API for
24 * pabc credentials.
25 *
26 * @author Martin Schanzenbach
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_reclaim_plugin.h"
31#include <inttypes.h>
32#include <jansson.h>
33#include <pabc/pabc.h>
34#include "pabc_helper.h"
35
36/**
37 * Convert the 'value' of an credential to a string.
38 *
39 * @param cls closure, unused
40 * @param type type of the credential
41 * @param data value in binary encoding
42 * @param data_size number of bytes in @a data
43 * @return NULL on error, otherwise human-readable representation of the value
44 */
45static char *
46pabc_value_to_string (void *cls,
47 uint32_t type,
48 const void *data,
49 size_t data_size)
50{
51 switch (type)
52 {
53 case GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC:
54 return GNUNET_strndup (data, data_size);
55
56 default:
57 return NULL;
58 }
59}
60
61
62/**
63 * Convert human-readable version of a 'value' of an credential to the binary
64 * representation.
65 *
66 * @param cls closure, unused
67 * @param type type of the credential
68 * @param s human-readable string
69 * @param data set to value in binary encoding (will be allocated)
70 * @param data_size set to number of bytes in @a data
71 * @return #GNUNET_OK on success
72 */
73static int
74pabc_string_to_value (void *cls,
75 uint32_t type,
76 const char *s,
77 void **data,
78 size_t *data_size)
79{
80 if (NULL == s)
81 return GNUNET_SYSERR;
82 switch (type)
83 {
84 case GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC:
85 *data = GNUNET_strdup (s);
86 *data_size = strlen (s) + 1;
87 return GNUNET_OK;
88
89 default:
90 return GNUNET_SYSERR;
91 }
92}
93
94
95/**
96 * Mapping of credential type numbers to human-readable
97 * credential type names.
98 */
99static struct
100{
101 const char *name;
102 uint32_t number;
103} pabc_cred_name_map[] = { { "PABC", GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC },
104 { NULL, UINT32_MAX } };
105
106/**
107 * Convert a type name to the corresponding number.
108 *
109 * @param cls closure, unused
110 * @param pabc_typename name to convert
111 * @return corresponding number, UINT32_MAX on error
112 */
113static uint32_t
114pabc_typename_to_number (void *cls, const char *pabc_typename)
115{
116 unsigned int i;
117
118 i = 0;
119 while ((NULL != pabc_cred_name_map[i].name) &&
120 (0 != strcasecmp (pabc_typename, pabc_cred_name_map[i].name)))
121 i++;
122 return pabc_cred_name_map[i].number;
123}
124
125
126/**
127 * Convert a type number (i.e. 1) to the corresponding type string
128 *
129 * @param cls closure, unused
130 * @param type number of a type to convert
131 * @return corresponding typestring, NULL on error
132 */
133static const char *
134pabc_number_to_typename (void *cls, uint32_t type)
135{
136 unsigned int i;
137
138 i = 0;
139 while ((NULL != pabc_cred_name_map[i].name) && (type !=
140 pabc_cred_name_map[i].
141 number))
142 i++;
143 return pabc_cred_name_map[i].name;
144}
145
146
147static void
148inspect_attrs (char const *const key,
149 char const *const value,
150 void *ctx)
151{
152 struct GNUNET_RECLAIM_AttributeList *attrs = ctx;
153
154 if (NULL == value)
155 return;
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157 "Found attribute in PABC credential: `%s': `%s'\n",
158 key, value);
159 if (0 == strcmp (key, "expiration"))
160 return;
161 if (0 == strcmp (key, "issuer"))
162 return;
163 if (0 == strcmp (key, "subject"))
164 return;
165 GNUNET_RECLAIM_attribute_list_add (attrs,
166 key,
167 NULL,
168 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
169 value,
170 strlen (value));
171}
172
173
174/**
175 * Parse a pabc and return the respective claim value as Attribute
176 *
177 * @param cls the plugin
178 * @param cred the pabc credential
179 * @return a GNUNET_RECLAIM_Attribute, containing the new value
180 */
181struct GNUNET_RECLAIM_AttributeList *
182pabc_parse_attributes (void *cls,
183 const char *data,
184 size_t data_size)
185{
186 struct GNUNET_RECLAIM_AttributeList *attrs;
187
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "Collecting PABC attributes...\n");
190 attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
191 GNUNET_assert (PABC_OK ==
192 pabc_cred_inspect_credential (data,
193 &inspect_attrs, attrs));
194 return attrs;
195}
196
197
198/**
199 * Parse a pabc and return the respective claim value as Attribute
200 *
201 * @param cls the plugin
202 * @param cred the pabc credential
203 * @return a GNUNET_RECLAIM_Attribute, containing the new value
204 */
205struct GNUNET_RECLAIM_AttributeList *
206pabc_parse_attributes_c (void *cls,
207 const struct GNUNET_RECLAIM_Credential *cred)
208{
209 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC)
210 return NULL;
211 return pabc_parse_attributes (cls, cred->data, cred->data_size);
212}
213
214
215/**
216 * Parse a pabc and return the respective claim value as Attribute
217 *
218 * @param cls the plugin
219 * @param cred the pabc credential
220 * @return a GNUNET_RECLAIM_Attribute, containing the new value
221 */
222struct GNUNET_RECLAIM_AttributeList *
223pabc_parse_attributes_p (void *cls,
224 const struct GNUNET_RECLAIM_Presentation *cred)
225{
226 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC)
227 return NULL;
228 return pabc_parse_attributes (cls, cred->data, cred->data_size);
229}
230
231
232/**
233 * Parse a pabc and return the issuer
234 *
235 * @param cls the plugin
236 * @param cred the pabc credential
237 * @return a string, containing the isser
238 */
239char*
240pabc_get_issuer (void *cls,
241 const char *data,
242 size_t data_size)
243{
244 char *res;
245 if (PABC_OK != pabc_cred_get_attr_by_name_from_cred (data,
246 "issuer",
247 &res))
248 return NULL;
249 return res;
250}
251
252
253/**
254 * Parse a pabc and return the issuer
255 *
256 * @param cls the plugin
257 * @param cred the pabc credential
258 * @return a string, containing the isser
259 */
260char *
261pabc_get_issuer_c (void *cls,
262 const struct GNUNET_RECLAIM_Credential *cred)
263{
264 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != cred->type)
265 return NULL;
266 return pabc_get_issuer (cls, cred->data, cred->data_size);
267}
268
269
270/**
271 * Parse a pabc and return the issuer
272 *
273 * @param cls the plugin
274 * @param cred the pabc credential
275 * @return a string, containing the isser
276 */
277char *
278pabc_get_issuer_p (void *cls,
279 const struct GNUNET_RECLAIM_Presentation *cred)
280{
281 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != cred->type)
282 return NULL;
283 return pabc_get_issuer (cls, cred->data, cred->data_size);
284}
285
286
287/**
288 * Parse a pabc and return the expiration
289 *
290 * @param cls the plugin
291 * @param cred the pabc credential
292 * @return a string, containing the isser
293 */
294enum GNUNET_GenericReturnValue
295pabc_get_expiration (void *cls,
296 const char *data,
297 size_t data_size,
298 struct GNUNET_TIME_Absolute *exp)
299{
300 char *exp_str;
301 uint64_t exp_i;
302
303 if (PABC_OK != pabc_cred_get_attr_by_name_from_cred (data,
304 "expiration",
305 &exp_str))
306 return GNUNET_SYSERR;
307
308 if (1 != sscanf (exp_str, "%llu", &exp_i))
309 {
310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
311 "Invalid expiration `%s'\n", exp_str);
312 GNUNET_free (exp_str);
313 return GNUNET_SYSERR;
314 }
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Converted expiration string `%s' to %llu",
317 exp_str, exp_i);
318
319 GNUNET_free (exp_str);
320 exp->abs_value_us = exp_i * 1000 * 1000;
321 return GNUNET_OK;
322}
323
324
325/**
326 * Parse a pabc and return the expiration
327 *
328 * @param cls the plugin
329 * @param cred the pabc credential
330 * @return a string, containing the isser
331 */
332enum GNUNET_GenericReturnValue
333pabc_get_expiration_c (void *cls,
334 const struct GNUNET_RECLAIM_Credential *cred,
335 struct GNUNET_TIME_Absolute *exp)
336{
337 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC)
338 return GNUNET_NO;
339 return pabc_get_expiration (cls, cred->data, cred->data_size, exp);
340}
341
342
343/**
344 * Parse a pabc and return the expiration
345 *
346 * @param cls the plugin
347 * @param cred the pabc credential
348 * @return a string, containing the isser
349 */
350enum GNUNET_GenericReturnValue
351pabc_get_expiration_p (void *cls,
352 const struct GNUNET_RECLAIM_Presentation *cred,
353 struct GNUNET_TIME_Absolute *exp)
354{
355 if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC)
356 return GNUNET_NO;
357 return pabc_get_expiration (cls, cred->data, cred->data_size, exp);
358}
359
360
361int
362pabc_create_presentation (void *cls,
363 const struct GNUNET_RECLAIM_Credential *credential,
364 const struct GNUNET_RECLAIM_AttributeList *attrs,
365 struct GNUNET_RECLAIM_Presentation **presentation)
366{
367 struct pabc_context *ctx = NULL;
368 struct pabc_user_context *usr_ctx = NULL;
369 struct pabc_public_parameters *pp = NULL;
370 struct pabc_credential *cred = NULL;
371 struct pabc_blinded_proof *proof = NULL;
372 struct GNUNET_RECLAIM_AttributeListEntry *ale;
373 char *issuer;
374 char *subject;
375 enum pabc_status status;
376
377 if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != credential->type)
378 return GNUNET_NO;
379
380
381 PABC_ASSERT (pabc_new_ctx (&ctx));
382 issuer = pabc_get_issuer_c (cls, credential);
383 if (NULL == issuer)
384 {
385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
386 "No issuer found in credential\n");
387 pabc_free_ctx (&ctx);
388 return GNUNET_SYSERR;
389 }
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Got issuer for credential: %s\n", issuer);
392 status = PABC_load_public_parameters (ctx, issuer, &pp);
393 if (status != PABC_OK)
394 {
395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
396 "Failed to read public parameters.\n");
397 pabc_free_ctx (&ctx);
398 GNUNET_free (issuer);
399 return GNUNET_SYSERR;
400 }
401 if (PABC_OK != pabc_cred_get_attr_by_name_from_cred (credential->data,
402 "subject",
403 &subject))
404 {
405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
406 "Failed to get subject.\n");
407 pabc_free_ctx (&ctx);
408 GNUNET_free (issuer);
409 return GNUNET_SYSERR;
410 }
411 status = PABC_read_usr_ctx (subject, issuer, ctx, pp, &usr_ctx);
412 GNUNET_free (issuer);
413 GNUNET_free (subject);
414 if (PABC_OK != status)
415 {
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "Failed to read user context.\n");
418 pabc_free_public_parameters (ctx, &pp);
419 return GNUNET_SYSERR;
420 }
421
422 status = pabc_new_credential (ctx, pp, &cred);
423 if (status != PABC_OK)
424 {
425 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
426 "Failed to allocate credential.\n");
427 pabc_free_user_context (ctx, pp, &usr_ctx);
428 pabc_free_public_parameters (ctx, &pp);
429 return GNUNET_SYSERR;
430 }
431
432 status = pabc_decode_credential (ctx, pp, cred, credential->data);
433 if (status != PABC_OK)
434 {
435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
436 "Failed to decode credential.\n");
437 pabc_free_credential (ctx, pp, &cred);
438 pabc_free_user_context (ctx, pp, &usr_ctx);
439 pabc_free_public_parameters (ctx, &pp);
440 return GNUNET_SYSERR;
441 }
442
443 status = pabc_new_proof (ctx, pp, &proof);
444 if (status != PABC_OK)
445 {
446 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
447 "Failed to allocate proof.\n");
448 pabc_free_credential (ctx, pp, &cred);
449 pabc_free_user_context (ctx, pp, &usr_ctx);
450 pabc_free_public_parameters (ctx, &pp);
451 return GNUNET_SYSERR;
452 }
453
454 // now we can parse the attributes to disclose and configure the proof
455 for (ale = attrs->list_head; NULL != ale; ale = ale->next)
456 {
457 status = pabc_set_disclosure_by_attribute_name (ctx, pp, proof,
458 ale->attribute->name,
459 PABC_DISCLOSED, cred);
460 if (status != PABC_OK)
461 {
462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
463 "Failed to configure proof.\n");
464 pabc_free_credential (ctx, pp, &cred);
465 pabc_free_user_context (ctx, pp, &usr_ctx);
466 pabc_free_public_parameters (ctx, &pp);
467 return GNUNET_SYSERR;
468 }
469 }
470
471 // and finally -> sign the proof
472 status = pabc_gen_proof (ctx, usr_ctx, pp, proof, cred);
473 if (status != PABC_OK)
474 {
475 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
476 "Failed to sign proof.\n");
477 pabc_free_proof (ctx, pp, &proof);
478 pabc_free_credential (ctx, pp, &cred);
479 pabc_free_user_context (ctx, pp, &usr_ctx);
480 pabc_free_public_parameters (ctx, &pp);
481 return GNUNET_SYSERR;
482 }
483 // print the result
484 char *json = NULL;
485 char *ppid = NULL;
486 char *userid = NULL;
487 GNUNET_assert (PABC_OK == pabc_cred_get_userid_from_cred (credential->data,
488 &userid));
489 GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_cred (credential->data,
490 &ppid));
491 pabc_cred_encode_proof (ctx, pp, proof, userid, ppid, &json);
492 GNUNET_free (ppid);
493 GNUNET_free (userid);
494 if (PABC_OK != status)
495 {
496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
497 "Failed to serialize proof.\n");
498 pabc_free_proof (ctx, pp, &proof);
499 pabc_free_credential (ctx, pp, &cred);
500 pabc_free_user_context (ctx, pp, &usr_ctx);
501 pabc_free_public_parameters (ctx, &pp);
502 return GNUNET_SYSERR;
503 }
504 char *json_enc;
505 GNUNET_STRINGS_base64_encode (json,
506 strlen (json) + 1,
507 &json_enc);
508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
509 "Presentation: %s\n", json_enc);
510 // clean up
511 *presentation = GNUNET_RECLAIM_presentation_new (
512 GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC,
513 json_enc,
514 strlen (json_enc) + 1);
515 GNUNET_free (json_enc);
516 PABC_FREE_NULL (json);
517 pabc_free_proof (ctx, pp, &proof);
518 pabc_free_credential (ctx, pp, &cred);
519 pabc_free_user_context (ctx, pp, &usr_ctx);
520 pabc_free_public_parameters (ctx, &pp);
521 return GNUNET_OK;
522}
523
524
525/**
526 * Entry point for the plugin.
527 *
528 * @param cls NULL
529 * @return the exported block API
530 */
531void *
532libgnunet_plugin_reclaim_credential_pabc_init (void *cls)
533{
534 struct GNUNET_RECLAIM_CredentialPluginFunctions *api;
535
536 api = GNUNET_new (struct GNUNET_RECLAIM_CredentialPluginFunctions);
537 api->value_to_string = &pabc_value_to_string;
538 api->string_to_value = &pabc_string_to_value;
539 api->typename_to_number = &pabc_typename_to_number;
540 api->number_to_typename = &pabc_number_to_typename;
541 api->get_attributes = &pabc_parse_attributes_c;
542 api->get_issuer = &pabc_get_issuer_c;
543 api->get_expiration = &pabc_get_expiration_c;
544 api->value_to_string_p = &pabc_value_to_string;
545 api->string_to_value_p = &pabc_string_to_value;
546 api->typename_to_number_p = &pabc_typename_to_number;
547 api->number_to_typename_p = &pabc_number_to_typename;
548 api->get_attributes_p = &pabc_parse_attributes_p;
549 api->get_issuer_p = &pabc_get_issuer_p;
550 api->get_expiration_p = &pabc_get_expiration_p;
551 api->create_presentation = &pabc_create_presentation;
552 return api;
553}
554
555
556/**
557 * Exit point from the plugin.
558 *
559 * @param cls the return value from #libgnunet_plugin_block_test_init()
560 * @return NULL
561 */
562void *
563libgnunet_plugin_reclaim_credential_pabc_done (void *cls)
564{
565 struct GNUNET_RECLAIM_CredentialPluginFunctions *api = cls;
566
567 GNUNET_free (api);
568 return NULL;
569}
570
571
572/* end of plugin_reclaim_credential_type_pabc.c */
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c
deleted file mode 100644
index 1c00abcbd..000000000
--- a/src/reclaim/plugin_rest_openid_connect.c
+++ /dev/null
@@ -1,2860 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2018 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 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file identity/plugin_rest_openid_connect.c
24 * @brief GNUnet Namestore REST plugin
25 *
26 */
27#include "platform.h"
28#include <inttypes.h>
29#include <jansson.h>
30
31#include "gnunet_buffer_lib.h"
32#include "gnunet_strings_lib.h"
33#include "gnunet_gns_service.h"
34#include "gnunet_gnsrecord_lib.h"
35#include "gnunet_identity_service.h"
36#include "gnunet_namestore_service.h"
37#include "gnunet_reclaim_lib.h"
38#include "gnunet_reclaim_service.h"
39#include "gnunet_rest_lib.h"
40#include "gnunet_rest_plugin.h"
41#include "gnunet_signatures.h"
42#include "microhttpd.h"
43#include "oidc_helper.h"
44
45/**
46 * REST root namespace
47 */
48#define GNUNET_REST_API_NS_OIDC "/openid"
49
50/**
51 * OIDC config
52 */
53#define GNUNET_REST_API_NS_OIDC_CONFIG "/.well-known/openid-configuration"
54
55/**
56 * Authorize endpoint
57 */
58#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
59
60/**
61 * Token endpoint
62 */
63#define GNUNET_REST_API_NS_TOKEN "/openid/token"
64
65/**
66 * UserInfo endpoint
67 */
68#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
69
70/**
71 * Login namespace
72 */
73#define GNUNET_REST_API_NS_LOGIN "/openid/login"
74
75/**
76 * State while collecting all egos
77 */
78#define ID_REST_STATE_INIT 0
79
80/**
81 * Done collecting egos
82 */
83#define ID_REST_STATE_POST_INIT 1
84
85/**
86 * OIDC grant_type key
87 */
88#define OIDC_GRANT_TYPE_KEY "grant_type"
89
90/**
91 * OIDC grant_type key
92 */
93#define OIDC_GRANT_TYPE_VALUE "authorization_code"
94
95/**
96 * OIDC code key
97 */
98#define OIDC_CODE_KEY "code"
99
100/**
101 * OIDC response_type key
102 */
103#define OIDC_RESPONSE_TYPE_KEY "response_type"
104
105/**
106 * OIDC client_id key
107 */
108#define OIDC_CLIENT_ID_KEY "client_id"
109
110/**
111 * OIDC scope key
112 */
113#define OIDC_SCOPE_KEY "scope"
114
115/**
116 * OIDC redirect_uri key
117 */
118#define OIDC_REDIRECT_URI_KEY "redirect_uri"
119
120/**
121 * OIDC state key
122 */
123#define OIDC_STATE_KEY "state"
124
125/**
126 * OIDC nonce key
127 */
128#define OIDC_NONCE_KEY "nonce"
129
130/**
131 * OIDC claims key
132 */
133#define OIDC_CLAIMS_KEY "claims"
134
135/**
136 * OIDC PKCE code challenge
137 */
138#define OIDC_CODE_CHALLENGE_KEY "code_challenge"
139
140/**
141 * OIDC PKCE code verifier
142 */
143#define OIDC_CODE_VERIFIER_KEY "code_verifier"
144
145/**
146 * OIDC cookie expiration (in seconds)
147 */
148#define OIDC_COOKIE_EXPIRATION 3
149
150/**
151 * OIDC cookie header key
152 */
153#define OIDC_COOKIE_HEADER_KEY "cookie"
154
155/**
156 * OIDC cookie header information key
157 */
158#define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
159
160/**
161 * OIDC cookie header information key
162 */
163#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
164
165/**
166 * OIDC cookie header if user cancelled
167 */
168#define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
169
170/**
171 * OIDC expected response_type while authorizing
172 */
173#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
174
175/**
176 * OIDC expected scope part while authorizing
177 */
178#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
179
180/**
181 * OIDC error key for invalid client
182 */
183#define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
184
185/**
186 * OIDC error key for invalid scopes
187 */
188#define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
189
190/**
191 * OIDC error key for invalid requests
192 */
193#define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
194
195/**
196 * OIDC error key for invalid tokens
197 */
198#define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
199
200/**
201 * OIDC error key for invalid cookies
202 */
203#define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
204
205/**
206 * OIDC error key for generic server errors
207 */
208#define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
209
210/**
211 * OIDC error key for unsupported grants
212 */
213#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
214
215/**
216 * OIDC error key for unsupported response types
217 */
218#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
219
220/**
221 * OIDC error key for unauthorized clients
222 */
223#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
224
225/**
226 * OIDC error key for denied access
227 */
228#define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
229
230/**
231 * How long to wait for a consume in userinfo endpoint
232 */
233#define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \
234 GNUNET_TIME_UNIT_SECONDS,2)
235
236/**
237 * OIDC ignored parameter array
238 */
239static char *OIDC_ignored_parameter_array[] = { "display",
240 "prompt",
241 "ui_locales",
242 "response_mode",
243 "id_token_hint",
244 "login_hint",
245 "acr_values" };
246
247/**
248 * OIDC hashmap for cached access tokens and codes
249 */
250struct GNUNET_CONTAINER_MultiHashMap *oidc_code_cache;
251
252/**
253 * OIDC hashmap that keeps track of issued cookies
254 */
255struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map;
256
257/**
258 * The configuration handle
259 */
260const struct GNUNET_CONFIGURATION_Handle *cfg;
261
262/**
263 * HTTP methods allows for this plugin
264 */
265static char *allow_methods;
266
267/**
268 * Ego list
269 */
270static struct EgoEntry *ego_head;
271
272/**
273 * Ego list
274 */
275static struct EgoEntry *ego_tail;
276
277/**
278 * The processing state
279 */
280static int state;
281
282/**
283 * Handle to Identity service.
284 */
285static struct GNUNET_IDENTITY_Handle *identity_handle;
286
287/**
288 * GNS handle
289 */
290static struct GNUNET_GNS_Handle *gns_handle;
291
292/**
293 * Identity Provider
294 */
295static struct GNUNET_RECLAIM_Handle *idp;
296
297/**
298 * @brief struct returned by the initialization function of the plugin
299 */
300struct Plugin
301{
302 const struct GNUNET_CONFIGURATION_Handle *cfg;
303};
304
305/**
306 * OIDC needed variables
307 */
308struct OIDC_Variables
309{
310 /**
311 * The RP client public key
312 */
313 struct GNUNET_IDENTITY_PublicKey client_pkey;
314
315 /**
316 * The OIDC client id of the RP
317 */
318 char *client_id;
319
320 /**
321 * The OIDC redirect uri
322 */
323 char *redirect_uri;
324
325 /**
326 * The list of oidc scopes
327 */
328 char *scope;
329
330 /**
331 * The OIDC state
332 */
333 char *state;
334
335 /**
336 * The OIDC nonce
337 */
338 char *nonce;
339
340 /**
341 * The OIDC claims
342 */
343 char *claims;
344
345 /**
346 * The OIDC response type
347 */
348 char *response_type;
349
350 /**
351 * The identity chosen by the user to login
352 */
353 char *login_identity;
354
355 /**
356 * User cancelled authorization/login
357 */
358 int user_cancelled;
359
360 /**
361 * The PKCE code_challenge
362 */
363 char *code_challenge;
364
365 /**
366 * The PKCE code_verifier
367 */
368 char *code_verifier;
369
370};
371
372/**
373 * The ego list
374 */
375struct EgoEntry
376{
377 /**
378 * DLL
379 */
380 struct EgoEntry *next;
381
382 /**
383 * DLL
384 */
385 struct EgoEntry *prev;
386
387 /**
388 * Ego Identifier
389 */
390 char *identifier;
391
392 /**
393 * Public key string
394 */
395 char *keystring;
396
397 /**
398 * The Ego
399 */
400 struct GNUNET_IDENTITY_Ego *ego;
401};
402
403
404struct RequestHandle
405{
406 /**
407 * DLL
408 */
409 struct RequestHandle *next;
410
411 /**
412 * DLL
413 */
414 struct RequestHandle *prev;
415
416 /**
417 * Selected ego
418 */
419 struct EgoEntry *ego_entry;
420
421 /**
422 * Pointer to ego private key
423 */
424 struct GNUNET_IDENTITY_PrivateKey priv_key;
425
426 /**
427 * OIDC variables
428 */
429 struct OIDC_Variables *oidc;
430
431 /**
432 * GNS lookup op
433 */
434 struct GNUNET_GNS_LookupRequest *gns_op;
435
436 /**
437 * Rest connection
438 */
439 struct GNUNET_REST_RequestHandle *rest_handle;
440
441 /**
442 * Attribute claim list for id_token
443 */
444 struct GNUNET_RECLAIM_AttributeList *attr_idtoken_list;
445
446 /**
447 * Attribute claim list for userinfo
448 */
449 struct GNUNET_RECLAIM_AttributeList *attr_userinfo_list;
450
451 /**
452 * Credentials
453 */
454 struct GNUNET_RECLAIM_CredentialList *credentials;
455
456 /**
457 * Presentations
458 */
459 struct GNUNET_RECLAIM_PresentationList *presentations;
460
461 /**
462 * IDENTITY Operation
463 */
464 struct GNUNET_IDENTITY_Operation *op;
465
466
467 /**
468 * Idp Operation
469 */
470 struct GNUNET_RECLAIM_Operation *idp_op;
471
472 /**
473 * Timeout task for consume
474 */
475 struct GNUNET_SCHEDULER_Task *consume_timeout_op;
476
477 /**
478 * Attribute iterator
479 */
480 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
481
482 /**
483 * Credential iterator
484 */
485 struct GNUNET_RECLAIM_CredentialIterator *cred_it;
486
487
488 /**
489 * Ticket iterator
490 */
491 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
492
493 /**
494 * A ticket
495 */
496 struct GNUNET_RECLAIM_Ticket ticket;
497
498 /**
499 * Desired timeout for the lookup (default is no timeout).
500 */
501 struct GNUNET_TIME_Relative timeout;
502
503 /**
504 * ID of a task associated with the resolution process.
505 */
506 struct GNUNET_SCHEDULER_Task *timeout_task;
507
508 /**
509 * The plugin result processor
510 */
511 GNUNET_REST_ResultProcessor proc;
512
513 /**
514 * The closure of the result processor
515 */
516 void *proc_cls;
517
518 /**
519 * The url
520 */
521 char *url;
522
523 /**
524 * The passed access token
525 */
526 char *access_token;
527
528 /**
529 * The tld for redirect
530 */
531 char *tld;
532
533 /**
534 * The redirect prefix
535 */
536 char *redirect_prefix;
537
538 /**
539 * The redirect suffix
540 */
541 char *redirect_suffix;
542
543 /**
544 * Error response message
545 */
546 char *emsg;
547
548 /**
549 * Error response description
550 */
551 char *edesc;
552
553 /**
554 * Response code
555 */
556 int response_code;
557
558 /**
559 * Public client
560 */
561 int public_client;
562};
563
564/**
565 * DLL
566 */
567static struct RequestHandle *requests_head;
568
569/**
570 * DLL
571 */
572static struct RequestHandle *requests_tail;
573
574
575/**
576 * Cleanup lookup handle
577 * @param handle Handle to clean up
578 */
579static void
580cleanup_handle (struct RequestHandle *handle)
581{
582
583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
584 if (NULL != handle->timeout_task)
585 GNUNET_SCHEDULER_cancel (handle->timeout_task);
586 if (NULL != handle->attr_it)
587 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
588 if (NULL != handle->cred_it)
589 GNUNET_RECLAIM_get_credentials_stop (handle->cred_it);
590 if (NULL != handle->ticket_it)
591 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
592 if (NULL != handle->idp_op)
593 GNUNET_RECLAIM_cancel (handle->idp_op);
594 if (NULL != handle->consume_timeout_op)
595 GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
596 GNUNET_free (handle->url);
597 GNUNET_free (handle->tld);
598 GNUNET_free (handle->redirect_prefix);
599 GNUNET_free (handle->redirect_suffix);
600 GNUNET_free (handle->emsg);
601 GNUNET_free (handle->edesc);
602 if (NULL != handle->gns_op)
603 GNUNET_GNS_lookup_cancel (handle->gns_op);
604 if (NULL != handle->oidc)
605 {
606 GNUNET_free (handle->oidc->client_id);
607 GNUNET_free (handle->oidc->login_identity);
608 GNUNET_free (handle->oidc->nonce);
609 GNUNET_free (handle->oidc->redirect_uri);
610 GNUNET_free (handle->oidc->response_type);
611 GNUNET_free (handle->oidc->scope);
612 GNUNET_free (handle->oidc->state);
613 if (NULL != handle->oidc->claims)
614 GNUNET_free (handle->oidc->claims);
615 if (NULL != handle->oidc->code_challenge)
616 GNUNET_free (handle->oidc->code_challenge);
617 GNUNET_free (handle->oidc);
618 }
619 if (NULL!=handle->attr_idtoken_list)
620 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_idtoken_list);
621 if (NULL!=handle->attr_userinfo_list)
622 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_userinfo_list);
623 if (NULL!=handle->credentials)
624 GNUNET_RECLAIM_credential_list_destroy (handle->credentials);
625 if (NULL!=handle->presentations)
626 GNUNET_RECLAIM_presentation_list_destroy (handle->presentations);
627 GNUNET_CONTAINER_DLL_remove (requests_head,
628 requests_tail,
629 handle);
630 if (NULL != handle->access_token)
631 GNUNET_free (handle->access_token);
632 GNUNET_free (handle);
633}
634
635
636/**
637 * Task run on error, sends error message. Cleans up everything.
638 *
639 * @param cls the `struct RequestHandle`
640 */
641static void
642do_error (void *cls)
643{
644 struct RequestHandle *handle = cls;
645 struct MHD_Response *resp;
646 char *json_error;
647
648 GNUNET_asprintf (&json_error,
649 "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
650 handle->emsg,
651 (NULL != handle->edesc) ? handle->edesc : "",
652 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
653 (NULL != handle->oidc->state) ? handle->oidc->state : "",
654 (NULL != handle->oidc->state) ? "\"" : "");
655 if (0 == handle->response_code)
656 handle->response_code = MHD_HTTP_BAD_REQUEST;
657 resp = GNUNET_REST_create_response (json_error);
658 if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
659 GNUNET_assert (MHD_NO !=
660 MHD_add_response_header (resp,
661 MHD_HTTP_HEADER_WWW_AUTHENTICATE,
662 "Basic"));
663 MHD_add_response_header (resp,
664 MHD_HTTP_HEADER_CONTENT_TYPE,
665 "application/json");
666 handle->proc (handle->proc_cls, resp, handle->response_code);
667 cleanup_handle (handle);
668 GNUNET_free (json_error);
669}
670
671
672/**
673 * Task run on error in userinfo endpoint, sends error header. Cleans up
674 * everything
675 *
676 * @param cls the `struct RequestHandle`
677 */
678static void
679do_userinfo_error (void *cls)
680{
681 struct RequestHandle *handle = cls;
682 struct MHD_Response *resp;
683 char *error;
684
685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
686 "Error: %s\n", handle->edesc);
687 GNUNET_asprintf (&error,
688 "error=\"%s\", error_description=\"%s\"",
689 handle->emsg,
690 (NULL != handle->edesc) ? handle->edesc : "");
691 resp = GNUNET_REST_create_response ("");
692 GNUNET_assert (MHD_NO !=
693 MHD_add_response_header (resp,
694 MHD_HTTP_HEADER_WWW_AUTHENTICATE,
695 "Bearer"));
696 handle->proc (handle->proc_cls, resp, handle->response_code);
697 cleanup_handle (handle);
698 GNUNET_free (error);
699}
700
701
702/**
703 * Task run on error, sends error message and redirects. Cleans up everything.
704 *
705 * @param cls the `struct RequestHandle`
706 */
707static void
708do_redirect_error (void *cls)
709{
710 struct RequestHandle *handle = cls;
711 struct MHD_Response *resp;
712 char *redirect;
713
714 GNUNET_asprintf (&redirect,
715 "%s?error=%s&error_description=%s%s%s",
716 handle->oidc->redirect_uri,
717 handle->emsg,
718 handle->edesc,
719 (NULL != handle->oidc->state) ? "&state=" : "",
720 (NULL != handle->oidc->state) ? handle->oidc->state : "");
721 resp = GNUNET_REST_create_response ("");
722 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
723 "Location", redirect));
724 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
725 cleanup_handle (handle);
726 GNUNET_free (redirect);
727}
728
729
730/**
731 * Task run on timeout, sends error message. Cleans up everything.
732 *
733 * @param cls the `struct RequestHandle`
734 */
735static void
736do_timeout (void *cls)
737{
738 struct RequestHandle *handle = cls;
739
740 handle->timeout_task = NULL;
741 do_error (handle);
742}
743
744
745/**
746 * Respond to OPTIONS request
747 *
748 * @param con_handle the connection handle
749 * @param url the url
750 * @param cls the RequestHandle
751 */
752static void
753options_cont (struct GNUNET_REST_RequestHandle *con_handle,
754 const char *url,
755 void *cls)
756{
757 struct MHD_Response *resp;
758 struct RequestHandle *handle = cls;
759
760 // For now, independent of path return all options
761 resp = GNUNET_REST_create_response (NULL);
762 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
763 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
764 cleanup_handle (handle);
765 return;
766}
767
768
769/**
770 * Interprets cookie header and pass its identity keystring to handle
771 */
772static void
773cookie_identity_interpretation (struct RequestHandle *handle)
774{
775 struct GNUNET_HashCode cache_key;
776 char *cookies;
777 struct GNUNET_TIME_Absolute current_time, *relog_time;
778 char delimiter[] = "; ";
779 char *tmp_cookies;
780 char *token;
781 char *value;
782
783 // gets identity of login try with cookie
784 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY,
785 strlen (OIDC_COOKIE_HEADER_KEY),
786 &cache_key);
787 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
788 ->header_param_map,
789 &cache_key))
790 {
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
792 return;
793 }
794 // splits cookies and find 'Identity' cookie
795 tmp_cookies =
796 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
797 &cache_key);
798 cookies = GNUNET_strdup (tmp_cookies);
799 token = strtok (cookies, delimiter);
800 handle->oidc->user_cancelled = GNUNET_NO;
801 handle->oidc->login_identity = NULL;
802 if (NULL == token)
803 {
804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
805 "Unable to parse cookie: %s\n",
806 cookies);
807 GNUNET_free (cookies);
808 return;
809 }
810
811 while (NULL != token)
812 {
813 if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
814 {
815 handle->oidc->user_cancelled = GNUNET_YES;
816 GNUNET_free (cookies);
817 return;
818 }
819 if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
820 break;
821 token = strtok (NULL, delimiter);
822 }
823 if (NULL == token)
824 {
825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826 "No cookie value to process: %s\n",
827 cookies);
828 GNUNET_free (cookies);
829 return;
830 }
831 GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
832 if (GNUNET_NO ==
833 GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
834 {
835 GNUNET_log (
836 GNUNET_ERROR_TYPE_WARNING,
837 "Found cookie `%s', but no corresponding expiration entry present...\n",
838 token);
839 GNUNET_free (cookies);
840 return;
841 }
842 relog_time =
843 GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
844 current_time = GNUNET_TIME_absolute_get ();
845 // 30 min after old login -> redirect to login
846 if (current_time.abs_value_us > relog_time->abs_value_us)
847 {
848 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
849 "Found cookie `%s', but it is expired.\n",
850 token);
851 GNUNET_free (cookies);
852 return;
853 }
854 value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
855 GNUNET_assert (NULL != value);
856 handle->oidc->login_identity = GNUNET_strdup (value);
857 GNUNET_free (cookies);
858}
859
860
861/**
862 * Redirects to login page stored in configuration file
863 */
864static void
865login_redirect (void *cls)
866{
867 char *login_base_url;
868 char *new_redirect;
869 char *tmp;
870 struct MHD_Response *resp;
871 struct GNUNET_Buffer buf = { 0 };
872 struct RequestHandle *handle = cls;
873
874 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
875 "reclaim-rest-plugin",
876 "address",
877 &login_base_url))
878 {
879 GNUNET_buffer_write_str (&buf, login_base_url);
880 GNUNET_buffer_write_fstr (&buf,
881 "?%s=%s",
882 OIDC_RESPONSE_TYPE_KEY,
883 handle->oidc->response_type);
884 GNUNET_buffer_write_fstr (&buf,
885 "&%s=%s",
886 OIDC_CLIENT_ID_KEY,
887 handle->oidc->client_id);
888 GNUNET_STRINGS_urlencode (handle->oidc->redirect_uri,
889 strlen (handle->oidc->redirect_uri),
890 &tmp);
891 GNUNET_buffer_write_fstr (&buf,
892 "&%s=%s",
893 OIDC_REDIRECT_URI_KEY,
894 tmp);
895 GNUNET_free (tmp);
896 GNUNET_STRINGS_urlencode (handle->oidc->scope,
897 strlen (handle->oidc->scope),
898 &tmp);
899 GNUNET_buffer_write_fstr (&buf,
900 "&%s=%s",
901 OIDC_SCOPE_KEY,
902 tmp);
903 GNUNET_free (tmp);
904 if (NULL != handle->oidc->state)
905 {
906 GNUNET_STRINGS_urlencode (handle->oidc->state,
907 strlen (handle->oidc->state),
908 &tmp);
909 GNUNET_buffer_write_fstr (&buf,
910 "&%s=%s",
911 OIDC_STATE_KEY,
912 handle->oidc->state);
913 GNUNET_free (tmp);
914 }
915 if (NULL != handle->oidc->code_challenge)
916 {
917 GNUNET_buffer_write_fstr (&buf,
918 "&%s=%s",
919 OIDC_CODE_CHALLENGE_KEY,
920 handle->oidc->code_challenge);
921 }
922 if (NULL != handle->oidc->nonce)
923 {
924 GNUNET_buffer_write_fstr (&buf,
925 "&%s=%s",
926 OIDC_NONCE_KEY,
927 handle->oidc->nonce);
928 }
929 if (NULL != handle->oidc->claims)
930 {
931 GNUNET_STRINGS_urlencode (handle->oidc->claims,
932 strlen (handle->oidc->claims),
933 &tmp);
934 GNUNET_buffer_write_fstr (&buf,
935 "&%s=%s",
936 OIDC_CLAIMS_KEY,
937 tmp);
938 GNUNET_free (tmp);
939 }
940 new_redirect = GNUNET_buffer_reap_str (&buf);
941 resp = GNUNET_REST_create_response ("");
942 MHD_add_response_header (resp, "Location", new_redirect);
943 GNUNET_free (login_base_url);
944 }
945 else
946 {
947 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
948 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
949 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
950 GNUNET_SCHEDULER_add_now (&do_error, handle);
951 return;
952 }
953 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
954 GNUNET_free (new_redirect);
955 cleanup_handle (handle);
956}
957
958
959/**
960 * Does internal server error when iteration failed.
961 */
962static void
963oidc_iteration_error (void *cls)
964{
965 struct RequestHandle *handle = cls;
966
967 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
968 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
969 GNUNET_SCHEDULER_add_now (&do_error, handle);
970}
971
972
973/**
974 * Issues ticket and redirects to relying party with the authorization code as
975 * parameter. Otherwise redirects with error
976 */
977static void
978oidc_ticket_issue_cb (void *cls,
979 const struct GNUNET_RECLAIM_Ticket *ticket,
980 const struct
981 GNUNET_RECLAIM_PresentationList *presentation)
982{
983 struct RequestHandle *handle = cls;
984 struct MHD_Response *resp;
985 char *ticket_str;
986 char *redirect_uri;
987 char *code_string;
988
989 handle->idp_op = NULL;
990 if (NULL == ticket)
991 {
992 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
993 handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
994 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
995 return;
996 }
997 handle->ticket = *ticket;
998 ticket_str =
999 GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
1000 sizeof(struct GNUNET_RECLAIM_Ticket));
1001 code_string = OIDC_build_authz_code (&handle->priv_key,
1002 &handle->ticket,
1003 handle->attr_idtoken_list,
1004 presentation,
1005 handle->oidc->nonce,
1006 handle->oidc->code_challenge);
1007 if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
1008 (NULL != handle->tld))
1009 {
1010 GNUNET_asprintf (&redirect_uri,
1011 "%s.%s/%s%s%s=%s&state=%s",
1012 handle->redirect_prefix,
1013 handle->tld,
1014 handle->redirect_suffix,
1015 (NULL == strchr (handle->redirect_suffix, '?') ? "?" :
1016 "&"),
1017 handle->oidc->response_type,
1018 code_string,
1019 handle->oidc->state);
1020 }
1021 else
1022 {
1023 GNUNET_asprintf (&redirect_uri,
1024 "%s%s%s=%s&state=%s",
1025 handle->oidc->redirect_uri,
1026 (NULL == strchr (handle->oidc->redirect_uri, '?') ? "?" :
1027 "&"),
1028 handle->oidc->response_type,
1029 code_string,
1030 handle->oidc->state);
1031 }
1032 resp = GNUNET_REST_create_response ("");
1033 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1034 "Location", redirect_uri));
1035 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1036 cleanup_handle (handle);
1037 GNUNET_free (redirect_uri);
1038 GNUNET_free (ticket_str);
1039 GNUNET_free (code_string);
1040}
1041
1042
1043static struct GNUNET_RECLAIM_AttributeList*
1044attribute_list_merge (struct GNUNET_RECLAIM_AttributeList *list_a,
1045 struct GNUNET_RECLAIM_AttributeList *list_b)
1046{
1047 struct GNUNET_RECLAIM_AttributeList *merged_list;
1048 struct GNUNET_RECLAIM_AttributeListEntry *le_a;
1049 struct GNUNET_RECLAIM_AttributeListEntry *le_b;
1050 struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1051
1052 merged_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1053 for (le_a = list_a->list_head; NULL != le_a; le_a = le_a->next)
1054 {
1055 le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1056 le_m->attribute = GNUNET_RECLAIM_attribute_new (le_a->attribute->name,
1057 &le_a->attribute->
1058 credential,
1059 le_a->attribute->type,
1060 le_a->attribute->data,
1061 le_a->attribute->data_size);
1062 le_m->attribute->id = le_a->attribute->id;
1063 le_m->attribute->flag = le_a->attribute->flag;
1064 le_m->attribute->credential = le_a->attribute->credential;
1065 GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1066 merged_list->list_tail,
1067 le_m);
1068 }
1069 le_m = NULL;
1070 for (le_b = list_b->list_head; NULL != le_b; le_b = le_b->next)
1071 {
1072 for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1073 {
1074 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&le_m->attribute->id,
1075 &le_b->attribute->id))
1076 break; /** Attribute already in list **/
1077 }
1078 if (NULL != le_m)
1079 continue; /** Attribute already in list **/
1080 le_m = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1081 le_m->attribute = GNUNET_RECLAIM_attribute_new (le_b->attribute->name,
1082 &le_b->attribute->
1083 credential,
1084 le_b->attribute->type,
1085 le_b->attribute->data,
1086 le_b->attribute->data_size);
1087 le_m->attribute->id = le_b->attribute->id;
1088 le_m->attribute->flag = le_b->attribute->flag;
1089 le_m->attribute->credential = le_b->attribute->credential;
1090 GNUNET_CONTAINER_DLL_insert (merged_list->list_head,
1091 merged_list->list_tail,
1092 le_m);
1093 }
1094 return merged_list;
1095}
1096
1097
1098static void
1099oidc_cred_collect_finished_cb (void *cls)
1100{
1101 struct RequestHandle *handle = cls;
1102 struct GNUNET_RECLAIM_AttributeList *merged_list;
1103 struct GNUNET_RECLAIM_AttributeListEntry *le_m;
1104
1105 handle->cred_it = NULL;
1106 merged_list = attribute_list_merge (handle->attr_idtoken_list,
1107 handle->attr_userinfo_list);
1108 for (le_m = merged_list->list_head; NULL != le_m; le_m = le_m->next)
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110 "List Attribute in ticket to issue: %s\n",
1111 le_m->attribute->name);
1112 handle->idp_op = GNUNET_RECLAIM_ticket_issue (idp,
1113 &handle->priv_key,
1114 &handle->oidc->client_pkey,
1115 merged_list,
1116 &oidc_ticket_issue_cb,
1117 handle);
1118 GNUNET_RECLAIM_attribute_list_destroy (merged_list);
1119}
1120
1121
1122/**
1123 * Collects all attributes for an ego if in scope parameter
1124 */
1125static void
1126oidc_cred_collect (void *cls,
1127 const struct GNUNET_IDENTITY_PublicKey *identity,
1128 const struct GNUNET_RECLAIM_Credential *cred)
1129{
1130 struct RequestHandle *handle = cls;
1131 struct GNUNET_RECLAIM_AttributeListEntry *le;
1132 struct GNUNET_RECLAIM_CredentialListEntry *ale;
1133
1134 for (ale = handle->credentials->list_head; NULL != ale; ale = ale->next)
1135 {
1136 if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&ale->credential->id,
1137 &cred->id))
1138 continue;
1139 /** Credential already in list **/
1140 GNUNET_RECLAIM_get_credentials_next (handle->cred_it);
1141 return;
1142 }
1143
1144 for (le = handle->attr_idtoken_list->list_head; NULL != le; le = le->next)
1145 {
1146 if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->credential,
1147 &cred->id))
1148 continue;
1149 /** Credential matches for attribute, add **/
1150 ale = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry);
1151 ale->credential = GNUNET_RECLAIM_credential_new (cred->name,
1152 cred->type,
1153 cred->data,
1154 cred->data_size);
1155 GNUNET_CONTAINER_DLL_insert (handle->credentials->list_head,
1156 handle->credentials->list_tail,
1157 ale);
1158 }
1159 GNUNET_RECLAIM_get_credentials_next (handle->cred_it);
1160}
1161
1162
1163static void
1164oidc_attr_collect_finished_cb (void *cls)
1165{
1166 struct RequestHandle *handle = cls;
1167
1168 handle->attr_it = NULL;
1169 handle->ticket_it = NULL;
1170 if (NULL == handle->attr_idtoken_list->list_head)
1171 {
1172 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
1173 handle->edesc = GNUNET_strdup ("The requested scope is not available.");
1174 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1175 return;
1176 }
1177 handle->credentials = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
1178 handle->cred_it =
1179 GNUNET_RECLAIM_get_credentials_start (idp,
1180 &handle->priv_key,
1181 &oidc_iteration_error,
1182 handle,
1183 &oidc_cred_collect,
1184 handle,
1185 &oidc_cred_collect_finished_cb,
1186 handle);
1187
1188}
1189
1190
1191static int
1192attr_in_claims_request (struct RequestHandle *handle,
1193 const char *attr_name,
1194 const char *claims_parameter)
1195{
1196 int ret = GNUNET_NO;
1197 json_t *root;
1198 json_error_t error;
1199 json_t *claims_j;
1200 const char *key;
1201 json_t *value;
1202
1203 /** Check if attribute is requested through a scope **/
1204 if (GNUNET_YES == OIDC_check_scopes_for_claim_request (handle->oidc->scope,
1205 attr_name))
1206 return GNUNET_YES;
1207
1208 /** Try claims parameter if not in scope */
1209 if (NULL != handle->oidc->claims)
1210 {
1211 root = json_loads (handle->oidc->claims, JSON_DECODE_ANY, &error);
1212 claims_j = json_object_get (root, claims_parameter);
1213 /* obj is a JSON object */
1214 if (NULL != claims_j)
1215 {
1216 json_object_foreach (claims_j, key, value) {
1217 if (0 != strcmp (attr_name, key))
1218 continue;
1219 ret = GNUNET_YES;
1220 break;
1221 }
1222 }
1223 json_decref (root);
1224 }
1225 return ret;
1226}
1227
1228
1229static int
1230attr_in_idtoken_request (struct RequestHandle *handle,
1231 const char *attr_name)
1232{
1233 return attr_in_claims_request (handle, attr_name, "id_token");
1234}
1235
1236
1237static int
1238attr_in_userinfo_request (struct RequestHandle *handle,
1239 const char *attr_name)
1240{
1241 return attr_in_claims_request (handle, attr_name, "userinfo");
1242}
1243
1244
1245/**
1246 * Collects all attributes for an ego if in scope parameter
1247 */
1248static void
1249oidc_attr_collect (void *cls,
1250 const struct GNUNET_IDENTITY_PublicKey *identity,
1251 const struct GNUNET_RECLAIM_Attribute *attr)
1252{
1253 struct RequestHandle *handle = cls;
1254 struct GNUNET_RECLAIM_AttributeListEntry *le;
1255 if (GNUNET_YES == attr_in_idtoken_request (handle, attr->name))
1256 {
1257 le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1258 le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
1259 &attr->credential,
1260 attr->type,
1261 attr->data,
1262 attr->data_size);
1263 le->attribute->id = attr->id;
1264 le->attribute->flag = attr->flag;
1265 le->attribute->credential = attr->credential;
1266 GNUNET_CONTAINER_DLL_insert (handle->attr_idtoken_list->list_head,
1267 handle->attr_idtoken_list->list_tail,
1268 le);
1269 }
1270 if (GNUNET_YES == attr_in_userinfo_request (handle, attr->name))
1271 {
1272 le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1273 le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
1274 &attr->credential,
1275 attr->type,
1276 attr->data,
1277 attr->data_size);
1278 le->attribute->id = attr->id;
1279 le->attribute->flag = attr->flag;
1280 le->attribute->credential = attr->credential;
1281 GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
1282 handle->attr_userinfo_list->list_tail,
1283 le);
1284 }
1285
1286 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1287}
1288
1289
1290/**
1291 * Checks time and cookie and redirects accordingly
1292 */
1293static void
1294code_redirect (void *cls)
1295{
1296 struct RequestHandle *handle = cls;
1297 struct GNUNET_TIME_Absolute current_time;
1298 struct GNUNET_TIME_Absolute *relog_time;
1299 struct GNUNET_IDENTITY_PublicKey pubkey;
1300 struct GNUNET_IDENTITY_PublicKey ego_pkey;
1301 struct GNUNET_HashCode cache_key;
1302 char *identity_cookie;
1303
1304 GNUNET_asprintf (&identity_cookie,
1305 "Identity=%s",
1306 handle->oidc->login_identity);
1307 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1308 GNUNET_free (identity_cookie);
1309 // No login time for identity -> redirect to login
1310 if (GNUNET_YES ==
1311 GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
1312 {
1313 relog_time =
1314 GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1315 current_time = GNUNET_TIME_absolute_get ();
1316 // 30 min after old login -> redirect to login
1317 if (current_time.abs_value_us <= relog_time->abs_value_us)
1318 {
1319 if (GNUNET_OK !=
1320 GNUNET_IDENTITY_public_key_from_string (handle->oidc
1321 ->login_identity,
1322 &pubkey))
1323 {
1324 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE);
1325 handle->edesc =
1326 GNUNET_strdup ("The cookie of a login identity is not valid");
1327 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1328 return;
1329 }
1330 // iterate over egos and compare their public key
1331 for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
1332 handle->ego_entry = handle->ego_entry->next)
1333 {
1334 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1335 if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
1336 {
1337 handle->priv_key =
1338 *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1339 handle->attr_idtoken_list =
1340 GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1341 handle->attr_userinfo_list =
1342 GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1343 handle->attr_it =
1344 GNUNET_RECLAIM_get_attributes_start (idp,
1345 &handle->priv_key,
1346 &oidc_iteration_error,
1347 handle,
1348 &oidc_attr_collect,
1349 handle,
1350 &oidc_attr_collect_finished_cb,
1351 handle);
1352 return;
1353 }
1354 }
1355 GNUNET_SCHEDULER_add_now (&login_redirect, handle);
1356 return;
1357 }
1358 }
1359}
1360
1361
1362static void
1363build_redirect (void *cls)
1364{
1365 struct RequestHandle *handle = cls;
1366 struct MHD_Response *resp;
1367 char *redirect_uri;
1368
1369 if (GNUNET_YES == handle->oidc->user_cancelled)
1370 {
1371 if ((NULL != handle->redirect_prefix) &&
1372 (NULL != handle->redirect_suffix) && (NULL != handle->tld))
1373 {
1374 GNUNET_asprintf (&redirect_uri,
1375 "%s.%s/%s?error=%s&error_description=%s&state=%s",
1376 handle->redirect_prefix,
1377 handle->tld,
1378 handle->redirect_suffix,
1379 "access_denied",
1380 "User denied access",
1381 handle->oidc->state);
1382 }
1383 else
1384 {
1385 GNUNET_asprintf (&redirect_uri,
1386 "%s?error=%s&error_description=%s&state=%s",
1387 handle->oidc->redirect_uri,
1388 "access_denied",
1389 "User denied access",
1390 handle->oidc->state);
1391 }
1392 resp = GNUNET_REST_create_response ("");
1393 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1394 "Location",
1395 redirect_uri));
1396 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1397 cleanup_handle (handle);
1398 GNUNET_free (redirect_uri);
1399 return;
1400 }
1401 GNUNET_SCHEDULER_add_now (&code_redirect, handle);
1402}
1403
1404
1405static void
1406lookup_redirect_uri_result (void *cls,
1407 uint32_t rd_count,
1408 const struct GNUNET_GNSRECORD_Data *rd)
1409{
1410 struct RequestHandle *handle = cls;
1411 char *tmp;
1412 char *tmp_key_str;
1413 char *pos;
1414 struct GNUNET_IDENTITY_PublicKey redirect_zone;
1415
1416 handle->gns_op = NULL;
1417 if (0 == rd_count)
1418 {
1419 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
1420 handle->edesc =
1421 GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1422 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1423 return;
1424 }
1425 for (int i = 0; i < rd_count; i++)
1426 {
1427 if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
1428 continue;
1429 if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
1430 continue;
1431 tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
1432 if (NULL == strstr (tmp, handle->oidc->client_id))
1433 {
1434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1435 "Redirect uri %s does not contain client_id %s\n",
1436 tmp,
1437 handle->oidc->client_id);
1438 }
1439 else
1440 {
1441 pos = strrchr (tmp, (unsigned char) '.');
1442 if (NULL == pos)
1443 {
1444 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1445 "Redirect uri %s contains client_id but is malformed\n",
1446 tmp);
1447 GNUNET_free (tmp);
1448 continue;
1449 }
1450 *pos = '\0';
1451 handle->redirect_prefix = GNUNET_strdup (tmp);
1452 tmp_key_str = pos + 1;
1453 pos = strchr (tmp_key_str, (unsigned char) '/');
1454 if (NULL == pos)
1455 {
1456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1457 "Redirect uri %s contains client_id but is malformed\n",
1458 tmp);
1459 GNUNET_free (tmp);
1460 continue;
1461 }
1462 *pos = '\0';
1463 handle->redirect_suffix = GNUNET_strdup (pos + 1);
1464
1465 GNUNET_STRINGS_string_to_data (tmp_key_str,
1466 strlen (tmp_key_str),
1467 &redirect_zone,
1468 sizeof(redirect_zone));
1469 }
1470 GNUNET_SCHEDULER_add_now (&build_redirect, handle);
1471 GNUNET_free (tmp);
1472 return;
1473 }
1474 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
1475 handle->edesc =
1476 GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
1477 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1478}
1479
1480
1481/**
1482 * Initiate redirect back to client.
1483 */
1484static void
1485client_redirect (void *cls)
1486{
1487 struct RequestHandle *handle = cls;
1488
1489 /* Lookup client redirect uri to verify request */
1490 handle->gns_op =
1491 GNUNET_GNS_lookup (gns_handle,
1492 GNUNET_GNS_EMPTY_LABEL_AT,
1493 &handle->oidc->client_pkey,
1494 GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT,
1495 GNUNET_GNS_LO_DEFAULT,
1496 &lookup_redirect_uri_result,
1497 handle);
1498}
1499
1500
1501static char *
1502get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
1503{
1504 struct GNUNET_HashCode hc;
1505 char *value;
1506 char *res;
1507
1508 GNUNET_CRYPTO_hash (key, strlen (key), &hc);
1509 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
1510 ->url_param_map,
1511 &hc))
1512 return NULL;
1513 value =
1514 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
1515 if (NULL == value)
1516 return NULL;
1517 GNUNET_STRINGS_urldecode (value, strlen (value), &res);
1518 return res;
1519}
1520
1521
1522/**
1523 * Iteration over all results finished, build final
1524 * response.
1525 *
1526 * @param cls the `struct RequestHandle`
1527 */
1528static void
1529build_authz_response (void *cls)
1530{
1531 struct RequestHandle *handle = cls;
1532 struct GNUNET_HashCode cache_key;
1533
1534 char *expected_scope;
1535 char delimiter[] = " ";
1536 int number_of_ignored_parameter, iterator;
1537
1538
1539 // REQUIRED value: redirect_uri
1540 handle->oidc->redirect_uri =
1541 get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY);
1542 if (NULL == handle->oidc->redirect_uri)
1543 {
1544 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
1545 handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
1546 GNUNET_SCHEDULER_add_now (&do_error, handle);
1547 return;
1548 }
1549
1550 // REQUIRED value: response_type
1551 handle->oidc->response_type =
1552 get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY);
1553 if (NULL == handle->oidc->response_type)
1554 {
1555 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
1556 handle->edesc = GNUNET_strdup ("missing parameter response_type");
1557 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1558 return;
1559 }
1560
1561 // REQUIRED value: scope
1562 handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
1563 if (NULL == handle->oidc->scope)
1564 {
1565 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
1566 handle->edesc = GNUNET_strdup ("missing parameter scope");
1567 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1568 return;
1569 }
1570
1571 // OPTIONAL value: nonce
1572 handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
1573
1574 // OPTIONAL value: claims
1575 handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
1576
1577 // TODO check other values if needed
1578 number_of_ignored_parameter =
1579 sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1580 for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
1581 {
1582 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1583 strlen (OIDC_ignored_parameter_array[iterator]),
1584 &cache_key);
1585 if (GNUNET_YES ==
1586 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
1587 ->url_param_map,
1588 &cache_key))
1589 {
1590 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED);
1591 GNUNET_asprintf (&handle->edesc,
1592 "Server will not handle parameter: %s",
1593 OIDC_ignored_parameter_array[iterator]);
1594 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1595 return;
1596 }
1597 }
1598
1599 // We only support authorization code flows.
1600 if (0 != strcmp (handle->oidc->response_type,
1601 OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE))
1602 {
1603 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE);
1604 handle->edesc = GNUNET_strdup ("The authorization server does not support "
1605 "obtaining this authorization code.");
1606 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1607 return;
1608 }
1609
1610 // Checks if scope contains 'openid'
1611 expected_scope = GNUNET_strdup (handle->oidc->scope);
1612 char *test;
1613 test = strtok (expected_scope, delimiter);
1614 while (NULL != test)
1615 {
1616 if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
1617 break;
1618 test = strtok (NULL, delimiter);
1619 }
1620 if (NULL == test)
1621 {
1622 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
1623 handle->edesc =
1624 GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
1625 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1626 GNUNET_free (expected_scope);
1627 return;
1628 }
1629
1630 GNUNET_free (expected_scope);
1631 if ((NULL == handle->oidc->login_identity) &&
1632 (GNUNET_NO == handle->oidc->user_cancelled))
1633 GNUNET_SCHEDULER_add_now (&login_redirect, handle);
1634 else
1635 GNUNET_SCHEDULER_add_now (&client_redirect, handle);
1636}
1637
1638
1639/**
1640 * Iterate over tlds in config
1641 */
1642static void
1643tld_iter (void *cls, const char *section, const char *option, const char *value)
1644{
1645 struct RequestHandle *handle = cls;
1646 struct GNUNET_IDENTITY_PublicKey pkey;
1647
1648 if (GNUNET_OK !=
1649 GNUNET_IDENTITY_public_key_from_string (value, &pkey))
1650 {
1651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
1652 return;
1653 }
1654 if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1655 handle->tld = GNUNET_strdup (option + 1);
1656}
1657
1658
1659/**
1660 * Responds to authorization GET and url-encoded POST request
1661 *
1662 * @param con_handle the connection handle
1663 * @param url the url
1664 * @param cls the RequestHandle
1665 */
1666static void
1667authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1668 const char *url,
1669 void *cls)
1670{
1671 struct RequestHandle *handle = cls;
1672 struct EgoEntry *tmp_ego;
1673 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
1674 struct GNUNET_IDENTITY_PublicKey pkey;
1675
1676 cookie_identity_interpretation (handle);
1677
1678 // RECOMMENDED value: state - REQUIRED for answers
1679 handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
1680
1681 // REQUIRED value: client_id
1682 handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
1683 if (NULL == handle->oidc->client_id)
1684 {
1685 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
1686 handle->edesc = GNUNET_strdup ("missing parameter client_id");
1687 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1688 GNUNET_SCHEDULER_add_now (&do_error, handle);
1689 return;
1690 }
1691
1692 // OPTIONAL value: code_challenge
1693 handle->oidc->code_challenge = get_url_parameter_copy (handle,
1694 OIDC_CODE_CHALLENGE_KEY);
1695 if (NULL == handle->oidc->code_challenge)
1696 {
1697 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1698 "OAuth authorization request does not contain PKCE parameters!\n");
1699 }
1700
1701 if (GNUNET_OK !=
1702 GNUNET_IDENTITY_public_key_from_string (handle->oidc->client_id,
1703 &handle->oidc->client_pkey))
1704 {
1705 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT);
1706 handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
1707 "authorization code using this method.");
1708 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1709 GNUNET_SCHEDULER_add_now (&do_error, handle);
1710 return;
1711 }
1712
1713 // If we know this identity, translated the corresponding TLD
1714 // TODO: We might want to have a reverse lookup functionality for TLDs?
1715 for (tmp_ego = ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1716 {
1717 priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1718 GNUNET_IDENTITY_key_get_public (priv_key, &pkey);
1719 if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
1720 {
1721 handle->tld = GNUNET_strdup (tmp_ego->identifier);
1722 handle->ego_entry = ego_tail;
1723 }
1724 }
1725 if (NULL == handle->tld)
1726 GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle);
1727 if (NULL == handle->tld)
1728 handle->tld = GNUNET_strdup (handle->oidc->client_id);
1729 GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
1730}
1731
1732
1733/**
1734 * Combines an identity with a login time and responds OK to login request
1735 *
1736 * @param con_handle the connection handle
1737 * @param url the url
1738 * @param cls the RequestHandle
1739 */
1740static void
1741login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1742 const char *url,
1743 void *cls)
1744{
1745 struct MHD_Response *resp = GNUNET_REST_create_response ("");
1746 struct RequestHandle *handle = cls;
1747 struct GNUNET_HashCode cache_key;
1748 struct GNUNET_TIME_Absolute *current_time;
1749 struct GNUNET_TIME_Absolute *last_time;
1750 char *cookie;
1751 char *header_val;
1752 json_t *root;
1753 json_error_t error;
1754 json_t *identity;
1755 char term_data[handle->rest_handle->data_size + 1];
1756
1757 term_data[handle->rest_handle->data_size] = '\0';
1758 GNUNET_memcpy (term_data,
1759 handle->rest_handle->data,
1760 handle->rest_handle->data_size);
1761 root = json_loads (term_data, JSON_DECODE_ANY, &error);
1762 identity = json_object_get (root, "identity");
1763 if (! json_is_string (identity))
1764 {
1765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1766 "Error parsing json string from %s\n",
1767 term_data);
1768 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1769 json_decref (root);
1770 cleanup_handle (handle);
1771 return;
1772 }
1773 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1774 GNUNET_asprintf (&header_val,
1775 "%s;Max-Age=%d",
1776 cookie,
1777 OIDC_COOKIE_EXPIRATION);
1778 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
1779 "Set-Cookie", header_val));
1780 GNUNET_assert (MHD_NO !=
1781 MHD_add_response_header (resp,
1782 "Access-Control-Allow-Methods",
1783 "POST"));
1784 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1785
1786 if (0 != strcmp (json_string_value (identity), "Denied"))
1787 {
1788 current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
1789 *current_time = GNUNET_TIME_relative_to_absolute (
1790 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
1791 OIDC_COOKIE_EXPIRATION));
1792 last_time =
1793 GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
1794 GNUNET_free (last_time);
1795 GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
1796 &cache_key,
1797 current_time,
1798 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1799 }
1800 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1801 GNUNET_free (cookie);
1802 GNUNET_free (header_val);
1803 json_decref (root);
1804 cleanup_handle (handle);
1805}
1806
1807
1808static int
1809parse_credentials_basic_auth (struct RequestHandle *handle,
1810 char **client_id,
1811 char **client_secret)
1812{
1813 struct GNUNET_HashCode cache_key;
1814 char *authorization;
1815 char *credentials;
1816 char *basic_authorization;
1817 char *client_id_tmp;
1818 char *pass;
1819
1820 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1821 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1822 &cache_key);
1823 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
1824 ->header_param_map,
1825 &cache_key))
1826 return GNUNET_SYSERR;
1827 authorization =
1828 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
1829 &cache_key);
1830
1831 // split header in "Basic" and [content]
1832 credentials = strtok (authorization, " ");
1833 if ((NULL == credentials) || (0 != strcmp ("Basic", credentials)))
1834 return GNUNET_SYSERR;
1835 credentials = strtok (NULL, " ");
1836 if (NULL == credentials)
1837 return GNUNET_SYSERR;
1838 GNUNET_STRINGS_base64_decode (credentials,
1839 strlen (credentials),
1840 (void **) &basic_authorization);
1841
1842 if (NULL == basic_authorization)
1843 return GNUNET_SYSERR;
1844 client_id_tmp = strtok (basic_authorization, ":");
1845 if (NULL == client_id_tmp)
1846 {
1847 GNUNET_free (basic_authorization);
1848 return GNUNET_SYSERR;
1849 }
1850 pass = strtok (NULL, ":");
1851 if (NULL == pass)
1852 {
1853 GNUNET_free (basic_authorization);
1854 return GNUNET_SYSERR;
1855 }
1856 *client_id = strdup (client_id_tmp);
1857 *client_secret = strdup (pass);
1858 GNUNET_free (basic_authorization);
1859 return GNUNET_OK;
1860}
1861
1862
1863static int
1864parse_credentials_post_body (struct RequestHandle *handle,
1865 char **client_id,
1866 char **client_secret)
1867{
1868 struct GNUNET_HashCode cache_key;
1869 char *client_id_tmp;
1870 char *pass;
1871
1872 GNUNET_CRYPTO_hash ("client_id",
1873 strlen ("client_id"),
1874 &cache_key);
1875 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
1876 ->url_param_map,
1877 &cache_key))
1878 return GNUNET_SYSERR;
1879 client_id_tmp = GNUNET_CONTAINER_multihashmap_get (
1880 handle->rest_handle->url_param_map,
1881 &cache_key);
1882 if (NULL == client_id_tmp)
1883 return GNUNET_SYSERR;
1884 *client_id = strdup (client_id_tmp);
1885 GNUNET_CRYPTO_hash ("client_secret",
1886 strlen ("client_secret"),
1887 &cache_key);
1888 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
1889 ->url_param_map,
1890 &cache_key))
1891 {
1892 GNUNET_free (*client_id);
1893 *client_id = NULL;
1894 return GNUNET_SYSERR;
1895 }
1896 pass = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1897 &cache_key);
1898 if (NULL == pass)
1899 {
1900 GNUNET_free (*client_id);
1901 *client_id = NULL;
1902 return GNUNET_SYSERR;
1903 }
1904 *client_secret = strdup (pass);
1905 return GNUNET_OK;
1906}
1907
1908
1909static int
1910check_authorization (struct RequestHandle *handle,
1911 struct GNUNET_IDENTITY_PublicKey *cid)
1912{
1913 char *expected_pass;
1914 char *received_cid;
1915 char *received_cpw;
1916 char *pkce_cv;
1917
1918 if (GNUNET_OK == parse_credentials_basic_auth (handle,
1919 &received_cid,
1920 &received_cpw))
1921 {
1922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1923 "Received client credentials in HTTP AuthZ header\n");
1924 }
1925 else if (GNUNET_OK == parse_credentials_post_body (handle,
1926 &received_cid,
1927 &received_cpw))
1928 {
1929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1930 "Received client credentials in POST body\n");
1931 }
1932 else
1933 {
1934 /** Allow public clients with PKCE **/
1935 pkce_cv = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
1936 if (NULL == pkce_cv)
1937 {
1938 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
1939 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1940 return GNUNET_SYSERR;
1941 }
1942 handle->public_client = GNUNET_YES;
1943 GNUNET_free (pkce_cv);
1944 received_cid = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
1945 GNUNET_STRINGS_string_to_data (received_cid,
1946 strlen (received_cid),
1947 cid,
1948 sizeof(struct GNUNET_IDENTITY_PublicKey));
1949 GNUNET_free (received_cid);
1950 return GNUNET_OK;
1951
1952 }
1953
1954 // check client password
1955 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1956 "reclaim-rest-plugin",
1957 "OIDC_CLIENT_SECRET",
1958 &expected_pass))
1959 {
1960 if (0 != strcmp (expected_pass, received_cpw))
1961 {
1962 GNUNET_free (expected_pass);
1963 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
1964 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1965 GNUNET_free (received_cpw);
1966 GNUNET_free (received_cid);
1967 return GNUNET_SYSERR;
1968 }
1969 GNUNET_free (expected_pass);
1970 }
1971 else
1972 {
1973 GNUNET_free (received_cpw);
1974 GNUNET_free (received_cid);
1975 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
1976 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1977 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1978 return GNUNET_SYSERR;
1979 }
1980 // check client_id
1981 for (handle->ego_entry = ego_head; NULL != handle->ego_entry;
1982 handle->ego_entry = handle->ego_entry->next)
1983 {
1984 if (0 == strcmp (handle->ego_entry->keystring, received_cid))
1985 break;
1986 }
1987 if (NULL == handle->ego_entry)
1988 {
1989 GNUNET_free (received_cpw);
1990 GNUNET_free (received_cid);
1991 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
1992 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1993 return GNUNET_SYSERR;
1994 }
1995 GNUNET_STRINGS_string_to_data (received_cid,
1996 strlen (received_cid),
1997 cid,
1998 sizeof(struct GNUNET_IDENTITY_PublicKey));
1999
2000 GNUNET_free (received_cpw);
2001 GNUNET_free (received_cid);
2002 return GNUNET_OK;
2003}
2004
2005
2006const struct EgoEntry *
2007find_ego (struct RequestHandle *handle,
2008 struct GNUNET_IDENTITY_PublicKey *test_key)
2009{
2010 struct EgoEntry *ego_entry;
2011 struct GNUNET_IDENTITY_PublicKey pub_key;
2012
2013 for (ego_entry = ego_head; NULL != ego_entry;
2014 ego_entry = ego_entry->next)
2015 {
2016 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2017 if (0 == GNUNET_memcmp (&pub_key, test_key))
2018 return ego_entry;
2019 }
2020 return NULL;
2021}
2022
2023
2024/**
2025 * Responds to token url-encoded POST request
2026 *
2027 * @param con_handle the connection handle
2028 * @param url the url
2029 * @param cls the RequestHandle
2030 */
2031static void
2032token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2033 const char *url,
2034 void *cls)
2035{
2036 struct RequestHandle *handle = cls;
2037 const struct EgoEntry *ego_entry;
2038 struct GNUNET_TIME_Relative expiration_time;
2039 struct GNUNET_RECLAIM_AttributeList *cl = NULL;
2040 struct GNUNET_RECLAIM_PresentationList *pl = NULL;
2041 struct GNUNET_RECLAIM_Ticket ticket;
2042 struct GNUNET_IDENTITY_PublicKey cid;
2043 struct GNUNET_HashCode cache_key;
2044 struct MHD_Response *resp;
2045 char *grant_type;
2046 char *code;
2047 char *json_response;
2048 char *id_token;
2049 char *access_token;
2050 char *jwt_secret;
2051 char *nonce = NULL;
2052 char *code_verifier;
2053
2054 /*
2055 * Check Authorization
2056 */
2057 if (GNUNET_SYSERR == check_authorization (handle, &cid))
2058 {
2059 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2060 "OIDC authorization for token endpoint failed\n");
2061 GNUNET_SCHEDULER_add_now (&do_error, handle);
2062 return;
2063 }
2064
2065 /*
2066 * Check parameter
2067 */
2068
2069 // TODO Do not allow multiple equal parameter names
2070 // REQUIRED grant_type
2071 GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY,
2072 strlen (OIDC_GRANT_TYPE_KEY),
2073 &cache_key);
2074 grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY);
2075 if (NULL == grant_type)
2076 {
2077 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2078 handle->edesc = GNUNET_strdup ("missing parameter grant_type");
2079 handle->response_code = MHD_HTTP_BAD_REQUEST;
2080 GNUNET_SCHEDULER_add_now (&do_error, handle);
2081 return;
2082 }
2083
2084 // Check parameter grant_type == "authorization_code"
2085 if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
2086 {
2087 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE);
2088 handle->response_code = MHD_HTTP_BAD_REQUEST;
2089 GNUNET_free (grant_type);
2090 GNUNET_SCHEDULER_add_now (&do_error, handle);
2091 return;
2092 }
2093 GNUNET_free (grant_type);
2094 // REQUIRED code
2095 code = get_url_parameter_copy (handle, OIDC_CODE_KEY);
2096 if (NULL == code)
2097 {
2098 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2099 handle->edesc = GNUNET_strdup ("missing parameter code");
2100 handle->response_code = MHD_HTTP_BAD_REQUEST;
2101 GNUNET_SCHEDULER_add_now (&do_error, handle);
2102 return;
2103 }
2104 ego_entry = find_ego (handle, &cid);
2105 if (NULL == ego_entry)
2106 {
2107 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2108 handle->edesc = GNUNET_strdup ("Unknown client");
2109 handle->response_code = MHD_HTTP_BAD_REQUEST;
2110 GNUNET_free (code);
2111 GNUNET_SCHEDULER_add_now (&do_error, handle);
2112 return;
2113 }
2114
2115 // REQUIRED code verifier
2116 code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY);
2117 if (NULL == code_verifier)
2118 {
2119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2120 "OAuth authorization request does not contain PKCE parameters!\n");
2121
2122 }
2123
2124 // decode code
2125 if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket,
2126 &cl, &pl, &nonce,
2127 OIDC_VERIFICATION_DEFAULT))
2128 {
2129 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2130 handle->edesc = GNUNET_strdup ("invalid code");
2131 handle->response_code = MHD_HTTP_BAD_REQUEST;
2132 GNUNET_free (code);
2133 if (NULL != code_verifier)
2134 GNUNET_free (code_verifier);
2135 GNUNET_SCHEDULER_add_now (&do_error, handle);
2136 return;
2137 }
2138 if (NULL != code_verifier)
2139 GNUNET_free (code_verifier);
2140
2141 // create jwt
2142 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
2143 "reclaim-rest-plugin",
2144 "expiration_time",
2145 &expiration_time))
2146 {
2147 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
2148 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2149 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2150 GNUNET_free (code);
2151 if (NULL != nonce)
2152 GNUNET_free (nonce);
2153 GNUNET_RECLAIM_attribute_list_destroy (cl);
2154 GNUNET_RECLAIM_presentation_list_destroy (pl);
2155 GNUNET_SCHEDULER_add_now (&do_error, handle);
2156 return;
2157 }
2158
2159
2160 // TODO OPTIONAL acr,amr,azp
2161 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
2162 "reclaim-rest-plugin",
2163 "jwt_secret",
2164 &jwt_secret))
2165 {
2166 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2167 handle->edesc = GNUNET_strdup ("No signing secret configured!");
2168 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2169 GNUNET_free (code);
2170 GNUNET_RECLAIM_attribute_list_destroy (cl);
2171 GNUNET_RECLAIM_presentation_list_destroy (pl);
2172 if (NULL != nonce)
2173 GNUNET_free (nonce);
2174 GNUNET_SCHEDULER_add_now (&do_error, handle);
2175 return;
2176 }
2177 id_token = OIDC_generate_id_token (&ticket.audience,
2178 &ticket.identity,
2179 cl,
2180 pl,
2181 &expiration_time,
2182 (NULL != nonce) ? nonce : NULL,
2183 jwt_secret);
2184 GNUNET_free (jwt_secret);
2185 if (NULL != nonce)
2186 GNUNET_free (nonce);
2187 access_token = OIDC_access_token_new (&ticket);
2188 /* Store mapping from access token to code so we can later
2189 * fall back on the provided attributes in userinfo
2190 */
2191 GNUNET_CRYPTO_hash (access_token,
2192 strlen (access_token),
2193 &cache_key);
2194 char *tmp_at = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache,
2195 &cache_key);
2196 GNUNET_CONTAINER_multihashmap_put (oidc_code_cache,
2197 &cache_key,
2198 code,
2199 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2200 /* If there was a previous code in there, free the old value */
2201 if (NULL != tmp_at)
2202 {
2203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2204 "OIDC access token already issued. Cleanup.\n");
2205 GNUNET_free (tmp_at);
2206 }
2207
2208 OIDC_build_token_response (access_token,
2209 id_token,
2210 &expiration_time,
2211 &json_response);
2212
2213 resp = GNUNET_REST_create_response (json_response);
2214 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2215 "Cache-Control",
2216 "no-store"));
2217 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2218 "Pragma", "no-cache"));
2219 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
2220 "Content-Type",
2221 "application/json"));
2222 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2223 GNUNET_RECLAIM_attribute_list_destroy (cl);
2224 GNUNET_RECLAIM_presentation_list_destroy (pl);
2225 GNUNET_free (access_token);
2226 GNUNET_free (json_response);
2227 GNUNET_free (id_token);
2228 cleanup_handle (handle);
2229}
2230
2231
2232/**
2233 * Collects claims and stores them in handle
2234 */
2235static void
2236consume_ticket (void *cls,
2237 const struct GNUNET_IDENTITY_PublicKey *identity,
2238 const struct GNUNET_RECLAIM_Attribute *attr,
2239 const struct GNUNET_RECLAIM_Presentation *presentation)
2240{
2241 struct RequestHandle *handle = cls;
2242 struct GNUNET_RECLAIM_AttributeListEntry *ale;
2243 struct GNUNET_RECLAIM_PresentationListEntry *atle;
2244 struct MHD_Response *resp;
2245 char *result_str;
2246
2247 if (NULL != handle->consume_timeout_op)
2248 GNUNET_SCHEDULER_cancel (handle->consume_timeout_op);
2249 handle->consume_timeout_op = NULL;
2250 handle->idp_op = NULL;
2251
2252 if (NULL == identity)
2253 {
2254 result_str = OIDC_generate_userinfo (&handle->ticket.identity,
2255 handle->attr_userinfo_list,
2256 handle->presentations);
2257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
2258 resp = GNUNET_REST_create_response (result_str);
2259 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2260 GNUNET_free (result_str);
2261 cleanup_handle (handle);
2262 return;
2263 }
2264 ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
2265 ale->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
2266 &attr->credential,
2267 attr->type,
2268 attr->data,
2269 attr->data_size);
2270 ale->attribute->id = attr->id;
2271 ale->attribute->flag = attr->flag;
2272 ale->attribute->credential = attr->credential;
2273 GNUNET_CONTAINER_DLL_insert (handle->attr_userinfo_list->list_head,
2274 handle->attr_userinfo_list->list_tail,
2275 ale);
2276 if (NULL == presentation)
2277 return;
2278 for (atle = handle->presentations->list_head;
2279 NULL != atle; atle = atle->next)
2280 {
2281 if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (
2282 &atle->presentation->credential_id,
2283 &presentation->credential_id))
2284 continue;
2285 break; /** already in list **/
2286 }
2287 if (NULL == atle)
2288 {
2289 /** Credential matches for attribute, add **/
2290 atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
2291 atle->presentation = GNUNET_RECLAIM_presentation_new (presentation->type,
2292 presentation->data,
2293 presentation->
2294 data_size);
2295 atle->presentation->credential_id = presentation->credential_id;
2296 GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head,
2297 handle->presentations->list_tail,
2298 atle);
2299 }
2300}
2301
2302
2303static void
2304consume_timeout (void*cls)
2305{
2306 struct RequestHandle *handle = cls;
2307 struct GNUNET_HashCode cache_key;
2308 struct GNUNET_RECLAIM_AttributeList *cl = NULL;
2309 struct GNUNET_RECLAIM_PresentationList *pl = NULL;
2310 struct GNUNET_RECLAIM_Ticket ticket;
2311 char *nonce;
2312 char *cached_code;
2313
2314 handle->consume_timeout_op = NULL;
2315 if (NULL != handle->idp_op)
2316 GNUNET_RECLAIM_cancel (handle->idp_op);
2317 handle->idp_op = NULL;
2318
2319 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2320 "Ticket consumptioned timed out. Using cache...\n");
2321 GNUNET_CRYPTO_hash (handle->access_token,
2322 strlen (handle->access_token),
2323 &cache_key);
2324 cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache,
2325 &cache_key);
2326 if (NULL == cached_code)
2327 {
2328 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2329 handle->edesc = GNUNET_strdup ("No Access Token in cache!");
2330 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2331 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2332 return;
2333 }
2334
2335 // decode code
2336 if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience,
2337 cached_code, NULL, &ticket,
2338 &cl, &pl, &nonce,
2339 OIDC_VERIFICATION_NO_CODE_VERIFIER))
2340 {
2341 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
2342 handle->edesc = GNUNET_strdup ("invalid code");
2343 handle->response_code = MHD_HTTP_BAD_REQUEST;
2344 GNUNET_free (cached_code);
2345 if (NULL != nonce)
2346 GNUNET_free (nonce);
2347 GNUNET_SCHEDULER_add_now (&do_error, handle);
2348 return;
2349 }
2350
2351 struct MHD_Response *resp;
2352 char *result_str;
2353
2354 result_str = OIDC_generate_userinfo (&handle->ticket.identity,
2355 cl,
2356 pl);
2357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str);
2358 resp = GNUNET_REST_create_response (result_str);
2359 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2360 GNUNET_free (result_str);
2361 GNUNET_free (nonce);
2362 GNUNET_RECLAIM_attribute_list_destroy (cl);
2363 GNUNET_RECLAIM_presentation_list_destroy (pl);
2364 cleanup_handle (handle);
2365}
2366
2367
2368/**
2369 * Responds to userinfo GET and url-encoded POST request
2370 *
2371 * @param con_handle the connection handle
2372 * @param url the url
2373 * @param cls the RequestHandle
2374 */
2375static void
2376userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2377 const char *url,
2378 void *cls)
2379{
2380 // TODO expiration time
2381 struct RequestHandle *handle = cls;
2382 struct GNUNET_RECLAIM_Ticket *ticket;
2383 char delimiter[] = " ";
2384 struct GNUNET_HashCode cache_key;
2385 char *authorization;
2386 char *authorization_type;
2387 char *authorization_access_token;
2388 const struct EgoEntry *aud_ego;
2389 const struct GNUNET_IDENTITY_PrivateKey *privkey;
2390
2391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting userinfo\n");
2392 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
2393 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
2394 &cache_key);
2395 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
2396 ->header_param_map,
2397 &cache_key))
2398 {
2399 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2400 handle->edesc = GNUNET_strdup ("No Access Token");
2401 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2402 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2403 return;
2404 }
2405 authorization =
2406 GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
2407 &cache_key);
2408
2409 // split header in "Bearer" and access_token
2410 authorization = GNUNET_strdup (authorization);
2411 authorization_type = strtok (authorization, delimiter);
2412 if ((NULL == authorization_type) ||
2413 (0 != strcmp ("Bearer", authorization_type)))
2414 {
2415 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2416 handle->edesc = GNUNET_strdup ("No Access Token");
2417 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2418 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2419 GNUNET_free (authorization);
2420 return;
2421 }
2422 authorization_access_token = strtok (NULL, delimiter);
2423 if (NULL == authorization_access_token)
2424 {
2425 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2426 handle->edesc = GNUNET_strdup ("Access token missing");
2427 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2428 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2429 GNUNET_free (authorization);
2430 return;
2431 }
2432
2433 if (GNUNET_OK != OIDC_access_token_parse (authorization_access_token,
2434 &ticket))
2435 {
2436 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2437 handle->edesc = GNUNET_strdup ("The access token is invalid");
2438 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2439 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2440 GNUNET_free (authorization);
2441 return;
2442
2443 }
2444 GNUNET_assert (NULL != ticket);
2445 handle->ticket = *ticket;
2446 GNUNET_free (ticket);
2447 aud_ego = find_ego (handle, &handle->ticket.audience);
2448 if (NULL == aud_ego)
2449 {
2450 handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
2451 handle->edesc = GNUNET_strdup ("The access token expired");
2452 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2453 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2454 GNUNET_free (authorization);
2455 return;
2456 }
2457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Consuming ticket\n");
2458 privkey = GNUNET_IDENTITY_ego_get_private_key (aud_ego->ego);
2459 handle->attr_userinfo_list =
2460 GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
2461 handle->presentations =
2462 GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
2463
2464 /* If the consume takes too long, we use values from the cache */
2465 handle->access_token = GNUNET_strdup (authorization_access_token);
2466 handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (CONSUME_TIMEOUT,
2467 &consume_timeout,
2468 handle);
2469 handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp,
2470 privkey,
2471 &handle->ticket,
2472 &consume_ticket,
2473 handle);
2474 GNUNET_free (authorization);
2475}
2476
2477
2478/**
2479 * If listing is enabled, prints information about the egos.
2480 *
2481 * This function is initially called for all egos and then again
2482 * whenever a ego's identifier changes or if it is deleted. At the
2483 * end of the initial pass over all egos, the function is once called
2484 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2485 * be invoked in the future or that there was an error.
2486 *
2487 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
2488 * function is only called ONCE, and 'NULL' being passed in 'ego' does
2489 * indicate an error (for example because name is taken or no default value is
2490 * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
2491 * value WILL be passed to a subsequent call to the identity callback of
2492 * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
2493 *
2494 * When an identity is renamed, this function is called with the
2495 * (known) ego but the NEW identifier.
2496 *
2497 * When an identity is deleted, this function is called with the
2498 * (known) ego and "NULL" for the 'identifier'. In this case,
2499 * the 'ego' is henceforth invalid (and the 'ctx' should also be
2500 * cleaned up).
2501 *
2502 * @param cls closure
2503 * @param ego ego handle
2504 * @param ctx context for application to store data for this ego
2505 * (during the lifetime of this process, initially NULL)
2506 * @param identifier identifier assigned by the user for this ego,
2507 * NULL if the user just deleted the ego and it
2508 * must thus no longer be used
2509 */
2510static void
2511list_ego (void *cls,
2512 struct GNUNET_IDENTITY_Ego *ego,
2513 void **ctx,
2514 const char *identifier)
2515{
2516 struct EgoEntry *ego_entry;
2517 struct GNUNET_IDENTITY_PublicKey pk;
2518
2519 if (NULL == ego)
2520 {
2521 state = ID_REST_STATE_POST_INIT;
2522 return;
2523 }
2524 if (ID_REST_STATE_INIT == state)
2525
2526 {
2527 ego_entry = GNUNET_new (struct EgoEntry);
2528 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2529 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
2530 ego_entry->ego = ego;
2531 ego_entry->identifier = GNUNET_strdup (identifier);
2532 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
2533 ego_tail,
2534 ego_entry);
2535 return;
2536 }
2537 /* Ego renamed or added */
2538 if (identifier != NULL)
2539 {
2540 for (ego_entry = ego_head; NULL != ego_entry;
2541 ego_entry = ego_entry->next)
2542 {
2543 if (ego_entry->ego == ego)
2544 {
2545 /* Rename */
2546 GNUNET_free (ego_entry->identifier);
2547 ego_entry->identifier = GNUNET_strdup (identifier);
2548 break;
2549 }
2550 }
2551 if (NULL == ego_entry)
2552 {
2553 /* Add */
2554 ego_entry = GNUNET_new (struct EgoEntry);
2555 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2556 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
2557 ego_entry->ego = ego;
2558 ego_entry->identifier = GNUNET_strdup (identifier);
2559 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
2560 ego_tail,
2561 ego_entry);
2562 }
2563 }
2564 else
2565 {
2566 /* Delete */
2567 for (ego_entry = ego_head; NULL != ego_entry;
2568 ego_entry = ego_entry->next)
2569 {
2570 if (ego_entry->ego == ego)
2571 break;
2572 }
2573 if (NULL == ego_entry)
2574 return; /* Not found */
2575
2576 GNUNET_CONTAINER_DLL_remove (ego_head,
2577 ego_tail,
2578 ego_entry);
2579 GNUNET_free (ego_entry->identifier);
2580 GNUNET_free (ego_entry->keystring);
2581 GNUNET_free (ego_entry);
2582 return;
2583 }
2584}
2585
2586
2587static void
2588oidc_config_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2589 const char *url,
2590 void *cls)
2591{
2592 json_t *oidc_config;
2593 json_t *auth_methods;
2594 json_t *sig_algs;
2595 json_t *scopes;
2596 json_t *response_types;
2597 json_t *sub_types;
2598 json_t *claim_types;
2599 char *oidc_config_str;
2600 struct MHD_Response *resp;
2601 struct RequestHandle *handle = cls;
2602
2603 oidc_config = json_object ();
2604 // FIXME get from config?
2605 json_object_set_new (oidc_config,
2606 "issuer", json_string ("http://localhost:7776"));
2607 json_object_set_new (oidc_config,
2608 "authorization_endpoint",
2609 json_string ("https://api.reclaim/openid/authorize"));
2610 json_object_set_new (oidc_config,
2611 "token_endpoint",
2612 json_string ("http://localhost:7776/openid/token"));
2613 auth_methods = json_array ();
2614 json_array_append_new (auth_methods,
2615 json_string ("client_secret_basic"));
2616 json_array_append_new (auth_methods,
2617 json_string ("client_secret_post"));
2618 json_object_set_new (oidc_config,
2619 "token_endpoint_auth_methods_supported",
2620 auth_methods);
2621 sig_algs = json_array ();
2622 json_array_append_new (sig_algs,
2623 json_string ("HS512"));
2624 json_object_set_new (oidc_config,
2625 "id_token_signing_alg_values_supported",
2626 sig_algs);
2627 json_object_set_new (oidc_config,
2628 "userinfo_endpoint",
2629 json_string ("http://localhost:7776/openid/userinfo"));
2630 scopes = json_array ();
2631 json_array_append_new (scopes,
2632 json_string ("openid"));
2633 json_array_append_new (scopes,
2634 json_string ("profile"));
2635 json_array_append_new (scopes,
2636 json_string ("email"));
2637 json_array_append_new (scopes,
2638 json_string ("address"));
2639 json_array_append_new (scopes,
2640 json_string ("phone"));
2641 json_object_set_new (oidc_config,
2642 "scopes_supported",
2643 scopes);
2644 response_types = json_array ();
2645 json_array_append_new (response_types,
2646 json_string ("code"));
2647 json_object_set_new (oidc_config,
2648 "response_types_supported",
2649 response_types);
2650 sub_types = json_array ();
2651 json_array_append_new (sub_types,
2652 json_string ("public")); /* no pairwise support */
2653 json_object_set_new (oidc_config,
2654 "subject_types_supported",
2655 sub_types);
2656 claim_types = json_array ();
2657 json_array_append_new (claim_types,
2658 json_string ("normal"));
2659 json_array_append_new (claim_types,
2660 json_string ("aggregated"));
2661 json_object_set_new (oidc_config,
2662 "claim_types_supported",
2663 claim_types);
2664 json_object_set_new (oidc_config,
2665 "claims_parameter_supported",
2666 json_boolean (1));
2667 oidc_config_str = json_dumps (oidc_config, JSON_INDENT (1));
2668 resp = GNUNET_REST_create_response (oidc_config_str);
2669 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2670 json_decref (oidc_config);
2671 GNUNET_free (oidc_config_str);
2672 cleanup_handle (handle);
2673}
2674
2675
2676/**
2677 * Respond to OPTIONS request
2678 *
2679 * @param con_handle the connection handle
2680 * @param url the url
2681 * @param cls the RequestHandle
2682 */
2683static void
2684oidc_config_cors (struct GNUNET_REST_RequestHandle *con_handle,
2685 const char *url,
2686 void *cls)
2687{
2688 struct MHD_Response *resp;
2689 struct RequestHandle *handle = cls;
2690
2691 // For now, independent of path return all options
2692 resp = GNUNET_REST_create_response (NULL);
2693 GNUNET_assert (MHD_NO !=
2694 MHD_add_response_header (resp,
2695 "Access-Control-Allow-Methods",
2696 allow_methods));
2697 GNUNET_assert (MHD_NO !=
2698 MHD_add_response_header (resp,
2699 "Access-Control-Allow-Origin",
2700 "*"));
2701 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2702 cleanup_handle (handle);
2703 return;
2704}
2705
2706
2707static enum GNUNET_GenericReturnValue
2708rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
2709 GNUNET_REST_ResultProcessor proc,
2710 void *proc_cls)
2711{
2712 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2713 struct GNUNET_REST_RequestHandlerError err;
2714 static const struct GNUNET_REST_RequestHandler handlers[] =
2715 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint },
2716 { MHD_HTTP_METHOD_POST,
2717 GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint }, // url-encoded
2718 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont },
2719 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2720 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2721 { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2722 { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_OIDC_CONFIG,
2723 &oidc_config_endpoint },
2724 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC_CONFIG,
2725 &oidc_config_cors },
2726 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont },
2727 GNUNET_REST_HANDLER_END };
2728
2729 handle->oidc = GNUNET_new (struct OIDC_Variables);
2730 if (NULL == OIDC_cookie_jar_map)
2731 OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10,
2732 GNUNET_NO);
2733 if (NULL == oidc_code_cache)
2734 oidc_code_cache = GNUNET_CONTAINER_multihashmap_create (10,
2735 GNUNET_NO);
2736
2737 handle->response_code = 0;
2738 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2739 handle->proc_cls = proc_cls;
2740 handle->proc = proc;
2741 handle->rest_handle = rest_handle;
2742 handle->url = GNUNET_strdup (rest_handle->url);
2743 handle->timeout_task =
2744 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
2745 GNUNET_CONTAINER_DLL_insert (requests_head,
2746 requests_tail,
2747 handle);
2748 if (handle->url[strlen (handle->url) - 1] == '/')
2749 handle->url[strlen (handle->url) - 1] = '\0';
2750 if (GNUNET_NO ==
2751 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
2752 return GNUNET_NO;
2753
2754 return GNUNET_YES;
2755}
2756
2757
2758/**
2759 * Entry point for the plugin.
2760 *
2761 * @param cls Config info
2762 * @return NULL on error, otherwise the plugin context
2763 */
2764void *
2765libgnunet_plugin_rest_openid_connect_init (void *cls)
2766{
2767 static struct Plugin plugin;
2768 struct GNUNET_REST_Plugin *api;
2769
2770 cfg = cls;
2771 if (NULL != plugin.cfg)
2772 return NULL; /* can only initialize once! */
2773 memset (&plugin, 0, sizeof(struct Plugin));
2774 plugin.cfg = cfg;
2775 api = GNUNET_new (struct GNUNET_REST_Plugin);
2776 api->cls = &plugin;
2777 api->name = GNUNET_REST_API_NS_OIDC;
2778 api->process_request = &rest_identity_process_request;
2779 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
2780 gns_handle = GNUNET_GNS_connect (cfg);
2781 idp = GNUNET_RECLAIM_connect (cfg);
2782
2783 state = ID_REST_STATE_INIT;
2784 GNUNET_asprintf (&allow_methods,
2785 "%s, %s, %s, %s, %s",
2786 MHD_HTTP_METHOD_GET,
2787 MHD_HTTP_METHOD_POST,
2788 MHD_HTTP_METHOD_PUT,
2789 MHD_HTTP_METHOD_DELETE,
2790 MHD_HTTP_METHOD_OPTIONS);
2791
2792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2793 _ ("OpenID Connect REST API initialized\n"));
2794 return api;
2795}
2796
2797
2798static int
2799cleanup_hashmap (void *cls, const struct GNUNET_HashCode *key, void *value)
2800{
2801 GNUNET_free (value);
2802 return GNUNET_YES;
2803}
2804
2805
2806/**
2807 * Exit point from the plugin.
2808 *
2809 * @param cls the plugin context (as returned by "init")
2810 * @return always NULL
2811 */
2812void *
2813libgnunet_plugin_rest_openid_connect_done (void *cls)
2814{
2815 struct GNUNET_REST_Plugin *api = cls;
2816 struct Plugin *plugin = api->cls;
2817 struct EgoEntry *ego_entry;
2818
2819 plugin->cfg = NULL;
2820 while (NULL != requests_head)
2821 cleanup_handle (requests_head);
2822 if (NULL != OIDC_cookie_jar_map)
2823 {
2824 GNUNET_CONTAINER_multihashmap_iterate (OIDC_cookie_jar_map,
2825 &cleanup_hashmap,
2826 NULL);
2827 GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
2828 }
2829 if (NULL != oidc_code_cache)
2830 {
2831 GNUNET_CONTAINER_multihashmap_iterate (oidc_code_cache,
2832 &cleanup_hashmap,
2833 NULL);
2834 GNUNET_CONTAINER_multihashmap_destroy (oidc_code_cache);
2835 }
2836
2837 GNUNET_free (allow_methods);
2838 if (NULL != gns_handle)
2839 GNUNET_GNS_disconnect (gns_handle);
2840 if (NULL != identity_handle)
2841 GNUNET_IDENTITY_disconnect (identity_handle);
2842 if (NULL != idp)
2843 GNUNET_RECLAIM_disconnect (idp);
2844 while (NULL != (ego_entry = ego_head))
2845 {
2846 GNUNET_CONTAINER_DLL_remove (ego_head,
2847 ego_tail,
2848 ego_entry);
2849 GNUNET_free (ego_entry->identifier);
2850 GNUNET_free (ego_entry->keystring);
2851 GNUNET_free (ego_entry);
2852 }
2853 GNUNET_free (api);
2854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2855 "OpenID Connect REST plugin is finished\n");
2856 return NULL;
2857}
2858
2859
2860/* end of plugin_rest_openid_connect.c */
diff --git a/src/reclaim/plugin_rest_pabc.c b/src/reclaim/plugin_rest_pabc.c
deleted file mode 100644
index 4b7d21df3..000000000
--- a/src/reclaim/plugin_rest_pabc.c
+++ /dev/null
@@ -1,667 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @file reclaim/plugin_rest_pabc.c
23 * @brief GNUnet pabc REST plugin
24 *
25 */
26#include "platform.h"
27#include "microhttpd.h"
28#include <inttypes.h>
29#include <jansson.h>
30#include <pabc/pabc.h>
31#include "gnunet_reclaim_lib.h"
32#include "gnunet_reclaim_service.h"
33#include "gnunet_rest_lib.h"
34#include "gnunet_rest_plugin.h"
35#include "gnunet_signatures.h"
36#include "pabc_helper.h"
37
38/**
39 * REST root namespace
40 */
41#define GNUNET_REST_API_NS_PABC "/pabc"
42
43/**
44 * Credential request endpoint
45 */
46#define GNUNET_REST_API_NS_PABC_CR "/pabc/cr"
47
48/**
49 * The configuration handle
50 */
51const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53/**
54 * HTTP methods allows for this plugin
55 */
56static char *allow_methods;
57
58/**
59 * @brief struct returned by the initialization function of the plugin
60 */
61struct Plugin
62{
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64};
65
66
67struct RequestHandle
68{
69 /**
70 * DLL
71 */
72 struct RequestHandle *next;
73
74 /**
75 * DLL
76 */
77 struct RequestHandle *prev;
78
79 /**
80 * Rest connection
81 */
82 struct GNUNET_REST_RequestHandle *rest_handle;
83
84 /**
85 * Desired timeout for the lookup (default is no timeout).
86 */
87 struct GNUNET_TIME_Relative timeout;
88
89 /**
90 * ID of a task associated with the resolution process.
91 */
92 struct GNUNET_SCHEDULER_Task *timeout_task;
93
94 /**
95 * The plugin result processor
96 */
97 GNUNET_REST_ResultProcessor proc;
98
99 /**
100 * The closure of the result processor
101 */
102 void *proc_cls;
103
104 /**
105 * The url
106 */
107 char *url;
108
109 /**
110 * Error response message
111 */
112 char *emsg;
113
114 /**
115 * Response code
116 */
117 int response_code;
118
119 /**
120 * Response object
121 */
122 json_t *resp_object;
123};
124
125/**
126 * DLL
127 */
128static struct RequestHandle *requests_head;
129
130/**
131 * DLL
132 */
133static struct RequestHandle *requests_tail;
134
135
136/**
137 * Cleanup lookup handle
138 * @param handle Handle to clean up
139 */
140static void
141cleanup_handle (void *cls)
142{
143 struct RequestHandle *handle = cls;
144
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
146 if (NULL != handle->resp_object)
147 json_decref (handle->resp_object);
148 if (NULL != handle->timeout_task)
149 GNUNET_SCHEDULER_cancel (handle->timeout_task);
150 if (NULL != handle->url)
151 GNUNET_free (handle->url);
152 if (NULL != handle->emsg)
153 GNUNET_free (handle->emsg);
154 GNUNET_CONTAINER_DLL_remove (requests_head,
155 requests_tail,
156 handle);
157 GNUNET_free (handle);
158}
159
160
161/**
162 * Task run on error, sends error message. Cleans up everything.
163 *
164 * @param cls the `struct RequestHandle`
165 */
166static void
167do_error (void *cls)
168{
169 struct RequestHandle *handle = cls;
170 struct MHD_Response *resp;
171 char *json_error;
172
173 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
174 if (0 == handle->response_code)
175 {
176 handle->response_code = MHD_HTTP_BAD_REQUEST;
177 }
178 resp = GNUNET_REST_create_response (json_error);
179 MHD_add_response_header (resp, "Content-Type", "application/json");
180 handle->proc (handle->proc_cls, resp, handle->response_code);
181 cleanup_handle (handle);
182 GNUNET_free (json_error);
183}
184
185
186/**
187 * Task run on timeout, sends error message. Cleans up everything.
188 *
189 * @param cls the `struct RequestHandle`
190 */
191static void
192do_timeout (void *cls)
193{
194 struct RequestHandle *handle = cls;
195
196 handle->timeout_task = NULL;
197 do_error (handle);
198}
199
200
201static void
202return_response (void *cls)
203{
204 char *result_str;
205 struct RequestHandle *handle = cls;
206 struct MHD_Response *resp;
207
208 result_str = json_dumps (handle->resp_object, 0);
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
210 resp = GNUNET_REST_create_response (result_str);
211 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
212 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
213 GNUNET_free (result_str);
214 cleanup_handle (handle);
215}
216
217
218static enum pabc_status
219set_attributes_from_idtoken (const struct pabc_context *ctx,
220 const struct pabc_public_parameters *pp,
221 struct pabc_user_context *usr_ctx,
222 const char *id_token)
223{
224 json_t *payload_json;
225 json_t *value;
226 json_error_t json_err;
227 const char *key;
228 const char *jwt_body;
229 char *decoded_jwt;
230 char delim[] = ".";
231 char *jwt_string;
232 const char *pabc_key;
233 enum pabc_status status;
234
235 // FIXME parse JWT
236 jwt_string = GNUNET_strndup (id_token, strlen (id_token));
237 jwt_body = strtok (jwt_string, delim);
238 jwt_body = strtok (NULL, delim);
239 GNUNET_STRINGS_base64url_decode (jwt_body, strlen (jwt_body),
240 (void **) &decoded_jwt);
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decoded ID Token: %s\n", decoded_jwt);
242 payload_json = json_loads (decoded_jwt, JSON_DECODE_ANY, &json_err);
243 GNUNET_free (decoded_jwt);
244
245 json_object_foreach (payload_json, key, value)
246 {
247 pabc_key = key;
248 if (0 == strcmp ("iss", key))
249 pabc_key = "issuer"; // rename
250 if (0 == strcmp ("sub", key))
251 pabc_key = "subject"; // rename
252 if (0 == strcmp ("jti", key))
253 continue;
254 if (0 == strcmp ("exp", key))
255 pabc_key = "expiration"; // rename
256 if (0 == strcmp ("iat", key))
257 continue;
258 if (0 == strcmp ("nbf", key))
259 continue;
260 if (0 == strcmp ("aud", key))
261 continue;
262 char *tmp_val;
263 if (json_is_string (value))
264 tmp_val = GNUNET_strdup (json_string_value (value));
265 else
266 tmp_val = json_dumps (value, JSON_ENCODE_ANY);
267 if (NULL == tmp_val)
268 {
269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270 "Unable to encode JSON value for `%s'\n", key);
271 continue;
272 }
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 "Setting `%s' to `%s'\n", key, tmp_val);
275 status = pabc_set_attribute_value_by_name (ctx, pp, usr_ctx,
276 pabc_key,
277 tmp_val);
278 GNUNET_free (tmp_val);
279 if (PABC_OK != status)
280 {
281 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
282 "Failed to set attribute `%s'.\n", key);
283 }
284 }
285 GNUNET_free (jwt_string);
286 return PABC_OK;
287}
288
289
290static enum GNUNET_GenericReturnValue
291setup_new_user_context (struct pabc_context *ctx,
292 struct pabc_public_parameters *pp,
293 struct pabc_user_context **usr_ctx)
294{
295 if (PABC_OK != pabc_new_user_context (ctx, pp, usr_ctx))
296 return GNUNET_SYSERR;
297
298 if (PABC_OK != pabc_populate_user_context (ctx, *usr_ctx))
299 {
300 pabc_free_user_context (ctx, pp, usr_ctx);
301 return GNUNET_SYSERR;
302 }
303 return GNUNET_OK;
304}
305
306
307static void
308cr_cont (struct GNUNET_REST_RequestHandle *con_handle,
309 const char *url,
310 void *cls)
311{
312 struct RequestHandle *handle = cls;
313 char term_data[handle->rest_handle->data_size + 1];
314 char *response_str;
315 json_t *data_json;
316 json_t *nonce_json;
317 json_t *pp_json;
318 json_t *idtoken_json;
319 json_t *iss_json;
320 json_t *identity_json;
321 json_error_t err;
322 struct pabc_public_parameters *pp = NULL;
323 struct pabc_context *ctx = NULL;
324 struct pabc_user_context *usr_ctx = NULL;
325 struct pabc_credential_request *cr = NULL;
326 struct pabc_nonce *nonce = NULL;
327 enum pabc_status status;
328
329
330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
331 "Credential request...\n");
332
333 if (0 >= handle->rest_handle->data_size)
334 {
335 GNUNET_SCHEDULER_add_now (&do_error, handle);
336 return;
337 }
338
339 term_data[handle->rest_handle->data_size] = '\0';
340 GNUNET_memcpy (term_data,
341 handle->rest_handle->data,
342 handle->rest_handle->data_size);
343 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
344 if (NULL == data_json)
345 {
346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
347 "Unable to parse %s\n", term_data);
348 GNUNET_SCHEDULER_add_now (&do_error, handle);
349 return;
350 }
351 if (! json_is_object (data_json))
352 {
353 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
354 "Unable to parse %s\n", term_data);
355 json_decref (data_json);
356 GNUNET_SCHEDULER_add_now (&do_error, handle);
357 return;
358 }
359
360 nonce_json = json_object_get (data_json, "nonce");
361 if (NULL == nonce_json)
362 {
363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364 "Unable to parse nonce\n");
365 json_decref (data_json);
366 GNUNET_SCHEDULER_add_now (&do_error, handle);
367 return;
368 }
369 iss_json = json_object_get (data_json, "issuer");
370 if (NULL == iss_json)
371 {
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373 "Unable to parse issuer\n");
374 json_decref (data_json);
375 GNUNET_SCHEDULER_add_now (&do_error, handle);
376 return;
377 }
378 identity_json = json_object_get (data_json, "identity");
379 if (NULL == identity_json)
380 {
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 "Unable to parse identity\n");
383 json_decref (data_json);
384 GNUNET_SCHEDULER_add_now (&do_error, handle);
385 return;
386 }
387 idtoken_json = json_object_get (data_json, "id_token");
388 if (NULL == idtoken_json)
389 {
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
391 "Unable to parse id_token\n");
392 json_decref (data_json);
393 GNUNET_SCHEDULER_add_now (&do_error, handle);
394 return;
395 }
396 pp_json = json_object_get (data_json, "public_params");
397 if (NULL == pp_json)
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
400 "Unable to parse public parameters\n");
401 json_decref (data_json);
402 GNUNET_SCHEDULER_add_now (&do_error, handle);
403 return;
404 }
405
406 PABC_ASSERT (pabc_new_ctx (&ctx));
407 char *pp_str = json_dumps (pp_json, JSON_ENCODE_ANY);
408 status = pabc_decode_and_new_public_parameters (ctx,
409 &pp,
410 pp_str);
411 char *ppid;
412 GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_pp (pp_str, &ppid));
413 GNUNET_free (pp_str);
414 if (status != PABC_OK)
415 {
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "Failed to read public parameters: %s\n",
418 pp_str);
419 json_decref (data_json);
420 GNUNET_SCHEDULER_add_now (&do_error, handle);
421 return;
422 }
423 // (Over)write parameters
424 status = PABC_write_public_parameters (json_string_value (iss_json),
425 pp);
426 if (status != PABC_OK)
427 {
428 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
429 "Failed to write public parameters.\n");
430 json_decref (data_json);
431 GNUNET_SCHEDULER_add_now (&do_error, handle);
432 return;
433 }
434 status = PABC_read_usr_ctx (json_string_value (identity_json),
435 json_string_value (iss_json),
436 ctx, pp, &usr_ctx);
437 if (PABC_OK != status)
438 {
439 if (GNUNET_OK != setup_new_user_context (ctx, pp, &usr_ctx))
440 {
441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup user context.\n");
442 pabc_free_public_parameters (ctx, &pp);
443 json_decref (data_json);
444 GNUNET_SCHEDULER_add_now (&do_error, handle);
445 return;
446 }
447 PABC_write_usr_ctx (json_string_value (identity_json),
448 json_string_value (iss_json),
449 ctx, pp, usr_ctx);
450 }
451
452 // Set attributes from JWT to context
453 status = set_attributes_from_idtoken (ctx,
454 pp,
455 usr_ctx,
456 json_string_value (idtoken_json));
457 if (status != PABC_OK)
458 {
459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to set attributes.\n");
460 pabc_free_user_context (ctx, pp, &usr_ctx);
461 pabc_free_public_parameters (ctx, &pp);
462 json_decref (data_json);
463 GNUNET_SCHEDULER_add_now (&do_error, handle);
464 return;
465 }
466
467
468 // nonce
469 status = pabc_new_nonce (ctx, &nonce);
470 if (status != PABC_OK)
471 {
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate nonce.\n");
473 pabc_free_user_context (ctx, pp, &usr_ctx);
474 pabc_free_public_parameters (ctx, &pp);
475 json_decref (data_json);
476 GNUNET_SCHEDULER_add_now (&do_error, handle);
477 return;
478 }
479 char *nonce_str = json_dumps (nonce_json, JSON_ENCODE_ANY);
480 status = pabc_decode_nonce (ctx, nonce, nonce_str);
481 if (status != PABC_OK)
482 {
483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode nonce.\n");
484 pabc_free_nonce (ctx, &nonce);
485 pabc_free_user_context (ctx, pp, &usr_ctx);
486 pabc_free_public_parameters (ctx, &pp);
487 json_decref (data_json);
488 GNUNET_SCHEDULER_add_now (&do_error, handle);
489 return;
490 }
491
492 // cr
493 status = pabc_new_credential_request (ctx, pp, &cr);
494 if (PABC_OK != status)
495 {
496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to allocate cr.\n");
497 pabc_free_nonce (ctx, &nonce);
498 pabc_free_user_context (ctx, pp, &usr_ctx);
499 pabc_free_public_parameters (ctx, &pp);
500 json_decref (data_json);
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
502 return;
503 }
504
505 status = pabc_gen_credential_request (ctx, pp, usr_ctx, nonce, cr);
506 if (PABC_OK != status)
507 {
508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to generate cr.\n");
509 pabc_free_nonce (ctx, &nonce);
510 pabc_free_credential_request (ctx, pp, &cr);
511 pabc_free_user_context (ctx, pp, &usr_ctx);
512 pabc_free_public_parameters (ctx, &pp);
513 json_decref (data_json);
514 GNUNET_SCHEDULER_add_now (&do_error, handle);
515 return;
516 }
517 handle->resp_object = json_object ();
518 GNUNET_assert (PABC_OK == pabc_cred_encode_cr (ctx, pp, cr,
519 json_string_value (
520 identity_json),
521 ppid, &response_str));
522 if (PABC_OK != status)
523 {
524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize cr.\n");
525 pabc_free_nonce (ctx, &nonce);
526 pabc_free_credential_request (ctx, pp, &cr);
527 pabc_free_user_context (ctx, pp, &usr_ctx);
528 pabc_free_public_parameters (ctx, &pp);
529 json_decref (data_json);
530 GNUNET_SCHEDULER_add_now (&do_error, handle);
531 return;
532 }
533 json_decref (handle->resp_object);
534 handle->resp_object = json_loads (response_str, JSON_DECODE_ANY, &err);
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", response_str);
536 GNUNET_free (response_str);
537
538 // clean up
539 pabc_free_nonce (ctx, &nonce);
540 pabc_free_credential_request (ctx, pp, &cr);
541 pabc_free_user_context (ctx, pp, &usr_ctx);
542 pabc_free_public_parameters (ctx, &pp);
543 GNUNET_SCHEDULER_add_now (&return_response, handle);
544 json_decref (data_json);
545}
546
547
548/**
549 * Respond to OPTIONS request
550 *
551 * @param con_handle the connection handle
552 * @param url the url
553 * @param cls the RequestHandle
554 */
555static void
556options_cont (struct GNUNET_REST_RequestHandle *con_handle,
557 const char *url,
558 void *cls)
559{
560 struct MHD_Response *resp;
561 struct RequestHandle *handle = cls;
562
563 // For now, independent of path return all options
564 resp = GNUNET_REST_create_response (NULL);
565 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
566 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
567 cleanup_handle (handle);
568 return;
569}
570
571
572static enum GNUNET_GenericReturnValue
573rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
574 GNUNET_REST_ResultProcessor proc,
575 void *proc_cls)
576{
577 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
578 struct GNUNET_REST_RequestHandlerError err;
579 static const struct GNUNET_REST_RequestHandler handlers[] = {
580 {MHD_HTTP_METHOD_POST,
581 GNUNET_REST_API_NS_PABC_CR, &cr_cont },
582 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_PABC, &options_cont },
583 GNUNET_REST_HANDLER_END
584 };
585
586 handle->response_code = 0;
587 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
588 handle->proc_cls = proc_cls;
589 handle->proc = proc;
590 handle->rest_handle = rest_handle;
591
592 handle->url = GNUNET_strdup (rest_handle->url);
593 if (handle->url[strlen (handle->url) - 1] == '/')
594 handle->url[strlen (handle->url) - 1] = '\0';
595 handle->timeout_task =
596 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
597 GNUNET_CONTAINER_DLL_insert (requests_head,
598 requests_tail,
599 handle);
600 if (GNUNET_NO ==
601 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
602 {
603 cleanup_handle (handle);
604 return GNUNET_NO;
605 }
606
607 return GNUNET_YES;
608}
609
610
611/**
612 * Entry point for the plugin.
613 *
614 * @param cls Config info
615 * @return NULL on error, otherwise the plugin context
616 */
617void *
618libgnunet_plugin_rest_pabc_init (void *cls)
619{
620 static struct Plugin plugin;
621 struct GNUNET_REST_Plugin *api;
622
623 cfg = cls;
624 if (NULL != plugin.cfg)
625 return NULL; /* can only initialize once! */
626 memset (&plugin, 0, sizeof(struct Plugin));
627 plugin.cfg = cfg;
628 api = GNUNET_new (struct GNUNET_REST_Plugin);
629 api->cls = &plugin;
630 api->name = GNUNET_REST_API_NS_PABC;
631 api->process_request = &rest_identity_process_request;
632 GNUNET_asprintf (&allow_methods,
633 "%s, %s",
634 MHD_HTTP_METHOD_POST,
635 MHD_HTTP_METHOD_OPTIONS);
636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
637 _ ("Identity Provider REST API initialized\n"));
638 return api;
639}
640
641
642/**
643 * Exit point from the plugin.
644 *
645 * @param cls the plugin context (as returned by "init")
646 * @return always NULL
647 */
648void *
649libgnunet_plugin_rest_reclaim_done (void *cls)
650{
651 struct GNUNET_REST_Plugin *api = cls;
652 struct Plugin *plugin = api->cls;
653 struct RequestHandle *request;
654
655 plugin->cfg = NULL;
656 while (NULL != (request = requests_head))
657 do_error (request);
658
659 GNUNET_free (allow_methods);
660 GNUNET_free (api);
661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662 "PABC REST plugin is finished\n");
663 return NULL;
664}
665
666
667/* end of plugin_rest_reclaim.c */
diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c
deleted file mode 100644
index a2f8d96b2..000000000
--- a/src/reclaim/plugin_rest_reclaim.c
+++ /dev/null
@@ -1,1564 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file reclaim/plugin_rest_reclaim.c
24 * @brief GNUnet reclaim REST plugin
25 *
26 */
27#include "platform.h"
28#include "microhttpd.h"
29#include <inttypes.h>
30#include <jansson.h>
31#include "gnunet_gns_service.h"
32#include "gnunet_gnsrecord_lib.h"
33#include "gnunet_identity_service.h"
34#include "gnunet_reclaim_lib.h"
35#include "gnunet_reclaim_service.h"
36#include "gnunet_rest_lib.h"
37#include "gnunet_rest_plugin.h"
38#include "gnunet_signatures.h"
39#include "json_reclaim.h"
40/**
41 * REST root namespace
42 */
43#define GNUNET_REST_API_NS_RECLAIM "/reclaim"
44
45/**
46 * Attribute namespace
47 */
48#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
49
50/**
51 * Credential namespace
52 */
53#define GNUNET_REST_API_NS_RECLAIM_CREDENTIAL "/reclaim/credential"
54
55/**
56 * Ticket namespace
57 */
58#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
59
60/**
61 * Revoke namespace
62 */
63#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
64
65/**
66 * Revoke namespace
67 */
68#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
69
70/**
71 * State while collecting all egos
72 */
73#define ID_REST_STATE_INIT 0
74
75/**
76 * Done collecting egos
77 */
78#define ID_REST_STATE_POST_INIT 1
79
80/**
81 * The configuration handle
82 */
83const struct GNUNET_CONFIGURATION_Handle *cfg;
84
85/**
86 * HTTP methods allows for this plugin
87 */
88static char *allow_methods;
89
90/**
91 * Ego list
92 */
93static struct EgoEntry *ego_head;
94
95/**
96 * Ego list
97 */
98static struct EgoEntry *ego_tail;
99
100/**
101 * The processing state
102 */
103static int state;
104
105/**
106 * Handle to Identity service.
107 */
108static struct GNUNET_IDENTITY_Handle *identity_handle;
109
110/**
111 * Identity Provider
112 */
113static struct GNUNET_RECLAIM_Handle *idp;
114
115/**
116 * @brief struct returned by the initialization function of the plugin
117 */
118struct Plugin
119{
120 const struct GNUNET_CONFIGURATION_Handle *cfg;
121};
122
123/**
124 * The ego list
125 */
126struct EgoEntry
127{
128 /**
129 * DLL
130 */
131 struct EgoEntry *next;
132
133 /**
134 * DLL
135 */
136 struct EgoEntry *prev;
137
138 /**
139 * Ego Identifier
140 */
141 char *identifier;
142
143 /**
144 * Public key string
145 */
146 char *keystring;
147
148 /**
149 * The Ego
150 */
151 struct GNUNET_IDENTITY_Ego *ego;
152};
153
154
155struct RequestHandle
156{
157 /**
158 * DLL
159 */
160 struct RequestHandle *next;
161
162 /**
163 * DLL
164 */
165 struct RequestHandle *prev;
166
167 /**
168 * Selected ego
169 */
170 struct EgoEntry *ego_entry;
171
172 /**
173 * Pointer to ego private key
174 */
175 struct GNUNET_IDENTITY_PrivateKey priv_key;
176
177 /**
178 * Rest connection
179 */
180 struct GNUNET_REST_RequestHandle *rest_handle;
181
182 /**
183 * Attribute claim list
184 */
185 struct GNUNET_RECLAIM_AttributeList *attr_list;
186
187 /**
188 * IDENTITY Operation
189 */
190 struct GNUNET_IDENTITY_Operation *op;
191
192 /**
193 * Idp Operation
194 */
195 struct GNUNET_RECLAIM_Operation *idp_op;
196
197 /**
198 * Attribute iterator
199 */
200 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
201
202 /**
203 * Attribute iterator
204 */
205 struct GNUNET_RECLAIM_CredentialIterator *cred_it;
206
207 /**
208 * Ticket iterator
209 */
210 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
211
212 /**
213 * A ticket
214 */
215 struct GNUNET_RECLAIM_Ticket ticket;
216
217 /**
218 * Desired timeout for the lookup (default is no timeout).
219 */
220 struct GNUNET_TIME_Relative timeout;
221
222 /**
223 * ID of a task associated with the resolution process.
224 */
225 struct GNUNET_SCHEDULER_Task *timeout_task;
226
227 /**
228 * The plugin result processor
229 */
230 GNUNET_REST_ResultProcessor proc;
231
232 /**
233 * The closure of the result processor
234 */
235 void *proc_cls;
236
237 /**
238 * The url
239 */
240 char *url;
241
242 /**
243 * Error response message
244 */
245 char *emsg;
246
247 /**
248 * Response code
249 */
250 int response_code;
251
252 /**
253 * Response object
254 */
255 json_t *resp_object;
256};
257
258/**
259 * DLL
260 */
261static struct RequestHandle *requests_head;
262
263/**
264 * DLL
265 */
266static struct RequestHandle *requests_tail;
267
268
269/**
270 * Cleanup lookup handle
271 * @param handle Handle to clean up
272 */
273static void
274cleanup_handle (void *cls)
275{
276 struct RequestHandle *handle = cls;
277
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
279 if (NULL != handle->resp_object)
280 json_decref (handle->resp_object);
281 if (NULL != handle->timeout_task)
282 GNUNET_SCHEDULER_cancel (handle->timeout_task);
283 if (NULL != handle->attr_it)
284 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
285 if (NULL != handle->cred_it)
286 GNUNET_RECLAIM_get_credentials_stop (handle->cred_it);
287 if (NULL != handle->ticket_it)
288 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
289 if (NULL != handle->url)
290 GNUNET_free (handle->url);
291 if (NULL != handle->emsg)
292 GNUNET_free (handle->emsg);
293 if (NULL != handle->attr_list)
294 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
295 GNUNET_CONTAINER_DLL_remove (requests_head,
296 requests_tail,
297 handle);
298 GNUNET_free (handle);
299}
300
301
302/**
303 * Task run on error, sends error message. Cleans up everything.
304 *
305 * @param cls the `struct RequestHandle`
306 */
307static void
308do_error (void *cls)
309{
310 struct RequestHandle *handle = cls;
311 struct MHD_Response *resp;
312 char *json_error;
313
314 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
315 if (0 == handle->response_code)
316 {
317 handle->response_code = MHD_HTTP_BAD_REQUEST;
318 }
319 resp = GNUNET_REST_create_response (json_error);
320 MHD_add_response_header (resp, "Content-Type", "application/json");
321 handle->proc (handle->proc_cls, resp, handle->response_code);
322 cleanup_handle (handle);
323 GNUNET_free (json_error);
324}
325
326
327/**
328 * Task run on timeout, sends error message. Cleans up everything.
329 *
330 * @param cls the `struct RequestHandle`
331 */
332static void
333do_timeout (void *cls)
334{
335 struct RequestHandle *handle = cls;
336
337 handle->timeout_task = NULL;
338 do_error (handle);
339}
340
341
342static void
343collect_error_cb (void *cls)
344{
345 GNUNET_SCHEDULER_add_now (&do_error, cls);
346}
347
348
349static void
350finished_cont (void *cls, int32_t success, const char *emsg)
351{
352 struct RequestHandle *handle = cls;
353 struct MHD_Response *resp;
354
355 handle->idp_op = NULL;
356 if (GNUNET_OK != success)
357 {
358 GNUNET_SCHEDULER_add_now (&do_error, handle);
359 return;
360 }
361 resp = GNUNET_REST_create_response (emsg);
362 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
363 "Content-Type",
364 "application/json"));
365 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
366 "Access-Control-Allow-Methods",
367 allow_methods));
368 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
369 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
370}
371
372
373static void
374delete_finished_cb (void *cls, int32_t success, const char *emsg)
375{
376 struct RequestHandle *handle = cls;
377 struct MHD_Response *resp;
378
379 if (GNUNET_OK != success)
380 {
381 GNUNET_SCHEDULER_add_now (&do_error, handle);
382 return;
383 }
384 resp = GNUNET_REST_create_response (emsg);
385 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
386 "Access-Control-Allow-Methods",
387 allow_methods));
388 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
389 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
390}
391
392
393/**
394 * Return attributes for identity
395 *
396 * @param cls the request handle
397 */
398static void
399return_response (void *cls)
400{
401 char *result_str;
402 struct RequestHandle *handle = cls;
403 struct MHD_Response *resp;
404
405 result_str = json_dumps (handle->resp_object, 0);
406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
407 resp = GNUNET_REST_create_response (result_str);
408 GNUNET_assert (MHD_NO !=
409 MHD_add_response_header (resp,
410 "Access-Control-Allow-Methods",
411 allow_methods));
412 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
413 GNUNET_free (result_str);
414 cleanup_handle (handle);
415}
416
417
418static void
419collect_finished_cb (void *cls)
420{
421 struct RequestHandle *handle = cls;
422
423 // Done
424 handle->attr_it = NULL;
425 handle->cred_it = NULL;
426 handle->ticket_it = NULL;
427 GNUNET_SCHEDULER_add_now (&return_response, handle);
428}
429
430
431/**
432 * Collect all attributes for an ego
433 *
434 */
435static void
436ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
437{
438 json_t *json_resource;
439 struct RequestHandle *handle = cls;
440 json_t *value;
441 char *tmp;
442
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
444 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
445 json_resource = json_object ();
446 GNUNET_free (tmp);
447 json_array_append (handle->resp_object, json_resource);
448
449 tmp =
450 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
451 sizeof(struct
452 GNUNET_IDENTITY_PublicKey));
453 value = json_string (tmp);
454 json_object_set_new (json_resource, "issuer", value);
455 GNUNET_free (tmp);
456 tmp =
457 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
458 sizeof(struct
459 GNUNET_IDENTITY_PublicKey));
460 value = json_string (tmp);
461 json_object_set_new (json_resource, "audience", value);
462 GNUNET_free (tmp);
463 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
464 value = json_string (tmp);
465 json_object_set_new (json_resource, "rnd", value);
466 GNUNET_free (tmp);
467 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
468}
469
470
471static void
472add_credential_cont (struct GNUNET_REST_RequestHandle *con_handle,
473 const char *url,
474 void *cls)
475{
476 struct RequestHandle *handle = cls;
477 const struct GNUNET_IDENTITY_PrivateKey *identity_priv;
478 const char *identity;
479 struct EgoEntry *ego_entry;
480 struct GNUNET_RECLAIM_Credential *attribute;
481 struct GNUNET_TIME_Relative exp;
482 char term_data[handle->rest_handle->data_size + 1];
483 json_t *data_json;
484 json_error_t err;
485 struct GNUNET_JSON_Specification attrspec[] =
486 { GNUNET_RECLAIM_JSON_spec_credential (&attribute),
487 GNUNET_JSON_spec_end () };
488
489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 "Adding an credential for %s.\n",
491 handle->url);
492 if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen (
493 handle->url))
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
496 GNUNET_SCHEDULER_add_now (&do_error, handle);
497 return;
498 }
499 identity = handle->url + strlen (
500 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1;
501
502 for (ego_entry = ego_head; NULL != ego_entry;
503 ego_entry = ego_entry->next)
504 if (0 == strcmp (identity, ego_entry->identifier))
505 break;
506
507 if (NULL == ego_entry)
508 {
509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
510 return;
511 }
512 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
513
514 if (0 >= handle->rest_handle->data_size)
515 {
516 GNUNET_SCHEDULER_add_now (&do_error, handle);
517 return;
518 }
519
520 term_data[handle->rest_handle->data_size] = '\0';
521 GNUNET_memcpy (term_data,
522 handle->rest_handle->data,
523 handle->rest_handle->data_size);
524 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
525 if (GNUNET_OK != GNUNET_JSON_parse (data_json, attrspec, NULL, NULL))
526 {
527 json_decref (data_json);
528 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
529 "Unable to parse JSON from %s\n",
530 term_data);
531 GNUNET_SCHEDULER_add_now (&do_error, handle);
532 return;
533 }
534 json_decref (data_json);
535 if (NULL == attribute)
536 {
537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
538 "Unable to parse credential from %s\n",
539 term_data);
540 GNUNET_SCHEDULER_add_now (&do_error, handle);
541 return;
542 }
543 /**
544 * New ID for attribute
545 */
546 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
547 GNUNET_RECLAIM_id_generate (&attribute->id);
548 exp = GNUNET_TIME_UNIT_HOURS;
549 handle->idp_op = GNUNET_RECLAIM_credential_store (idp,
550 identity_priv,
551 attribute,
552 &exp,
553 &finished_cont,
554 handle);
555 GNUNET_JSON_parse_free (attrspec);
556}
557
558
559/**
560 * Collect all credentials for an ego
561 *
562 */
563static void
564cred_collect (void *cls,
565 const struct GNUNET_IDENTITY_PublicKey *identity,
566 const struct GNUNET_RECLAIM_Credential *cred)
567{
568 struct RequestHandle *handle = cls;
569 struct GNUNET_RECLAIM_AttributeList *attrs;
570 struct GNUNET_RECLAIM_AttributeListEntry *ale;
571 struct GNUNET_TIME_Absolute exp;
572 json_t *attr_obj;
573 json_t *cred_obj;
574 const char *type;
575 char *tmp_value;
576 char *id_str;
577 char *issuer;
578
579
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding credential: %s\n",
581 cred->name);
582 attrs = GNUNET_RECLAIM_credential_get_attributes (cred);
583 issuer = GNUNET_RECLAIM_credential_get_issuer (cred);
584 tmp_value = GNUNET_RECLAIM_credential_value_to_string (cred->type,
585 cred->data,
586 cred->data_size);
587 cred_obj = json_object ();
588 json_object_set_new (cred_obj, "value", json_string (tmp_value));
589 json_object_set_new (cred_obj, "name", json_string (cred->name));
590 type = GNUNET_RECLAIM_credential_number_to_typename (cred->type);
591 json_object_set_new (cred_obj, "type", json_string (type));
592 if (NULL != issuer)
593 {
594 json_object_set_new (cred_obj, "issuer", json_string (issuer));
595 GNUNET_free (issuer);
596 }
597 if (GNUNET_OK == GNUNET_RECLAIM_credential_get_expiration (cred,
598 &exp))
599 {
600 json_object_set_new (cred_obj, "expiration", json_integer (
601 exp.abs_value_us));
602 }
603 id_str = GNUNET_STRINGS_data_to_string_alloc (&cred->id,
604 sizeof(cred->id));
605 json_object_set_new (cred_obj, "id", json_string (id_str));
606 GNUNET_free (tmp_value);
607 GNUNET_free (id_str);
608 if (NULL != attrs)
609 {
610 json_t *attr_arr = json_array ();
611 for (ale = attrs->list_head; NULL != ale; ale = ale->next)
612 {
613 tmp_value =
614 GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type,
615 ale->attribute->data,
616 ale->attribute->data_size);
617 attr_obj = json_object ();
618 json_object_set_new (attr_obj, "value", json_string (tmp_value));
619 json_object_set_new (attr_obj, "name", json_string (
620 ale->attribute->name));
621
622 json_object_set_new (attr_obj, "flag", json_string ("1")); // FIXME
623 type = GNUNET_RECLAIM_attribute_number_to_typename (ale->attribute->type);
624 json_object_set_new (attr_obj, "type", json_string (type));
625 json_object_set_new (attr_obj, "id", json_string (""));
626 json_object_set_new (attr_obj, "credential", json_string (""));
627 json_array_append_new (attr_arr, attr_obj);
628 GNUNET_free (tmp_value);
629 }
630 json_object_set_new (cred_obj, "attributes", attr_arr);
631 }
632 json_array_append_new (handle->resp_object, cred_obj);
633 if (NULL != attrs)
634 GNUNET_RECLAIM_attribute_list_destroy (attrs);
635 GNUNET_RECLAIM_get_credentials_next (handle->cred_it);
636}
637
638
639/**
640 * Lists credential for identity request
641 *
642 * @param con_handle the connection handle
643 * @param url the url
644 * @param cls the RequestHandle
645 */
646static void
647list_credential_cont (struct GNUNET_REST_RequestHandle *con_handle,
648 const char *url,
649 void *cls)
650{
651 struct RequestHandle *handle = cls;
652 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
653 struct EgoEntry *ego_entry;
654 char *identity;
655
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657 "Getting credentials for %s.\n",
658 handle->url);
659 if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen (
660 handle->url))
661 {
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
663 GNUNET_SCHEDULER_add_now (&do_error, handle);
664 return;
665 }
666 identity = handle->url + strlen (
667 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1;
668
669 for (ego_entry = ego_head; NULL != ego_entry;
670 ego_entry = ego_entry->next)
671 if (0 == strcmp (identity, ego_entry->identifier))
672 break;
673 handle->resp_object = json_array ();
674
675
676 if (NULL == ego_entry)
677 {
678 // Done
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
680 GNUNET_SCHEDULER_add_now (&return_response, handle);
681 return;
682 }
683 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
684 handle->cred_it = GNUNET_RECLAIM_get_credentials_start (idp,
685 priv_key,
686 &collect_error_cb,
687 handle,
688 &cred_collect,
689 handle,
690 &
691 collect_finished_cb,
692 handle);
693}
694
695
696/**
697 * Deletes credential from an identity
698 *
699 * @param con_handle the connection handle
700 * @param url the url
701 * @param cls the RequestHandle
702 */
703static void
704delete_credential_cont (struct GNUNET_REST_RequestHandle *con_handle,
705 const char *url,
706 void *cls)
707{
708 struct RequestHandle *handle = cls;
709 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
710 struct GNUNET_RECLAIM_Credential attr;
711 struct EgoEntry *ego_entry;
712 char *identity_id_str;
713 char *identity;
714 char *id;
715
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting credential.\n");
717 if (strlen (GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) >= strlen (
718 handle->url))
719 {
720 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
721 GNUNET_SCHEDULER_add_now (&do_error, handle);
722 return;
723 }
724 identity_id_str =
725 strdup (handle->url + strlen (
726 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL) + 1);
727 identity = strtok (identity_id_str, "/");
728 id = strtok (NULL, "/");
729 if ((NULL == identity) || (NULL == id))
730 {
731 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
732 GNUNET_free (identity_id_str);
733 GNUNET_SCHEDULER_add_now (&do_error, handle);
734 return;
735 }
736
737 for (ego_entry = ego_head; NULL != ego_entry;
738 ego_entry = ego_entry->next)
739 if (0 == strcmp (identity, ego_entry->identifier))
740 break;
741 handle->resp_object = json_array ();
742 if (NULL == ego_entry)
743 {
744 // Done
745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
746 GNUNET_free (identity_id_str);
747 GNUNET_SCHEDULER_add_now (&return_response, handle);
748 return;
749 }
750 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
751 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Credential));
752 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
753 attr.name = "";
754 handle->idp_op = GNUNET_RECLAIM_credential_delete (idp,
755 priv_key,
756 &attr,
757 &delete_finished_cb,
758 handle);
759 GNUNET_free (identity_id_str);
760}
761
762
763/**
764 * List tickets for identity request
765 *
766 * @param con_handle the connection handle
767 * @param url the url
768 * @param cls the RequestHandle
769 */
770static void
771list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
772 const char *url,
773 void *cls)
774{
775 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
776 struct RequestHandle *handle = cls;
777 struct EgoEntry *ego_entry;
778 char *identity;
779
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Getting tickets for %s.\n",
782 handle->url);
783 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
784 {
785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
786 GNUNET_SCHEDULER_add_now (&do_error, handle);
787 return;
788 }
789 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
790
791 for (ego_entry = ego_head; NULL != ego_entry;
792 ego_entry = ego_entry->next)
793 if (0 == strcmp (identity, ego_entry->identifier))
794 break;
795 handle->resp_object = json_array ();
796
797 if (NULL == ego_entry)
798 {
799 // Done
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
801 GNUNET_SCHEDULER_add_now (&return_response, handle);
802 return;
803 }
804 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
805 handle->ticket_it =
806 GNUNET_RECLAIM_ticket_iteration_start (idp,
807 priv_key,
808 &collect_error_cb,
809 handle,
810 &ticket_collect,
811 handle,
812 &collect_finished_cb,
813 handle);
814}
815
816
817static void
818add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
819 const char *url,
820 void *cls)
821{
822 const struct GNUNET_IDENTITY_PrivateKey *identity_priv;
823 const char *identity;
824 struct RequestHandle *handle = cls;
825 struct EgoEntry *ego_entry;
826 struct GNUNET_RECLAIM_Attribute *attribute;
827 struct GNUNET_TIME_Relative exp;
828 char term_data[handle->rest_handle->data_size + 1];
829 json_t *data_json;
830 json_error_t err;
831 struct GNUNET_JSON_Specification attrspec[] =
832 { GNUNET_RECLAIM_JSON_spec_attribute (&attribute), GNUNET_JSON_spec_end () };
833
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "Adding an attribute for %s.\n",
836 handle->url);
837 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
838 {
839 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
840 GNUNET_SCHEDULER_add_now (&do_error, handle);
841 return;
842 }
843 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
844
845 for (ego_entry = ego_head; NULL != ego_entry;
846 ego_entry = ego_entry->next)
847 if (0 == strcmp (identity, ego_entry->identifier))
848 break;
849
850 if (NULL == ego_entry)
851 {
852 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
853 return;
854 }
855 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
856
857 if (0 >= handle->rest_handle->data_size)
858 {
859 GNUNET_SCHEDULER_add_now (&do_error, handle);
860 return;
861 }
862
863 term_data[handle->rest_handle->data_size] = '\0';
864 GNUNET_memcpy (term_data,
865 handle->rest_handle->data,
866 handle->rest_handle->data_size);
867 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
868 GNUNET_assert (GNUNET_OK ==
869 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
870 json_decref (data_json);
871 if (NULL == attribute)
872 {
873 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
874 "Unable to parse attribute from %s\n",
875 term_data);
876 GNUNET_SCHEDULER_add_now (&do_error, handle);
877 return;
878 }
879 /**
880 * New ID for attribute
881 */
882 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
883 GNUNET_RECLAIM_id_generate (&attribute->id);
884 exp = GNUNET_TIME_UNIT_HOURS;
885 handle->idp_op = GNUNET_RECLAIM_attribute_store (idp,
886 identity_priv,
887 attribute,
888 &exp,
889 &finished_cont,
890 handle);
891 GNUNET_JSON_parse_free (attrspec);
892}
893
894
895/**
896 * Parse a JWT and return the respective claim value as Attribute
897 *
898 * @param cred the jwt credential
899 * @param claim the name of the claim in the JWT
900 *
901 * @return a GNUNET_RECLAIM_Attribute, containing the new value
902 */
903struct GNUNET_RECLAIM_Attribute *
904parse_jwt (const struct GNUNET_RECLAIM_Credential *cred,
905 const char *claim)
906{
907 char *jwt_string;
908 struct GNUNET_RECLAIM_Attribute *attr;
909 char delim[] = ".";
910 const char *type_str = NULL;
911 const char *val_str = NULL;
912 char *data;
913 size_t data_size;
914 uint32_t type;
915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
916 char *decoded_jwt;
917 json_t *json_val;
918 json_error_t *json_err = NULL;
919
920 jwt_string = GNUNET_RECLAIM_credential_value_to_string (cred->type,
921 cred->data,
922 cred->data_size);
923 char *jwt_body = strtok (jwt_string, delim);
924 jwt_body = strtok (NULL, delim);
925 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
926 (void **) &decoded_jwt);
927 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
928 const char *key;
929 json_t *value;
930 json_object_foreach (json_val, key, value) {
931 if (0 == strcasecmp (key,claim))
932 {
933 val_str = json_dumps (value, JSON_ENCODE_ANY);
934 }
935 }
936 type_str = "String";
937 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
938 if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
939 (void **) &data,
940 &data_size))
941 {
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
943 "Attribute value from JWT Parser invalid!\n");
944 GNUNET_RECLAIM_attribute_string_to_value (type,
945 "Error: Referenced Claim Name not Found",
946 (void **) &data,
947 &data_size);
948 attr = GNUNET_RECLAIM_attribute_new (claim, &cred->id,
949 type, data, data_size);
950 attr->id = cred->id;
951 attr->flag = 1;
952 }
953 else
954 {
955 attr = GNUNET_RECLAIM_attribute_new (claim, &cred->id,
956 type, data, data_size);
957 attr->id = cred->id;
958 attr->flag = 1;
959 }
960 return attr;
961}
962
963
964/**
965 * Collect all attributes for an ego
966 *
967 */
968static void
969attr_collect (void *cls,
970 const struct GNUNET_IDENTITY_PublicKey *identity,
971 const struct GNUNET_RECLAIM_Attribute *attr)
972{
973 struct RequestHandle *handle = cls;
974 json_t *attr_obj;
975 const char *type;
976 char *id_str;
977
978 char *tmp_value;
979 tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
980 attr->data,
981 attr->data_size);
982 attr_obj = json_object ();
983 json_object_set_new (attr_obj, "value", json_string (tmp_value));
984 json_object_set_new (attr_obj, "name", json_string (attr->name));
985
986 if (GNUNET_RECLAIM_id_is_zero (&attr->credential))
987 json_object_set_new (attr_obj, "flag", json_string ("0"));
988 else
989 json_object_set_new (attr_obj, "flag", json_string ("1"));
990 type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
991 json_object_set_new (attr_obj, "type", json_string (type));
992 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
993 sizeof(attr->id));
994 json_object_set_new (attr_obj, "id", json_string (id_str));
995 GNUNET_free (id_str);
996 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->credential,
997 sizeof(attr->credential));
998 json_object_set_new (attr_obj, "credential", json_string (id_str));
999 GNUNET_free (id_str);
1000 json_array_append (handle->resp_object, attr_obj);
1001 json_decref (attr_obj);
1002 GNUNET_free (tmp_value);
1003 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1004}
1005
1006
1007/**
1008 * List attributes for identity request
1009 *
1010 * @param con_handle the connection handle
1011 * @param url the url
1012 * @param cls the RequestHandle
1013 */
1014static void
1015list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1016 const char *url,
1017 void *cls)
1018{
1019 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
1020 struct RequestHandle *handle = cls;
1021 struct EgoEntry *ego_entry;
1022 char *identity;
1023
1024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1025 "Getting attributes for %s.\n",
1026 handle->url);
1027 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1028 {
1029 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1030 GNUNET_SCHEDULER_add_now (&do_error, handle);
1031 return;
1032 }
1033 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1034
1035 for (ego_entry = ego_head; NULL != ego_entry;
1036 ego_entry = ego_entry->next)
1037 if (0 == strcmp (identity, ego_entry->identifier))
1038 break;
1039 handle->resp_object = json_array ();
1040
1041
1042 if (NULL == ego_entry)
1043 {
1044 // Done
1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1046 GNUNET_SCHEDULER_add_now (&return_response, handle);
1047 return;
1048 }
1049 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1050 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (idp,
1051 priv_key,
1052 &collect_error_cb,
1053 handle,
1054 &attr_collect,
1055 handle,
1056 &collect_finished_cb,
1057 handle);
1058}
1059
1060
1061/**
1062 * List attributes for identity request
1063 *
1064 * @param con_handle the connection handle
1065 * @param url the url
1066 * @param cls the RequestHandle
1067 */
1068static void
1069delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1070 const char *url,
1071 void *cls)
1072{
1073 const struct GNUNET_IDENTITY_PrivateKey *priv_key;
1074 struct RequestHandle *handle = cls;
1075 struct GNUNET_RECLAIM_Attribute attr;
1076 struct EgoEntry *ego_entry;
1077 char *identity_id_str;
1078 char *identity;
1079 char *id;
1080
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1082 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1083 {
1084 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1085 GNUNET_SCHEDULER_add_now (&do_error, handle);
1086 return;
1087 }
1088 identity_id_str =
1089 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1090 identity = strtok (identity_id_str, "/");
1091 id = strtok (NULL, "/");
1092 if ((NULL == identity) || (NULL == id))
1093 {
1094 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1095 GNUNET_free (identity_id_str);
1096 GNUNET_SCHEDULER_add_now (&do_error, handle);
1097 return;
1098 }
1099
1100 for (ego_entry = ego_head; NULL != ego_entry;
1101 ego_entry = ego_entry->next)
1102 if (0 == strcmp (identity, ego_entry->identifier))
1103 break;
1104 handle->resp_object = json_array ();
1105 if (NULL == ego_entry)
1106 {
1107 // Done
1108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1109 GNUNET_free (identity_id_str);
1110 GNUNET_SCHEDULER_add_now (&return_response, handle);
1111 return;
1112 }
1113 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1114 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1115 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1116 attr.name = "";
1117 handle->idp_op = GNUNET_RECLAIM_attribute_delete (idp,
1118 priv_key,
1119 &attr,
1120 &delete_finished_cb,
1121 handle);
1122 GNUNET_free (identity_id_str);
1123}
1124
1125
1126static void
1127revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1128 const char *url,
1129 void *cls)
1130{
1131 const struct GNUNET_IDENTITY_PrivateKey *identity_priv;
1132 struct RequestHandle *handle = cls;
1133 struct EgoEntry *ego_entry;
1134 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1135 struct GNUNET_IDENTITY_PublicKey tmp_pk;
1136 char term_data[handle->rest_handle->data_size + 1];
1137 json_t *data_json;
1138 json_error_t err;
1139 struct GNUNET_JSON_Specification tktspec[] =
1140 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1141
1142 if (0 >= handle->rest_handle->data_size)
1143 {
1144 GNUNET_SCHEDULER_add_now (&do_error, handle);
1145 return;
1146 }
1147
1148 term_data[handle->rest_handle->data_size] = '\0';
1149 GNUNET_memcpy (term_data,
1150 handle->rest_handle->data,
1151 handle->rest_handle->data_size);
1152 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1153 if ((NULL == data_json) ||
1154 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1155 {
1156 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1157 GNUNET_SCHEDULER_add_now (&do_error, handle);
1158 GNUNET_JSON_parse_free (tktspec);
1159 if (NULL != data_json)
1160 json_decref (data_json);
1161 return;
1162 }
1163 json_decref (data_json);
1164 if (NULL == ticket)
1165 {
1166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1167 "Unable to parse ticket from %s\n",
1168 term_data);
1169 GNUNET_SCHEDULER_add_now (&do_error, handle);
1170 return;
1171 }
1172
1173 for (ego_entry = ego_head; NULL != ego_entry;
1174 ego_entry = ego_entry->next)
1175 {
1176 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1177 if (0 == memcmp (&ticket->identity,
1178 &tmp_pk,
1179 sizeof(struct GNUNET_IDENTITY_PublicKey)))
1180 break;
1181 }
1182 if (NULL == ego_entry)
1183 {
1184 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1185 GNUNET_JSON_parse_free (tktspec);
1186 return;
1187 }
1188 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1189
1190 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (idp,
1191 identity_priv,
1192 ticket,
1193 &finished_cont,
1194 handle);
1195 GNUNET_JSON_parse_free (tktspec);
1196}
1197
1198
1199static void
1200consume_cont (void *cls,
1201 const struct GNUNET_IDENTITY_PublicKey *identity,
1202 const struct GNUNET_RECLAIM_Attribute *attr,
1203 const struct GNUNET_RECLAIM_Presentation *presentation)
1204{
1205 struct RequestHandle *handle = cls;
1206 char *val_str;
1207 json_t *value;
1208
1209 if (NULL == identity)
1210 {
1211 GNUNET_SCHEDULER_add_now (&return_response, handle);
1212 return;
1213 }
1214
1215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1216 val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1217 attr->data,
1218 attr->data_size);
1219 if (NULL == val_str)
1220 {
1221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1222 "Failed to parse value for: %s\n",
1223 attr->name);
1224 return;
1225 }
1226 value = json_string (val_str);
1227 json_object_set_new (handle->resp_object, attr->name, value);
1228 json_decref (value);
1229 GNUNET_free (val_str);
1230}
1231
1232
1233static void
1234consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1235 const char *url,
1236 void *cls)
1237{
1238 const struct GNUNET_IDENTITY_PrivateKey *identity_priv;
1239 struct RequestHandle *handle = cls;
1240 struct EgoEntry *ego_entry;
1241 struct GNUNET_RECLAIM_Ticket *ticket;
1242 struct GNUNET_IDENTITY_PublicKey tmp_pk;
1243 char term_data[handle->rest_handle->data_size + 1];
1244 json_t *data_json;
1245 json_error_t err;
1246 struct GNUNET_JSON_Specification tktspec[] =
1247 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1248
1249 if (0 >= handle->rest_handle->data_size)
1250 {
1251 GNUNET_SCHEDULER_add_now (&do_error, handle);
1252 return;
1253 }
1254
1255 term_data[handle->rest_handle->data_size] = '\0';
1256 GNUNET_memcpy (term_data,
1257 handle->rest_handle->data,
1258 handle->rest_handle->data_size);
1259 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1260 if (NULL == data_json)
1261 {
1262 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1263 "Unable to parse JSON Object from %s\n",
1264 term_data);
1265 GNUNET_SCHEDULER_add_now (&do_error, handle);
1266 return;
1267 }
1268 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1269 {
1270 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1271 GNUNET_SCHEDULER_add_now (&do_error, handle);
1272 GNUNET_JSON_parse_free (tktspec);
1273 json_decref (data_json);
1274 return;
1275 }
1276 for (ego_entry = ego_head; NULL != ego_entry;
1277 ego_entry = ego_entry->next)
1278 {
1279 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1280 if (0 == memcmp (&ticket->audience,
1281 &tmp_pk,
1282 sizeof(struct GNUNET_IDENTITY_PublicKey)))
1283 break;
1284 }
1285 if (NULL == ego_entry)
1286 {
1287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1288 GNUNET_JSON_parse_free (tktspec);
1289 return;
1290 }
1291 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1292 handle->resp_object = json_object ();
1293 handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp,
1294 identity_priv,
1295 ticket,
1296 &consume_cont,
1297 handle);
1298 GNUNET_JSON_parse_free (tktspec);
1299}
1300
1301
1302/**
1303 * Respond to OPTIONS request
1304 *
1305 * @param con_handle the connection handle
1306 * @param url the url
1307 * @param cls the RequestHandle
1308 */
1309static void
1310options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1311 const char *url,
1312 void *cls)
1313{
1314 struct MHD_Response *resp;
1315 struct RequestHandle *handle = cls;
1316
1317 // For now, independent of path return all options
1318 resp = GNUNET_REST_create_response (NULL);
1319 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1320 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1321 cleanup_handle (handle);
1322 return;
1323}
1324
1325
1326/**
1327 * If listing is enabled, prints information about the egos.
1328 *
1329 * This function is initially called for all egos and then again
1330 * whenever a ego's identifier changes or if it is deleted. At the
1331 * end of the initial pass over all egos, the function is once called
1332 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1333 * be invoked in the future or that there was an error.
1334 *
1335 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
1336 * function is only called ONCE, and 'NULL' being passed in 'ego' does
1337 * indicate an error (for example because name is taken or no default value is
1338 * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
1339 * value WILL be passed to a subsequent call to the identity callback of
1340 * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
1341 *
1342 * When an identity is renamed, this function is called with the
1343 * (known) ego but the NEW identifier.
1344 *
1345 * When an identity is deleted, this function is called with the
1346 * (known) ego and "NULL" for the 'identifier'. In this case,
1347 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1348 * cleaned up).
1349 *
1350 * @param cls closure
1351 * @param ego ego handle
1352 * @param ctx context for application to store data for this ego
1353 * (during the lifetime of this process, initially NULL)
1354 * @param identifier identifier assigned by the user for this ego,
1355 * NULL if the user just deleted the ego and it
1356 * must thus no longer be used
1357 */
1358static void
1359list_ego (void *cls,
1360 struct GNUNET_IDENTITY_Ego *ego,
1361 void **ctx,
1362 const char *identifier)
1363{
1364 struct EgoEntry *ego_entry;
1365 struct GNUNET_IDENTITY_PublicKey pk;
1366
1367 if (NULL == ego)
1368 {
1369 state = ID_REST_STATE_POST_INIT;
1370 return;
1371 }
1372 if (ID_REST_STATE_INIT == state)
1373 {
1374 ego_entry = GNUNET_new (struct EgoEntry);
1375 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1376 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
1377 ego_entry->ego = ego;
1378 ego_entry->identifier = GNUNET_strdup (identifier);
1379 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1380 ego_tail,
1381 ego_entry);
1382 }
1383 /* Ego renamed or added */
1384 if (identifier != NULL)
1385 {
1386 for (ego_entry = ego_head; NULL != ego_entry;
1387 ego_entry = ego_entry->next)
1388 {
1389 if (ego_entry->ego == ego)
1390 {
1391 /* Rename */
1392 GNUNET_free (ego_entry->identifier);
1393 ego_entry->identifier = GNUNET_strdup (identifier);
1394 break;
1395 }
1396 }
1397 if (NULL == ego_entry)
1398 {
1399 /* Add */
1400 ego_entry = GNUNET_new (struct EgoEntry);
1401 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1402 ego_entry->keystring = GNUNET_IDENTITY_public_key_to_string (&pk);
1403 ego_entry->ego = ego;
1404 ego_entry->identifier = GNUNET_strdup (identifier);
1405 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1406 ego_tail,
1407 ego_entry);
1408 }
1409 }
1410 else
1411 {
1412 /* Delete */
1413 for (ego_entry = ego_head; NULL != ego_entry;
1414 ego_entry = ego_entry->next)
1415 {
1416 if (ego_entry->ego == ego)
1417 break;
1418 }
1419 if (NULL == ego_entry)
1420 return; /* Not found */
1421
1422 GNUNET_CONTAINER_DLL_remove (ego_head,
1423 ego_tail,
1424 ego_entry);
1425 GNUNET_free (ego_entry->identifier);
1426 GNUNET_free (ego_entry->keystring);
1427 GNUNET_free (ego_entry);
1428 return;
1429 }
1430
1431}
1432
1433
1434static enum GNUNET_GenericReturnValue
1435rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1436 GNUNET_REST_ResultProcessor proc,
1437 void *proc_cls)
1438{
1439 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1440 struct GNUNET_REST_RequestHandlerError err;
1441 static const struct GNUNET_REST_RequestHandler handlers[] =
1442 { { MHD_HTTP_METHOD_GET,
1443 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont },
1444 { MHD_HTTP_METHOD_POST,
1445 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont },
1446 { MHD_HTTP_METHOD_DELETE,
1447 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &delete_attribute_cont },
1448 { MHD_HTTP_METHOD_GET,
1449 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &list_credential_cont },
1450 { MHD_HTTP_METHOD_POST,
1451 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &add_credential_cont },
1452 { MHD_HTTP_METHOD_DELETE,
1453 GNUNET_REST_API_NS_RECLAIM_CREDENTIAL, &delete_credential_cont },
1454 { MHD_HTTP_METHOD_GET,
1455 GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont },
1456 { MHD_HTTP_METHOD_POST,
1457 GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont },
1458 { MHD_HTTP_METHOD_POST,
1459 GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont },
1460 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1461 GNUNET_REST_HANDLER_END};
1462
1463 handle->response_code = 0;
1464 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1465 handle->proc_cls = proc_cls;
1466 handle->proc = proc;
1467 handle->rest_handle = rest_handle;
1468
1469 handle->url = GNUNET_strdup (rest_handle->url);
1470 if (handle->url[strlen (handle->url) - 1] == '/')
1471 handle->url[strlen (handle->url) - 1] = '\0';
1472 handle->timeout_task =
1473 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1474 GNUNET_CONTAINER_DLL_insert (requests_head,
1475 requests_tail,
1476 handle);
1477 if (GNUNET_NO ==
1478 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1479 {
1480 cleanup_handle (handle);
1481 return GNUNET_NO;
1482 }
1483
1484 return GNUNET_YES;
1485}
1486
1487
1488/**
1489 * Entry point for the plugin.
1490 *
1491 * @param cls Config info
1492 * @return NULL on error, otherwise the plugin context
1493 */
1494void *
1495libgnunet_plugin_rest_reclaim_init (void *cls)
1496{
1497 static struct Plugin plugin;
1498 struct GNUNET_REST_Plugin *api;
1499
1500 cfg = cls;
1501 if (NULL != plugin.cfg)
1502 return NULL; /* can only initialize once! */
1503 memset (&plugin, 0, sizeof(struct Plugin));
1504 plugin.cfg = cfg;
1505 api = GNUNET_new (struct GNUNET_REST_Plugin);
1506 api->cls = &plugin;
1507 api->name = GNUNET_REST_API_NS_RECLAIM;
1508 api->process_request = &rest_identity_process_request;
1509 GNUNET_asprintf (&allow_methods,
1510 "%s, %s, %s, %s, %s",
1511 MHD_HTTP_METHOD_GET,
1512 MHD_HTTP_METHOD_POST,
1513 MHD_HTTP_METHOD_PUT,
1514 MHD_HTTP_METHOD_DELETE,
1515 MHD_HTTP_METHOD_OPTIONS);
1516 identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, NULL);
1517 state = ID_REST_STATE_INIT;
1518 idp = GNUNET_RECLAIM_connect (cfg);
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 _ ("Identity Provider REST API initialized\n"));
1521 return api;
1522}
1523
1524
1525/**
1526 * Exit point from the plugin.
1527 *
1528 * @param cls the plugin context (as returned by "init")
1529 * @return always NULL
1530 */
1531void *
1532libgnunet_plugin_rest_reclaim_done (void *cls)
1533{
1534 struct GNUNET_REST_Plugin *api = cls;
1535 struct Plugin *plugin = api->cls;
1536 struct RequestHandle *request;
1537 struct EgoEntry *ego_entry;
1538 struct EgoEntry *ego_tmp;
1539
1540 plugin->cfg = NULL;
1541 while (NULL != (request = requests_head))
1542 do_error (request);
1543 if (NULL != idp)
1544 GNUNET_RECLAIM_disconnect (idp);
1545 if (NULL != identity_handle)
1546 GNUNET_IDENTITY_disconnect (identity_handle);
1547 for (ego_entry = ego_head; NULL != ego_entry;)
1548 {
1549 ego_tmp = ego_entry;
1550 ego_entry = ego_entry->next;
1551 GNUNET_free (ego_tmp->identifier);
1552 GNUNET_free (ego_tmp->keystring);
1553 GNUNET_free (ego_tmp);
1554 }
1555
1556 GNUNET_free (allow_methods);
1557 GNUNET_free (api);
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1559 "Identity Provider REST plugin is finished\n");
1560 return NULL;
1561}
1562
1563
1564/* end of plugin_rest_reclaim.c */
diff --git a/src/reclaim/reclaim.conf b/src/reclaim/reclaim.conf
deleted file mode 100644
index 8655f2e0b..000000000
--- a/src/reclaim/reclaim.conf
+++ /dev/null
@@ -1,19 +0,0 @@
1[reclaim]
2START_ON_DEMAND = YES
3RUN_PER_USER = YES
4#PORT = 2108
5HOSTNAME = localhost
6BINARY = gnunet-service-reclaim
7ACCEPT_FROM = 127.0.0.1;
8ACCEPT_FROM6 = ::1;
9UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-reclaim.sock
10UNIX_MATCH_UID = NO
11UNIX_MATCH_GID = YES
12TICKET_REFRESH_INTERVAL = 6h
13
14[reclaim-rest-plugin]
15#ADDRESS = https://identity.gnu:8000#/login
16ADDRESS = https://ui.reclaim/#/login
17OIDC_CLIENT_SECRET = secret
18JWT_SECRET = secret
19EXPIRATION_TIME = 1d
diff --git a/src/reclaim/reclaim.h b/src/reclaim/reclaim.h
deleted file mode 100644
index aae8ee89a..000000000
--- a/src/reclaim/reclaim.h
+++ /dev/null
@@ -1,552 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 * @author Martin Schanzenbach
23 * @file reclaim/reclaim.h
24 *
25 * @brief Common type definitions for the identity provider
26 * service and API.
27 */
28#ifndef RECLAIM_H
29#define RECLAIM_H
30
31#include "gnunet_common.h"
32#include "gnunet_identity_service.h"
33
34GNUNET_NETWORK_STRUCT_BEGIN
35
36
37/**
38 * Use to store an identity attribute
39 */
40struct AttributeStoreMessage
41{
42 /**
43 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT
44 */
45 struct GNUNET_MessageHeader header;
46
47 /**
48 * Unique identifier for this request (for key collisions).
49 */
50 uint32_t id GNUNET_PACKED;
51
52 /**
53 * The length of the attribute
54 */
55 uint32_t attr_len GNUNET_PACKED;
56
57 /**
58 * The expiration interval of the attribute
59 */
60 uint64_t exp GNUNET_PACKED;
61
62 /**
63 * Identity
64 */
65 struct GNUNET_IDENTITY_PrivateKey identity;
66
67 /* followed by the serialized attribute */
68};
69
70
71/**
72 * Use to delete an identity attribute
73 */
74struct AttributeDeleteMessage
75{
76 /**
77 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT
78 */
79 struct GNUNET_MessageHeader header;
80
81 /**
82 * Unique identifier for this request (for key collisions).
83 */
84 uint32_t id GNUNET_PACKED;
85
86 /**
87 * The length of the attribute
88 */
89 uint32_t attr_len GNUNET_PACKED;
90
91 /**
92 * Identity
93 */
94 struct GNUNET_IDENTITY_PrivateKey identity;
95
96 /* followed by the serialized attribute */
97};
98
99
100/**
101 * Attribute store/delete response message
102 */
103struct SuccessResultMessage
104{
105 /**
106 * Message header
107 */
108 struct GNUNET_MessageHeader header;
109
110 /**
111 * Unique identifier for this request (for key collisions).
112 */
113 uint32_t id GNUNET_PACKED;
114
115 /**
116 * #GNUNET_SYSERR on failure, #GNUNET_OK on success
117 */
118 int32_t op_result GNUNET_PACKED;
119};
120
121/**
122 * Attribute is returned from the idp.
123 */
124struct AttributeResultMessage
125{
126 /**
127 * Message header
128 */
129 struct GNUNET_MessageHeader header;
130
131 /**
132 * Unique identifier for this request (for key collisions).
133 */
134 uint32_t id GNUNET_PACKED;
135
136 /**
137 * Length of serialized attribute data
138 */
139 uint16_t attr_len GNUNET_PACKED;
140
141 /**
142 * Length of serialized credential data
143 */
144 uint16_t credential_len GNUNET_PACKED;
145
146 /**
147 * always zero (for alignment)
148 */
149 uint16_t reserved GNUNET_PACKED;
150
151 /**
152 * The public key of the identity.
153 */
154 struct GNUNET_IDENTITY_PublicKey identity;
155
156 /* followed by:
157 * serialized attribute data
158 */
159};
160
161/**
162 * Credential is returned from the idp.
163 */
164struct CredentialResultMessage
165{
166 /**
167 * Message header
168 */
169 struct GNUNET_MessageHeader header;
170
171 /**
172 * Unique identifier for this request (for key collisions).
173 */
174 uint32_t id GNUNET_PACKED;
175
176 /**
177 * Length of serialized attribute data
178 */
179 uint16_t credential_len GNUNET_PACKED;
180
181 /**
182 * always zero (for alignment)
183 */
184 uint16_t reserved GNUNET_PACKED;
185
186 /**
187 * The public key of the identity.
188 */
189 struct GNUNET_IDENTITY_PublicKey identity;
190
191 /* followed by:
192 * serialized credential data
193 */
194};
195
196
197/**
198 * Start a attribute iteration for the given identity
199 */
200struct AttributeIterationStartMessage
201{
202 /**
203 * Message
204 */
205 struct GNUNET_MessageHeader header;
206
207 /**
208 * Unique identifier for this request (for key collisions).
209 */
210 uint32_t id GNUNET_PACKED;
211
212 /**
213 * Identity.
214 */
215 struct GNUNET_IDENTITY_PrivateKey identity;
216};
217
218
219/**
220 * Ask for next result of attribute iteration for the given operation
221 */
222struct AttributeIterationNextMessage
223{
224 /**
225 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT
226 */
227 struct GNUNET_MessageHeader header;
228
229 /**
230 * Unique identifier for this request (for key collisions).
231 */
232 uint32_t id GNUNET_PACKED;
233};
234
235
236/**
237 * Start a credential iteration for the given identity
238 */
239struct CredentialIterationStartMessage
240{
241 /**
242 * Message
243 */
244 struct GNUNET_MessageHeader header;
245
246 /**
247 * Unique identifier for this request (for key collisions).
248 */
249 uint32_t id GNUNET_PACKED;
250
251 /**
252 * Identity.
253 */
254 struct GNUNET_IDENTITY_PrivateKey identity;
255};
256
257
258/**
259 * Ask for next result of credential iteration for the given operation
260 */
261struct CredentialIterationNextMessage
262{
263 /**
264 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT
265 */
266 struct GNUNET_MessageHeader header;
267
268 /**
269 * Unique identifier for this request (for key collisions).
270 */
271 uint32_t id GNUNET_PACKED;
272};
273
274
275/**
276 * Stop credential iteration for the given operation
277 */
278struct CredentialIterationStopMessage
279{
280 /**
281 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP
282 */
283 struct GNUNET_MessageHeader header;
284
285 /**
286 * Unique identifier for this request (for key collisions).
287 */
288 uint32_t id GNUNET_PACKED;
289};
290
291
292/**
293 * Stop attribute iteration for the given operation
294 */
295struct AttributeIterationStopMessage
296{
297 /**
298 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP
299 */
300 struct GNUNET_MessageHeader header;
301
302 /**
303 * Unique identifier for this request (for key collisions).
304 */
305 uint32_t id GNUNET_PACKED;
306};
307
308/**
309 * Start a ticket iteration for the given identity
310 */
311struct TicketIterationStartMessage
312{
313 /**
314 * Message
315 */
316 struct GNUNET_MessageHeader header;
317
318 /**
319 * Unique identifier for this request (for key collisions).
320 */
321 uint32_t id GNUNET_PACKED;
322
323 /**
324 * Identity.
325 */
326 struct GNUNET_IDENTITY_PrivateKey identity;
327};
328
329
330/**
331 * Ask for next result of ticket iteration for the given operation
332 */
333struct TicketIterationNextMessage
334{
335 /**
336 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT
337 */
338 struct GNUNET_MessageHeader header;
339
340 /**
341 * Unique identifier for this request (for key collisions).
342 */
343 uint32_t id GNUNET_PACKED;
344};
345
346
347/**
348 * Stop ticket iteration for the given operation
349 */
350struct TicketIterationStopMessage
351{
352 /**
353 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP
354 */
355 struct GNUNET_MessageHeader header;
356
357 /**
358 * Unique identifier for this request (for key collisions).
359 */
360 uint32_t id GNUNET_PACKED;
361};
362
363
364/**
365 * Ticket issue message
366 */
367struct IssueTicketMessage
368{
369 /**
370 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET
371 */
372 struct GNUNET_MessageHeader header;
373
374 /**
375 * Unique identifier for this request (for key collisions).
376 */
377 uint32_t id GNUNET_PACKED;
378
379 /**
380 * Identity.
381 */
382 struct GNUNET_IDENTITY_PrivateKey identity;
383
384 /**
385 * Requesting party.
386 */
387 struct GNUNET_IDENTITY_PublicKey rp;
388
389 /**
390 * length of serialized attribute list
391 */
392 uint32_t attr_len GNUNET_PACKED;
393
394 // Followed by a serialized attribute list
395};
396
397/**
398 * Ticket revoke message
399 */
400struct RevokeTicketMessage
401{
402 /**
403 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET
404 */
405 struct GNUNET_MessageHeader header;
406
407 /**
408 * Unique identifier for this request (for key collisions).
409 */
410 uint32_t id GNUNET_PACKED;
411
412 /**
413 * Identity.
414 */
415 struct GNUNET_IDENTITY_PrivateKey identity;
416
417 /**
418 * length of serialized attribute list
419 */
420 uint32_t attrs_len GNUNET_PACKED;
421
422 /**
423 * The ticket to revoke
424 */
425 struct GNUNET_RECLAIM_Ticket ticket;
426};
427
428/**
429 * Ticket revoke message
430 */
431struct RevokeTicketResultMessage
432{
433 /**
434 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
435 */
436 struct GNUNET_MessageHeader header;
437
438 /**
439 * Unique identifier for this request (for key collisions).
440 */
441 uint32_t id GNUNET_PACKED;
442
443 /**
444 * Revocation result
445 */
446 uint32_t success GNUNET_PACKED;
447};
448
449
450/**
451 * Ticket result message
452 */
453struct TicketResultMessage
454{
455 /**
456 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
457 */
458 struct GNUNET_MessageHeader header;
459
460 /**
461 * Unique identifier for this request (for key collisions).
462 */
463 uint32_t id GNUNET_PACKED;
464
465 /**
466 * Length of new presentations created
467 */
468 uint32_t presentations_len GNUNET_PACKED;
469
470 /**
471 * The new ticket
472 */
473 struct GNUNET_RECLAIM_Ticket ticket;
474
475 /* Followed by the serialized GNUNET_RECLAIM_PresentationList */
476};
477
478/**
479 * Ticket consume message
480 */
481struct ConsumeTicketMessage
482{
483 /**
484 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET
485 */
486 struct GNUNET_MessageHeader header;
487
488 /**
489 * Unique identifier for this request (for key collisions).
490 */
491 uint32_t id GNUNET_PACKED;
492
493 /**
494 * Identity.
495 */
496 struct GNUNET_IDENTITY_PrivateKey identity;
497
498 /**
499 * The ticket to consume
500 */
501 struct GNUNET_RECLAIM_Ticket ticket;
502};
503
504/**
505 * Attribute list is returned from the idp.
506 */
507struct ConsumeTicketResultMessage
508{
509 /**
510 * Message header
511 */
512 struct GNUNET_MessageHeader header;
513
514 /**
515 * Unique identifier for this request (for key collisions).
516 */
517 uint32_t id GNUNET_PACKED;
518
519 /**
520 * Result
521 */
522 uint32_t result GNUNET_PACKED;
523
524 /**
525 * Length of serialized attribute data
526 */
527 uint16_t attrs_len GNUNET_PACKED;
528
529 /**
530 * Length of presentation data
531 */
532 uint16_t presentations_len;
533
534 /**
535 * always zero (for alignment)
536 */
537 uint16_t reserved GNUNET_PACKED;
538
539 /**
540 * The public key of the identity.
541 */
542 struct GNUNET_IDENTITY_PublicKey identity;
543
544 /* followed by:
545 * serialized attributes data
546 */
547};
548
549
550GNUNET_NETWORK_STRUCT_END
551
552#endif
diff --git a/src/reclaim/reclaim_api.c b/src/reclaim/reclaim_api.c
deleted file mode 100644
index f41473f9f..000000000
--- a/src/reclaim/reclaim_api.c
+++ /dev/null
@@ -1,1762 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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 reclaim/reclaim_api.c
23 * @brief api to interact with the reclaim service
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_mq_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_reclaim_lib.h"
32#include "gnunet_reclaim_service.h"
33#include "reclaim.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "reclaim-api", __VA_ARGS__)
36
37
38/**
39 * Handle for an operation with the service.
40 */
41struct GNUNET_RECLAIM_Operation
42{
43 /**
44 * Main handle.
45 */
46 struct GNUNET_RECLAIM_Handle *h;
47
48 /**
49 * We keep operations in a DLL.
50 */
51 struct GNUNET_RECLAIM_Operation *next;
52
53 /**
54 * We keep operations in a DLL.
55 */
56 struct GNUNET_RECLAIM_Operation *prev;
57
58 /**
59 * Message to send to the service.
60 * Allocated at the end of this struct.
61 */
62 const struct GNUNET_MessageHeader *msg;
63
64 /**
65 * Continuation to invoke after attribute store call
66 */
67 GNUNET_RECLAIM_ContinuationWithStatus as_cb;
68
69 /**
70 * Attribute result callback
71 */
72 GNUNET_RECLAIM_AttributeResult ar_cb;
73
74 /**
75 * Attribute result callback
76 */
77 GNUNET_RECLAIM_AttributeTicketResult atr_cb;
78
79 /**
80 * Credential result callback
81 */
82 GNUNET_RECLAIM_CredentialResult at_cb;
83
84 /**
85 * Revocation result callback
86 */
87 GNUNET_RECLAIM_ContinuationWithStatus rvk_cb;
88
89 /**
90 * Ticket result callback
91 */
92 GNUNET_RECLAIM_TicketCallback tr_cb;
93
94 /**
95 * Ticket issue result callback
96 */
97 GNUNET_RECLAIM_IssueTicketCallback ti_cb;
98
99 /**
100 * Envelope with the message for this queue entry.
101 */
102 struct GNUNET_MQ_Envelope *env;
103
104 /**
105 * request id
106 */
107 uint32_t r_id;
108
109 /**
110 * Closure for @e cont or @e cb.
111 */
112 void *cls;
113};
114
115
116/**
117 * Handle for a ticket iterator operation
118 */
119struct GNUNET_RECLAIM_TicketIterator
120{
121 /**
122 * Kept in a DLL.
123 */
124 struct GNUNET_RECLAIM_TicketIterator *next;
125
126 /**
127 * Kept in a DLL.
128 */
129 struct GNUNET_RECLAIM_TicketIterator *prev;
130
131 /**
132 * Main handle to access the idp.
133 */
134 struct GNUNET_RECLAIM_Handle *h;
135
136 /**
137 * Function to call on completion.
138 */
139 GNUNET_SCHEDULER_TaskCallback finish_cb;
140
141 /**
142 * Closure for @e finish_cb.
143 */
144 void *finish_cb_cls;
145
146 /**
147 * The continuation to call with the results
148 */
149 GNUNET_RECLAIM_TicketCallback tr_cb;
150
151 /**
152 * Closure for @e tr_cb.
153 */
154 void *cls;
155
156 /**
157 * Function to call on errors.
158 */
159 GNUNET_SCHEDULER_TaskCallback error_cb;
160
161 /**
162 * Closure for @e error_cb.
163 */
164 void *error_cb_cls;
165
166 /**
167 * Envelope of the message to send to the service, if not yet
168 * sent.
169 */
170 struct GNUNET_MQ_Envelope *env;
171
172 /**
173 * The operation id this zone iteration operation has
174 */
175 uint32_t r_id;
176};
177
178
179/**
180 * Handle for a attribute iterator operation
181 */
182struct GNUNET_RECLAIM_AttributeIterator
183{
184 /**
185 * Kept in a DLL.
186 */
187 struct GNUNET_RECLAIM_AttributeIterator *next;
188
189 /**
190 * Kept in a DLL.
191 */
192 struct GNUNET_RECLAIM_AttributeIterator *prev;
193
194 /**
195 * Main handle to access the service.
196 */
197 struct GNUNET_RECLAIM_Handle *h;
198
199 /**
200 * Function to call on completion.
201 */
202 GNUNET_SCHEDULER_TaskCallback finish_cb;
203
204 /**
205 * Closure for @e finish_cb.
206 */
207 void *finish_cb_cls;
208
209 /**
210 * The continuation to call with the results
211 */
212 GNUNET_RECLAIM_AttributeResult proc;
213
214 /**
215 * Closure for @e proc.
216 */
217 void *proc_cls;
218
219 /**
220 * Function to call on errors.
221 */
222 GNUNET_SCHEDULER_TaskCallback error_cb;
223
224 /**
225 * Closure for @e error_cb.
226 */
227 void *error_cb_cls;
228
229 /**
230 * Envelope of the message to send to the service, if not yet
231 * sent.
232 */
233 struct GNUNET_MQ_Envelope *env;
234
235 /**
236 * Private key of the zone.
237 */
238 struct GNUNET_IDENTITY_PrivateKey identity;
239
240 /**
241 * The operation id this zone iteration operation has
242 */
243 uint32_t r_id;
244};
245
246/**
247 * Handle for a credential iterator operation
248 */
249struct GNUNET_RECLAIM_CredentialIterator
250{
251 /**
252 * Kept in a DLL.
253 */
254 struct GNUNET_RECLAIM_CredentialIterator *next;
255
256 /**
257 * Kept in a DLL.
258 */
259 struct GNUNET_RECLAIM_CredentialIterator *prev;
260
261 /**
262 * Main handle to access the service.
263 */
264 struct GNUNET_RECLAIM_Handle *h;
265
266 /**
267 * Function to call on completion.
268 */
269 GNUNET_SCHEDULER_TaskCallback finish_cb;
270
271 /**
272 * Closure for @e finish_cb.
273 */
274 void *finish_cb_cls;
275
276 /**
277 * The continuation to call with the results
278 */
279 GNUNET_RECLAIM_CredentialResult proc;
280
281 /**
282 * Closure for @e proc.
283 */
284 void *proc_cls;
285
286 /**
287 * Function to call on errors.
288 */
289 GNUNET_SCHEDULER_TaskCallback error_cb;
290
291 /**
292 * Closure for @e error_cb.
293 */
294 void *error_cb_cls;
295
296 /**
297 * Envelope of the message to send to the service, if not yet
298 * sent.
299 */
300 struct GNUNET_MQ_Envelope *env;
301
302 /**
303 * Private key of the zone.
304 */
305 struct GNUNET_IDENTITY_PrivateKey identity;
306
307 /**
308 * The operation id this zone iteration operation has
309 */
310 uint32_t r_id;
311};
312
313
314/**
315 * Handle to the service.
316 */
317struct GNUNET_RECLAIM_Handle
318{
319 /**
320 * Configuration to use.
321 */
322 const struct GNUNET_CONFIGURATION_Handle *cfg;
323
324 /**
325 * Socket (if available).
326 */
327 struct GNUNET_CLIENT_Connection *client;
328
329 /**
330 * Closure for 'cb'.
331 */
332 void *cb_cls;
333
334 /**
335 * Head of active operations.
336 */
337 struct GNUNET_RECLAIM_Operation *op_head;
338
339 /**
340 * Tail of active operations.
341 */
342 struct GNUNET_RECLAIM_Operation *op_tail;
343
344 /**
345 * Head of active iterations
346 */
347 struct GNUNET_RECLAIM_AttributeIterator *it_head;
348
349 /**
350 * Tail of active iterations
351 */
352 struct GNUNET_RECLAIM_AttributeIterator *it_tail;
353
354 /**
355 * Head of active iterations
356 */
357 struct GNUNET_RECLAIM_CredentialIterator *ait_head;
358
359 /**
360 * Tail of active iterations
361 */
362 struct GNUNET_RECLAIM_CredentialIterator *ait_tail;
363
364 /**
365 * Head of active iterations
366 */
367 struct GNUNET_RECLAIM_TicketIterator *ticket_it_head;
368
369 /**
370 * Tail of active iterations
371 */
372 struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail;
373
374 /**
375 * Currently pending transmission request, or NULL for none.
376 */
377 struct GNUNET_CLIENT_TransmitHandle *th;
378
379 /**
380 * Task doing exponential back-off trying to reconnect.
381 */
382 struct GNUNET_SCHEDULER_Task *reconnect_task;
383
384 /**
385 * Time for next connect retry.
386 */
387 struct GNUNET_TIME_Relative reconnect_backoff;
388
389 /**
390 * Connection to service (if available).
391 */
392 struct GNUNET_MQ_Handle *mq;
393
394 /**
395 * Request Id generator. Incremented by one for each request.
396 */
397 uint32_t r_id_gen;
398
399 /**
400 * Are we polling for incoming messages right now?
401 */
402 int in_receive;
403};
404
405
406/**
407 * Try again to connect to the service.
408 *
409 * @param h handle to the reclaim service.
410 */
411static void
412reconnect (struct GNUNET_RECLAIM_Handle *h);
413
414
415/**
416 * Reconnect
417 *
418 * @param cls the handle
419 */
420static void
421reconnect_task (void *cls)
422{
423 struct GNUNET_RECLAIM_Handle *handle = cls;
424
425 handle->reconnect_task = NULL;
426 reconnect (handle);
427}
428
429
430/**
431 * Disconnect from service and then reconnect.
432 *
433 * @param handle our service
434 */
435static void
436force_reconnect (struct GNUNET_RECLAIM_Handle *handle)
437{
438 GNUNET_MQ_destroy (handle->mq);
439 handle->mq = NULL;
440 handle->reconnect_backoff =
441 GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
442 handle->reconnect_task =
443 GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
444 &reconnect_task,
445 handle);
446}
447
448
449/**
450 * Free @a it.
451 *
452 * @param it entry to free
453 */
454static void
455free_it (struct GNUNET_RECLAIM_AttributeIterator *it)
456{
457 struct GNUNET_RECLAIM_Handle *h = it->h;
458
459 GNUNET_CONTAINER_DLL_remove (h->it_head, h->it_tail, it);
460 if (NULL != it->env)
461 GNUNET_MQ_discard (it->env);
462 GNUNET_free (it);
463}
464
465
466/**
467 * Free @a it.
468 *
469 * @param ait entry to free
470 */
471static void
472free_ait (struct GNUNET_RECLAIM_CredentialIterator *ait)
473{
474 struct GNUNET_RECLAIM_Handle *h = ait->h;
475
476 GNUNET_CONTAINER_DLL_remove (h->ait_head, h->ait_tail, ait);
477 if (NULL != ait->env)
478 GNUNET_MQ_discard (ait->env);
479 GNUNET_free (ait);
480}
481
482
483/**
484 * Free @a op
485 *
486 * @param op the operation to free
487 */
488static void
489free_op (struct GNUNET_RECLAIM_Operation *op)
490{
491 if (NULL == op)
492 return;
493 if (NULL != op->env)
494 GNUNET_MQ_discard (op->env);
495 GNUNET_free (op);
496}
497
498
499/**
500 * Generic error handler, called with the appropriate error code and
501 * the same closure specified at the creation of the message queue.
502 * Not every message queue implementation supports an error handler.
503 *
504 * @param cls closure with the `struct GNUNET_GNS_Handle *`
505 * @param error error code
506 */
507static void
508mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
509{
510 struct GNUNET_RECLAIM_Handle *handle = cls;
511
512 force_reconnect (handle);
513}
514
515
516/**
517 * Handle an incoming message of type
518 * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE
519 *
520 * @param cls
521 * @param msg the message we received
522 */
523static void
524handle_success_response (void *cls, const struct SuccessResultMessage *msg)
525{
526 struct GNUNET_RECLAIM_Handle *h = cls;
527 struct GNUNET_RECLAIM_Operation *op;
528 uint32_t r_id = ntohl (msg->id);
529 int res;
530 const char *emsg;
531
532 for (op = h->op_head; NULL != op; op = op->next)
533 if (op->r_id == r_id)
534 break;
535 if (NULL == op)
536 return;
537
538 res = ntohl (msg->op_result);
539 LOG (GNUNET_ERROR_TYPE_DEBUG,
540 "Received SUCCESS_RESPONSE with result %d\n",
541 res);
542
543 /* TODO: add actual error message to response... */
544 if (GNUNET_SYSERR == res)
545 emsg = _ ("failed to store record\n");
546 else
547 emsg = NULL;
548 if (NULL != op->as_cb)
549 op->as_cb (op->cls, res, emsg);
550 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
551 free_op (op);
552}
553
554
555/**
556 * Handle an incoming message of type
557 * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
558 *
559 * @param cls
560 * @param msg the message we received
561 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
562 */
563static int
564check_consume_ticket_result (void *cls,
565 const struct ConsumeTicketResultMessage *msg)
566{
567 size_t msg_len;
568 size_t attrs_len;
569 size_t pl_len;
570
571 msg_len = ntohs (msg->header.size);
572 attrs_len = ntohs (msg->attrs_len);
573 pl_len = ntohs (msg->presentations_len);
574 if (msg_len !=
575 sizeof(struct ConsumeTicketResultMessage) + attrs_len + pl_len)
576 {
577 GNUNET_break (0);
578 return GNUNET_SYSERR;
579 }
580 return GNUNET_OK;
581}
582
583
584/**
585 * Handle an incoming message of type
586 * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
587 *
588 * @param cls
589 * @param msg the message we received
590 */
591static void
592handle_consume_ticket_result (void *cls,
593 const struct ConsumeTicketResultMessage *msg)
594{
595 struct GNUNET_RECLAIM_Handle *h = cls;
596 struct GNUNET_RECLAIM_Operation *op;
597 size_t attrs_len;
598 size_t pl_len;
599 uint32_t r_id = ntohl (msg->id);
600 char *read_ptr;
601
602 attrs_len = ntohs (msg->attrs_len);
603 pl_len = ntohs (msg->presentations_len);
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing ticket result.\n");
605
606
607 for (op = h->op_head; NULL != op; op = op->next)
608 if (op->r_id == r_id)
609 break;
610 if (NULL == op)
611 return;
612
613 {
614 struct GNUNET_RECLAIM_AttributeList *attrs;
615 struct GNUNET_RECLAIM_AttributeListEntry *le;
616 struct GNUNET_RECLAIM_PresentationList *pl;
617 struct GNUNET_RECLAIM_PresentationListEntry *ple;
618 attrs =
619 GNUNET_RECLAIM_attribute_list_deserialize ((char *) &msg[1], attrs_len);
620 read_ptr = ((char *) &msg[1]) + attrs_len;
621 pl = GNUNET_RECLAIM_presentation_list_deserialize (read_ptr, pl_len);
622 if (NULL != op->atr_cb)
623 {
624 if (NULL == attrs)
625 {
626 op->atr_cb (op->cls, &msg->identity, NULL, NULL);
627 }
628 else
629 {
630 for (le = attrs->list_head; NULL != le; le = le->next)
631 {
632 if (GNUNET_NO ==
633 GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
634 {
635 for (ple = pl->list_head; NULL != ple; ple = ple->next)
636 {
637 if (GNUNET_YES ==
638 GNUNET_RECLAIM_id_is_equal (&le->attribute->credential,
639 &ple->presentation->credential_id))
640 {
641 op->atr_cb (op->cls, &msg->identity,
642 le->attribute, ple->presentation);
643 break;
644 }
645
646 }
647 }
648 else // No credentials
649 {
650 op->atr_cb (op->cls, &msg->identity,
651 le->attribute, NULL);
652 }
653 }
654 }
655 op->atr_cb (op->cls, NULL, NULL, NULL);
656 }
657 if (NULL != attrs)
658 GNUNET_RECLAIM_attribute_list_destroy (attrs);
659 if (NULL != pl)
660 GNUNET_RECLAIM_presentation_list_destroy (pl);
661 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
662 free_op (op);
663 return;
664 }
665 GNUNET_assert (0);
666}
667
668
669/**
670 * Handle an incoming message of type
671 * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
672 *
673 * @param cls
674 * @param msg the message we received
675 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
676 */
677static int
678check_attribute_result (void *cls, const struct AttributeResultMessage *msg)
679{
680 size_t msg_len;
681 size_t attr_len;
682
683 msg_len = ntohs (msg->header.size);
684 attr_len = ntohs (msg->attr_len);
685 if (msg_len != sizeof(struct AttributeResultMessage) + attr_len)
686 {
687 GNUNET_break (0);
688 return GNUNET_SYSERR;
689 }
690 return GNUNET_OK;
691}
692
693
694/**
695 * Handle an incoming message of type
696 * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
697 *
698 * @param cls
699 * @param msg the message we received
700 */
701static void
702handle_attribute_result (void *cls, const struct AttributeResultMessage *msg)
703{
704 static struct GNUNET_IDENTITY_PrivateKey identity_dummy;
705 struct GNUNET_RECLAIM_Handle *h = cls;
706 struct GNUNET_RECLAIM_AttributeIterator *it;
707 struct GNUNET_RECLAIM_Operation *op;
708 size_t attr_len;
709 uint32_t r_id = ntohl (msg->id);
710
711 attr_len = ntohs (msg->attr_len);
712 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
713
714
715 for (it = h->it_head; NULL != it; it = it->next)
716 if (it->r_id == r_id)
717 break;
718 for (op = h->op_head; NULL != op; op = op->next)
719 if (op->r_id == r_id)
720 break;
721 if ((NULL == it) && (NULL == op))
722 return;
723
724 if ((0 ==
725 (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
726 {
727 if ((NULL == it) && (NULL == op))
728 {
729 GNUNET_break (0);
730 force_reconnect (h);
731 return;
732 }
733 if (NULL != it)
734 {
735 if (NULL != it->finish_cb)
736 it->finish_cb (it->finish_cb_cls);
737 free_it (it);
738 }
739 if (NULL != op)
740 {
741 if (NULL != op->ar_cb)
742 op->ar_cb (op->cls, NULL, NULL);
743 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
744 free_op (op);
745 }
746 return;
747 }
748
749 {
750 struct GNUNET_RECLAIM_Attribute *attr;
751 GNUNET_RECLAIM_attribute_deserialize ((char *) &msg[1], attr_len,
752 &attr);
753 if (NULL != it)
754 {
755 if (NULL != it->proc)
756 it->proc (it->proc_cls, &msg->identity, attr);
757 }
758 else if (NULL != op)
759 {
760 if (NULL != op->ar_cb)
761 op->ar_cb (op->cls, &msg->identity, attr);
762 }
763 GNUNET_free (attr);
764 return;
765 }
766 GNUNET_assert (0);
767}
768
769
770/**
771 * Handle an incoming message of type
772 * #GNUNET_MESSAGE_TYPE_RECLAIM_credential_RESULT
773 *
774 * @param cls
775 * @param msg the message we received
776 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
777 */
778static int
779check_credential_result (void *cls, const struct CredentialResultMessage *msg)
780{
781 size_t msg_len;
782 size_t cred_len;
783
784 msg_len = ntohs (msg->header.size);
785 cred_len = ntohs (msg->credential_len);
786 if (msg_len != sizeof(struct CredentialResultMessage) + cred_len)
787 {
788 GNUNET_break (0);
789 return GNUNET_SYSERR;
790 }
791 return GNUNET_OK;
792}
793
794
795/**
796 * Handle an incoming message of type
797 * #GNUNET_MESSAGE_TYPE_RECLAIM_credential_RESULT
798 *
799 * @param cls
800 * @param msg the message we received
801 */
802static void
803handle_credential_result (void *cls, const struct
804 CredentialResultMessage *msg)
805{
806 static struct GNUNET_IDENTITY_PrivateKey identity_dummy;
807 struct GNUNET_RECLAIM_Handle *h = cls;
808 struct GNUNET_RECLAIM_CredentialIterator *it;
809 struct GNUNET_RECLAIM_Operation *op;
810 size_t att_len;
811 uint32_t r_id = ntohl (msg->id);
812
813 att_len = ntohs (msg->credential_len);
814 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing credential result.\n");
815
816
817 for (it = h->ait_head; NULL != it; it = it->next)
818 if (it->r_id == r_id)
819 break;
820 for (op = h->op_head; NULL != op; op = op->next)
821 if (op->r_id == r_id)
822 break;
823 if ((NULL == it) && (NULL == op))
824 return;
825
826 if ((0 ==
827 (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
828 {
829 if ((NULL == it) && (NULL == op))
830 {
831 GNUNET_break (0);
832 force_reconnect (h);
833 return;
834 }
835 if (NULL != it)
836 {
837 if (NULL != it->finish_cb)
838 it->finish_cb (it->finish_cb_cls);
839 free_ait (it);
840 }
841 if (NULL != op)
842 {
843 if (NULL != op->at_cb)
844 op->at_cb (op->cls, NULL, NULL);
845 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
846 free_op (op);
847 }
848 return;
849 }
850
851 {
852 struct GNUNET_RECLAIM_Credential *att;
853 att = GNUNET_RECLAIM_credential_deserialize ((char *) &msg[1], att_len);
854
855 if (NULL != it)
856 {
857 if (NULL != it->proc)
858 it->proc (it->proc_cls, &msg->identity, att);
859 }
860 else if (NULL != op)
861 {
862 if (NULL != op->at_cb)
863 op->at_cb (op->cls, &msg->identity, att);
864 }
865 GNUNET_free (att);
866 return;
867 }
868 GNUNET_assert (0);
869}
870
871
872/**
873 * Handle an incoming message of type
874 * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
875 *
876 * @param cls
877 * @param msg the message we received
878 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
879 */
880static int
881check_ticket_result (void *cls, const struct TicketResultMessage *msg)
882{
883 size_t msg_len;
884 size_t pres_len;
885
886 msg_len = ntohs (msg->header.size);
887 pres_len = ntohs (msg->presentations_len);
888 if (msg_len != sizeof(struct TicketResultMessage) + pres_len)
889 {
890 GNUNET_break (0);
891 return GNUNET_SYSERR;
892 }
893 return GNUNET_OK;
894}
895
896
897/**
898 * Handle an incoming message of type
899 * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
900 *
901 * @param cls
902 * @param msg the message we received
903 */
904static void
905handle_ticket_result (void *cls, const struct TicketResultMessage *msg)
906{
907 struct GNUNET_RECLAIM_Handle *handle = cls;
908 struct GNUNET_RECLAIM_Operation *op;
909 struct GNUNET_RECLAIM_TicketIterator *it;
910 struct GNUNET_RECLAIM_PresentationList *presentation;
911 uint32_t r_id = ntohl (msg->id);
912 static const struct GNUNET_RECLAIM_Ticket ticket;
913 uint32_t pres_len = ntohs (msg->presentations_len);
914
915 for (op = handle->op_head; NULL != op; op = op->next)
916 if (op->r_id == r_id)
917 break;
918 for (it = handle->ticket_it_head; NULL != it; it = it->next)
919 if (it->r_id == r_id)
920 break;
921 if ((NULL == op) && (NULL == it))
922 return;
923 if (NULL != op)
924 {
925 if (0 < pres_len)
926 presentation = GNUNET_RECLAIM_presentation_list_deserialize (
927 (char*) &msg[1],
928 pres_len);
929 GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op);
930 if (0 ==
931 memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
932 {
933 if (NULL != op->ti_cb)
934 op->ti_cb (op->cls, NULL, NULL);
935 }
936 else
937 {
938 if (NULL != op->ti_cb)
939 op->ti_cb (op->cls,
940 &msg->ticket,
941 (0 < pres_len) ? presentation : NULL);
942 }
943 if (0 < pres_len)
944 GNUNET_RECLAIM_presentation_list_destroy (presentation);
945 free_op (op);
946 return;
947 }
948 else if (NULL != it)
949 {
950 if (0 ==
951 memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
952 {
953 GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
954 handle->ticket_it_tail,
955 it);
956 it->finish_cb (it->finish_cb_cls);
957 GNUNET_free (it);
958 }
959 else
960 {
961 if (NULL != it->tr_cb)
962 it->tr_cb (it->cls, &msg->ticket);
963 }
964 return;
965 }
966 GNUNET_break (0);
967}
968
969
970/**
971 * Handle an incoming message of type
972 * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
973 *
974 * @param cls
975 * @param msg the message we received
976 */
977static void
978handle_revoke_ticket_result (void *cls,
979 const struct RevokeTicketResultMessage *msg)
980{
981 struct GNUNET_RECLAIM_Handle *h = cls;
982 struct GNUNET_RECLAIM_Operation *op;
983 uint32_t r_id = ntohl (msg->id);
984 int32_t success;
985
986 LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n");
987
988
989 for (op = h->op_head; NULL != op; op = op->next)
990 if (op->r_id == r_id)
991 break;
992 if (NULL == op)
993 return;
994 success = ntohl (msg->success);
995 {
996 if (NULL != op->rvk_cb)
997 {
998 op->rvk_cb (op->cls, success, NULL);
999 }
1000 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
1001 free_op (op);
1002 return;
1003 }
1004 GNUNET_assert (0);
1005}
1006
1007
1008/**
1009 * Try again to connect to the service.
1010 *
1011 * @param h handle to the reclaim service.
1012 */
1013static void
1014reconnect (struct GNUNET_RECLAIM_Handle *h)
1015{
1016 struct GNUNET_MQ_MessageHandler handlers[] =
1017 { GNUNET_MQ_hd_fixed_size (success_response,
1018 GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
1019 struct SuccessResultMessage,
1020 h),
1021 GNUNET_MQ_hd_var_size (attribute_result,
1022 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
1023 struct AttributeResultMessage,
1024 h),
1025 GNUNET_MQ_hd_var_size (credential_result,
1026 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_RESULT,
1027 struct CredentialResultMessage,
1028 h),
1029 GNUNET_MQ_hd_var_size (ticket_result,
1030 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
1031 struct TicketResultMessage,
1032 h),
1033 GNUNET_MQ_hd_var_size (consume_ticket_result,
1034 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
1035 struct ConsumeTicketResultMessage,
1036 h),
1037 GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
1038 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
1039 struct RevokeTicketResultMessage,
1040 h),
1041 GNUNET_MQ_handler_end () };
1042 struct GNUNET_RECLAIM_Operation *op;
1043
1044 GNUNET_assert (NULL == h->mq);
1045 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
1046
1047 h->mq =
1048 GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
1049 if (NULL == h->mq)
1050 return;
1051 for (op = h->op_head; NULL != op; op = op->next)
1052 GNUNET_MQ_send_copy (h->mq, op->env);
1053}
1054
1055
1056/**
1057 * Connect to the reclaim service.
1058 *
1059 * @param cfg the configuration to use
1060 * @return handle to use
1061 */
1062struct GNUNET_RECLAIM_Handle *
1063GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
1064{
1065 struct GNUNET_RECLAIM_Handle *h;
1066
1067 h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
1068 h->cfg = cfg;
1069 reconnect (h);
1070 if (NULL == h->mq)
1071 {
1072 GNUNET_free (h);
1073 return NULL;
1074 }
1075 return h;
1076}
1077
1078
1079/**
1080 * Cancel an operation. Note that the operation MAY still
1081 * be executed; this merely cancels the continuation; if the request
1082 * was already transmitted, the service may still choose to complete
1083 * the operation.
1084 *
1085 * @param op operation to cancel
1086 */
1087void
1088GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
1089{
1090 struct GNUNET_RECLAIM_Handle *h = op->h;
1091
1092 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
1093 free_op (op);
1094}
1095
1096
1097/**
1098 * Disconnect from service
1099 *
1100 * @param h handle to destroy
1101 */
1102void
1103GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
1104{
1105 GNUNET_assert (NULL != h);
1106 if (NULL != h->mq)
1107 {
1108 GNUNET_MQ_destroy (h->mq);
1109 h->mq = NULL;
1110 }
1111 if (NULL != h->reconnect_task)
1112 {
1113 GNUNET_SCHEDULER_cancel (h->reconnect_task);
1114 h->reconnect_task = NULL;
1115 }
1116 GNUNET_assert (NULL == h->op_head);
1117 GNUNET_free (h);
1118}
1119
1120
1121/**
1122 * Store an attribute. If the attribute is already present,
1123 * it is replaced with the new attribute.
1124 *
1125 * @param h handle to the re:claimID service
1126 * @param pkey private key of the identity
1127 * @param attr the attribute value
1128 * @param exp_interval the relative expiration interval for the attribute
1129 * @param cont continuation to call when done
1130 * @param cont_cls closure for @a cont
1131 * @return handle to abort the request
1132 */
1133struct GNUNET_RECLAIM_Operation *
1134GNUNET_RECLAIM_attribute_store (
1135 struct GNUNET_RECLAIM_Handle *h,
1136 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1137 const struct GNUNET_RECLAIM_Attribute *attr,
1138 const struct GNUNET_TIME_Relative *exp_interval,
1139 GNUNET_RECLAIM_ContinuationWithStatus cont,
1140 void *cont_cls)
1141{
1142 struct GNUNET_RECLAIM_Operation *op;
1143 struct AttributeStoreMessage *sam;
1144 size_t attr_len;
1145
1146 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1147 op->h = h;
1148 op->as_cb = cont;
1149 op->cls = cont_cls;
1150 op->r_id = h->r_id_gen++;
1151 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1152 attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr);
1153 op->env = GNUNET_MQ_msg_extra (sam,
1154 attr_len,
1155 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
1156 sam->identity = *pkey;
1157 sam->id = htonl (op->r_id);
1158 sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1159
1160 GNUNET_RECLAIM_attribute_serialize (attr, (char *) &sam[1]);
1161
1162 sam->attr_len = htons (attr_len);
1163 if (NULL != h->mq)
1164 GNUNET_MQ_send_copy (h->mq, op->env);
1165 return op;
1166}
1167
1168
1169/**
1170 * Delete an attribute. Tickets used to share this attribute are updated
1171 * accordingly.
1172 *
1173 * @param h handle to the re:claimID service
1174 * @param pkey Private key of the identity to add an attribute to
1175 * @param attr The attribute
1176 * @param cont Continuation to call when done
1177 * @param cont_cls Closure for @a cont
1178 * @return handle Used to to abort the request
1179 */
1180struct GNUNET_RECLAIM_Operation *
1181GNUNET_RECLAIM_attribute_delete (
1182 struct GNUNET_RECLAIM_Handle *h,
1183 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1184 const struct GNUNET_RECLAIM_Attribute *attr,
1185 GNUNET_RECLAIM_ContinuationWithStatus cont,
1186 void *cont_cls)
1187{
1188 struct GNUNET_RECLAIM_Operation *op;
1189 struct AttributeDeleteMessage *dam;
1190 size_t attr_len;
1191
1192 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1193 op->h = h;
1194 op->as_cb = cont;
1195 op->cls = cont_cls;
1196 op->r_id = h->r_id_gen++;
1197 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1198 attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr);
1199 op->env = GNUNET_MQ_msg_extra (dam,
1200 attr_len,
1201 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
1202 dam->identity = *pkey;
1203 dam->id = htonl (op->r_id);
1204 GNUNET_RECLAIM_attribute_serialize (attr, (char *) &dam[1]);
1205
1206 dam->attr_len = htons (attr_len);
1207 if (NULL != h->mq)
1208 GNUNET_MQ_send_copy (h->mq, op->env);
1209 return op;
1210}
1211
1212
1213/**
1214 * Store an credential. If the credential is already present,
1215 * it is replaced with the new credential.
1216 *
1217 * @param h handle to the re:claimID service
1218 * @param pkey private key of the identity
1219 * @param attr the credential value
1220 * @param exp_interval the relative expiration interval for the credential
1221 * @param cont continuation to call when done
1222 * @param cont_cls closure for @a cont
1223 * @return handle to abort the request
1224 */
1225struct GNUNET_RECLAIM_Operation *
1226GNUNET_RECLAIM_credential_store (
1227 struct GNUNET_RECLAIM_Handle *h,
1228 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1229 const struct GNUNET_RECLAIM_Credential *attr,
1230 const struct GNUNET_TIME_Relative *exp_interval,
1231 GNUNET_RECLAIM_ContinuationWithStatus cont,
1232 void *cont_cls)
1233{
1234 struct GNUNET_RECLAIM_Operation *op;
1235 struct AttributeStoreMessage *sam;
1236 size_t attr_len;
1237
1238 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1239 op->h = h;
1240 op->as_cb = cont;
1241 op->cls = cont_cls;
1242 op->r_id = h->r_id_gen++;
1243 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1244 attr_len = GNUNET_RECLAIM_credential_serialize_get_size (attr);
1245 op->env = GNUNET_MQ_msg_extra (sam,
1246 attr_len,
1247 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_STORE);
1248 sam->identity = *pkey;
1249 sam->id = htonl (op->r_id);
1250 sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1251
1252 GNUNET_RECLAIM_credential_serialize (attr, (char *) &sam[1]);
1253
1254 sam->attr_len = htons (attr_len);
1255 if (NULL != h->mq)
1256 GNUNET_MQ_send_copy (h->mq, op->env);
1257 return op;
1258}
1259
1260
1261/**
1262 * Delete an credential. Tickets used to share this credential are updated
1263 * accordingly.
1264 *
1265 * @param h handle to the re:claimID service
1266 * @param pkey Private key of the identity to add an attribute to
1267 * @param attr The credential
1268 * @param cont Continuation to call when done
1269 * @param cont_cls Closure for @a cont
1270 * @return handle Used to to abort the request
1271 */
1272struct GNUNET_RECLAIM_Operation *
1273GNUNET_RECLAIM_credential_delete (
1274 struct GNUNET_RECLAIM_Handle *h,
1275 const struct GNUNET_IDENTITY_PrivateKey *pkey,
1276 const struct GNUNET_RECLAIM_Credential *attr,
1277 GNUNET_RECLAIM_ContinuationWithStatus cont,
1278 void *cont_cls)
1279{
1280 struct GNUNET_RECLAIM_Operation *op;
1281 struct AttributeDeleteMessage *dam;
1282 size_t attr_len;
1283
1284 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1285 op->h = h;
1286 op->as_cb = cont;
1287 op->cls = cont_cls;
1288 op->r_id = h->r_id_gen++;
1289 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1290 attr_len = GNUNET_RECLAIM_credential_serialize_get_size (attr);
1291 op->env = GNUNET_MQ_msg_extra (dam,
1292 attr_len,
1293 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_DELETE);
1294 dam->identity = *pkey;
1295 dam->id = htonl (op->r_id);
1296 GNUNET_RECLAIM_credential_serialize (attr, (char *) &dam[1]);
1297
1298 dam->attr_len = htons (attr_len);
1299 if (NULL != h->mq)
1300 GNUNET_MQ_send_copy (h->mq, op->env);
1301 return op;
1302}
1303
1304
1305/**
1306 * List all attributes for a local identity.
1307 * This MUST lock the `struct GNUNET_RECLAIM_Handle`
1308 * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
1309 * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
1310 * immediately, and then again after
1311 * #GNUNET_RECLAIM_get_attributes_next() is invoked.
1312 *
1313 * On error (disconnect), @a error_cb will be invoked.
1314 * On normal completion, @a finish_cb proc will be
1315 * invoked.
1316 *
1317 * @param h Handle to the re:claimID service
1318 * @param identity Identity to iterate over
1319 * @param error_cb Function to call on error (i.e. disconnect),
1320 * the handle is afterwards invalid
1321 * @param error_cb_cls Closure for @a error_cb
1322 * @param proc Function to call on each attribute
1323 * @param proc_cls Closure for @a proc
1324 * @param finish_cb Function to call on completion
1325 * the handle is afterwards invalid
1326 * @param finish_cb_cls Closure for @a finish_cb
1327 * @return an iterator Handle to use for iteration
1328 */
1329struct GNUNET_RECLAIM_AttributeIterator *
1330GNUNET_RECLAIM_get_attributes_start (
1331 struct GNUNET_RECLAIM_Handle *h,
1332 const struct GNUNET_IDENTITY_PrivateKey *identity,
1333 GNUNET_SCHEDULER_TaskCallback error_cb,
1334 void *error_cb_cls,
1335 GNUNET_RECLAIM_AttributeResult proc,
1336 void *proc_cls,
1337 GNUNET_SCHEDULER_TaskCallback finish_cb,
1338 void *finish_cb_cls)
1339{
1340 struct GNUNET_RECLAIM_AttributeIterator *it;
1341 struct GNUNET_MQ_Envelope *env;
1342 struct AttributeIterationStartMessage *msg;
1343 uint32_t rid;
1344
1345 rid = h->r_id_gen++;
1346 it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
1347 it->h = h;
1348 it->error_cb = error_cb;
1349 it->error_cb_cls = error_cb_cls;
1350 it->finish_cb = finish_cb;
1351 it->finish_cb_cls = finish_cb_cls;
1352 it->proc = proc;
1353 it->proc_cls = proc_cls;
1354 it->r_id = rid;
1355 it->identity = *identity;
1356 GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
1357 env =
1358 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
1359 msg->id = htonl (rid);
1360 msg->identity = *identity;
1361 if (NULL == h->mq)
1362 it->env = env;
1363 else
1364 GNUNET_MQ_send (h->mq, env);
1365 return it;
1366}
1367
1368
1369/**
1370 * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
1371 * for the next record.
1372 *
1373 * @param it the iterator
1374 */
1375void
1376GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
1377{
1378 struct GNUNET_RECLAIM_Handle *h = it->h;
1379 struct AttributeIterationNextMessage *msg;
1380 struct GNUNET_MQ_Envelope *env;
1381
1382 env =
1383 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
1384 msg->id = htonl (it->r_id);
1385 GNUNET_MQ_send (h->mq, env);
1386}
1387
1388
1389/**
1390 * Stops iteration and releases the handle for further calls. Must
1391 * be called on any iteration that has not yet completed prior to calling
1392 * #GNUNET_RECLAIM_disconnect.
1393 *
1394 * @param it the iterator
1395 */
1396void
1397GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1398{
1399 struct GNUNET_RECLAIM_Handle *h = it->h;
1400 struct GNUNET_MQ_Envelope *env;
1401 struct AttributeIterationStopMessage *msg;
1402
1403 if (NULL != h->mq)
1404 {
1405 env =
1406 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1407 msg->id = htonl (it->r_id);
1408 GNUNET_MQ_send (h->mq, env);
1409 }
1410 free_it (it);
1411}
1412
1413
1414/**
1415 * List all credentials for a local identity.
1416 * This MUST lock the `struct GNUNET_RECLAIM_Handle`
1417 * for any other calls than #GNUNET_RECLAIM_get_credentials_next() and
1418 * #GNUNET_RECLAIM_get_credentials_stop. @a proc will be called once
1419 * immediately, and then again after
1420 * #GNUNET_RECLAIM_get_credentials_next() is invoked.
1421 *
1422 * On error (disconnect), @a error_cb will be invoked.
1423 * On normal completion, @a finish_cb proc will be
1424 * invoked.
1425 *
1426 * @param h Handle to the re:claimID service
1427 * @param identity Identity to iterate over
1428 * @param error_cb Function to call on error (i.e. disconnect),
1429 * the handle is afterwards invalid
1430 * @param error_cb_cls Closure for @a error_cb
1431 * @param proc Function to call on each credential
1432 * @param proc_cls Closure for @a proc
1433 * @param finish_cb Function to call on completion
1434 * the handle is afterwards invalid
1435 * @param finish_cb_cls Closure for @a finish_cb
1436 * @return an iterator Handle to use for iteration
1437 */
1438struct GNUNET_RECLAIM_CredentialIterator *
1439GNUNET_RECLAIM_get_credentials_start (
1440 struct GNUNET_RECLAIM_Handle *h,
1441 const struct GNUNET_IDENTITY_PrivateKey *identity,
1442 GNUNET_SCHEDULER_TaskCallback error_cb,
1443 void *error_cb_cls,
1444 GNUNET_RECLAIM_CredentialResult proc,
1445 void *proc_cls,
1446 GNUNET_SCHEDULER_TaskCallback finish_cb,
1447 void *finish_cb_cls)
1448{
1449 struct GNUNET_RECLAIM_CredentialIterator *ait;
1450 struct GNUNET_MQ_Envelope *env;
1451 struct CredentialIterationStartMessage *msg;
1452 uint32_t rid;
1453
1454 rid = h->r_id_gen++;
1455 ait = GNUNET_new (struct GNUNET_RECLAIM_CredentialIterator);
1456 ait->h = h;
1457 ait->error_cb = error_cb;
1458 ait->error_cb_cls = error_cb_cls;
1459 ait->finish_cb = finish_cb;
1460 ait->finish_cb_cls = finish_cb_cls;
1461 ait->proc = proc;
1462 ait->proc_cls = proc_cls;
1463 ait->r_id = rid;
1464 ait->identity = *identity;
1465 GNUNET_CONTAINER_DLL_insert_tail (h->ait_head, h->ait_tail, ait);
1466 env =
1467 GNUNET_MQ_msg (msg,
1468 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_START);
1469 msg->id = htonl (rid);
1470 msg->identity = *identity;
1471 if (NULL == h->mq)
1472 ait->env = env;
1473 else
1474 GNUNET_MQ_send (h->mq, env);
1475 return ait;
1476}
1477
1478
1479/**
1480 * Calls the record processor specified in #GNUNET_RECLAIM_get_credential_start
1481 * for the next record.
1482 *
1483 * @param it the iterator
1484 */
1485void
1486GNUNET_RECLAIM_get_credentials_next (struct
1487 GNUNET_RECLAIM_CredentialIterator *ait)
1488{
1489 struct GNUNET_RECLAIM_Handle *h = ait->h;
1490 struct CredentialIterationNextMessage *msg;
1491 struct GNUNET_MQ_Envelope *env;
1492
1493 env =
1494 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_NEXT);
1495 msg->id = htonl (ait->r_id);
1496 GNUNET_MQ_send (h->mq, env);
1497}
1498
1499
1500/**
1501 * Stops iteration and releases the handle for further calls. Must
1502 * be called on any iteration that has not yet completed prior to calling
1503 * #GNUNET_RECLAIM_disconnect.
1504 *
1505 * @param it the iterator
1506 */
1507void
1508GNUNET_RECLAIM_get_credentials_stop (struct
1509 GNUNET_RECLAIM_CredentialIterator *ait)
1510{
1511 struct GNUNET_RECLAIM_Handle *h = ait->h;
1512 struct GNUNET_MQ_Envelope *env;
1513 struct CredentialIterationStopMessage *msg;
1514
1515 if (NULL != h->mq)
1516 {
1517 env =
1518 GNUNET_MQ_msg (msg,
1519 GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_STOP);
1520 msg->id = htonl (ait->r_id);
1521 GNUNET_MQ_send (h->mq, env);
1522 }
1523 free_ait (ait);
1524}
1525
1526
1527/**
1528 * Issues a ticket to another relying party. The identity may use
1529 * @GNUNET_RECLAIM_ticket_consume to consume the ticket
1530 * and retrieve the attributes specified in the attribute list.
1531 *
1532 * @param h the reclaim to use
1533 * @param iss the issuing identity (= the user)
1534 * @param rp the subject of the ticket (= the relying party)
1535 * @param attrs the attributes that the relying party is given access to
1536 * @param cb the callback
1537 * @param cb_cls the callback closure
1538 * @return handle to abort the operation
1539 */
1540struct GNUNET_RECLAIM_Operation *
1541GNUNET_RECLAIM_ticket_issue (
1542 struct GNUNET_RECLAIM_Handle *h,
1543 const struct GNUNET_IDENTITY_PrivateKey *iss,
1544 const struct GNUNET_IDENTITY_PublicKey *rp,
1545 const struct GNUNET_RECLAIM_AttributeList *attrs,
1546 GNUNET_RECLAIM_IssueTicketCallback cb,
1547 void *cb_cls)
1548{
1549 struct GNUNET_RECLAIM_Operation *op;
1550 struct IssueTicketMessage *tim;
1551 size_t attr_len;
1552
1553 fprintf (stderr, "Issuing ticket\n");
1554 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1555 op->h = h;
1556 op->ti_cb = cb;
1557 op->cls = cb_cls;
1558 op->r_id = h->r_id_gen++;
1559 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1560 attr_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
1561 op->env = GNUNET_MQ_msg_extra (tim,
1562 attr_len,
1563 GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1564 tim->identity = *iss;
1565 tim->rp = *rp;
1566 tim->id = htonl (op->r_id);
1567
1568 GNUNET_RECLAIM_attribute_list_serialize (attrs, (char *) &tim[1]);
1569
1570 tim->attr_len = htons (attr_len);
1571 if (NULL != h->mq)
1572 GNUNET_MQ_send_copy (h->mq, op->env);
1573 return op;
1574}
1575
1576
1577/**
1578 * Consumes an issued ticket. The ticket is persisted
1579 * and used to retrieve identity information from the issuer
1580 *
1581 * @param h the reclaim to use
1582 * @param identity the identity that is the subject of the issued ticket (the
1583 * relying party)
1584 * @param ticket the issued ticket to consume
1585 * @param cb the callback to call
1586 * @param cb_cls the callback closure
1587 * @return handle to abort the operation
1588 */
1589struct GNUNET_RECLAIM_Operation *
1590GNUNET_RECLAIM_ticket_consume (
1591 struct GNUNET_RECLAIM_Handle *h,
1592 const struct GNUNET_IDENTITY_PrivateKey *identity,
1593 const struct GNUNET_RECLAIM_Ticket *ticket,
1594 GNUNET_RECLAIM_AttributeTicketResult cb,
1595 void *cb_cls)
1596{
1597 struct GNUNET_RECLAIM_Operation *op;
1598 struct ConsumeTicketMessage *ctm;
1599
1600 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1601 op->h = h;
1602 op->atr_cb = cb;
1603 op->cls = cb_cls;
1604 op->r_id = h->r_id_gen++;
1605 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1606 op->env = GNUNET_MQ_msg (ctm, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1607 ctm->identity = *identity;
1608 ctm->id = htonl (op->r_id);
1609 ctm->ticket = *ticket;
1610 if (NULL != h->mq)
1611 GNUNET_MQ_send_copy (h->mq, op->env);
1612 else
1613 reconnect (h);
1614 return op;
1615}
1616
1617
1618/**
1619 * Lists all tickets that have been issued to remote
1620 * identites (relying parties)
1621 *
1622 * @param h the reclaim to use
1623 * @param identity the issuing identity
1624 * @param error_cb function to call on error (i.e. disconnect),
1625 * the handle is afterwards invalid
1626 * @param error_cb_cls closure for @a error_cb
1627 * @param proc function to call on each ticket; it
1628 * will be called repeatedly with a value (if available)
1629 * @param proc_cls closure for @a proc
1630 * @param finish_cb function to call on completion
1631 * the handle is afterwards invalid
1632 * @param finish_cb_cls closure for @a finish_cb
1633 * @return an iterator handle to use for iteration
1634 */
1635struct GNUNET_RECLAIM_TicketIterator *
1636GNUNET_RECLAIM_ticket_iteration_start (
1637 struct GNUNET_RECLAIM_Handle *h,
1638 const struct GNUNET_IDENTITY_PrivateKey *identity,
1639 GNUNET_SCHEDULER_TaskCallback error_cb,
1640 void *error_cb_cls,
1641 GNUNET_RECLAIM_TicketCallback proc,
1642 void *proc_cls,
1643 GNUNET_SCHEDULER_TaskCallback finish_cb,
1644 void *finish_cb_cls)
1645{
1646 struct GNUNET_RECLAIM_TicketIterator *it;
1647 struct GNUNET_MQ_Envelope *env;
1648 struct TicketIterationStartMessage *msg;
1649 uint32_t rid;
1650
1651 rid = h->r_id_gen++;
1652 it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1653 it->h = h;
1654 it->error_cb = error_cb;
1655 it->error_cb_cls = error_cb_cls;
1656 it->finish_cb = finish_cb;
1657 it->finish_cb_cls = finish_cb_cls;
1658 it->tr_cb = proc;
1659 it->cls = proc_cls;
1660 it->r_id = rid;
1661 GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1662 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1663 msg->id = htonl (rid);
1664 msg->identity = *identity;
1665 if (NULL == h->mq)
1666 it->env = env;
1667 else
1668 GNUNET_MQ_send (h->mq, env);
1669 return it;
1670}
1671
1672
1673/**
1674 * Calls the ticket processor specified in
1675 * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1676 *
1677 * @param it the iterator
1678 */
1679void
1680GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1681{
1682 struct GNUNET_RECLAIM_Handle *h = it->h;
1683 struct TicketIterationNextMessage *msg;
1684 struct GNUNET_MQ_Envelope *env;
1685
1686 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1687 msg->id = htonl (it->r_id);
1688 GNUNET_MQ_send (h->mq, env);
1689}
1690
1691
1692/**
1693 * Stops iteration and releases the handle for further calls. Must
1694 * be called on any iteration that has not yet completed prior to calling
1695 * #GNUNET_RECLAIM_disconnect.
1696 *
1697 * @param it the iterator
1698 */
1699void
1700GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1701{
1702 struct GNUNET_RECLAIM_Handle *h = it->h;
1703 struct GNUNET_MQ_Envelope *env;
1704 struct TicketIterationStopMessage *msg;
1705
1706 if (NULL != h->mq)
1707 {
1708 env =
1709 GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1710 msg->id = htonl (it->r_id);
1711 GNUNET_MQ_send (h->mq, env);
1712 }
1713 GNUNET_free (it);
1714}
1715
1716
1717/**
1718 * Revoked an issued ticket. The relying party will be unable to retrieve
1719 * attributes. Other issued tickets remain unaffected.
1720 * This includes tickets issued to other relying parties as well as to
1721 * other tickets issued to the audience specified in this ticket.
1722 *
1723 * @param h the identity provider to use
1724 * @param identity the issuing identity
1725 * @param ticket the ticket to revoke
1726 * @param cb the callback
1727 * @param cb_cls the callback closure
1728 * @return handle to abort the operation
1729 */
1730struct GNUNET_RECLAIM_Operation *
1731GNUNET_RECLAIM_ticket_revoke (
1732 struct GNUNET_RECLAIM_Handle *h,
1733 const struct GNUNET_IDENTITY_PrivateKey *identity,
1734 const struct GNUNET_RECLAIM_Ticket *ticket,
1735 GNUNET_RECLAIM_ContinuationWithStatus cb,
1736 void *cb_cls)
1737{
1738 struct GNUNET_RECLAIM_Operation *op;
1739 struct RevokeTicketMessage *msg;
1740 uint32_t rid;
1741
1742 rid = h->r_id_gen++;
1743 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1744 op->h = h;
1745 op->rvk_cb = cb;
1746 op->cls = cb_cls;
1747 op->r_id = rid;
1748 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1749 op->env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1750 msg->id = htonl (rid);
1751 msg->identity = *identity;
1752 msg->ticket = *ticket;
1753 if (NULL != h->mq)
1754 {
1755 GNUNET_MQ_send (h->mq, op->env);
1756 op->env = NULL;
1757 }
1758 return op;
1759}
1760
1761
1762/* end of reclaim_api.c */
diff --git a/src/reclaim/reclaim_attribute.c b/src/reclaim/reclaim_attribute.c
deleted file mode 100644
index 21fdd83a2..000000000
--- a/src/reclaim/reclaim_attribute.c
+++ /dev/null
@@ -1,582 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 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 reclaim-attribute/reclaim_attribute.c
23 * @brief helper library to manage identity attributes
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_reclaim_plugin.h"
29#include "reclaim_attribute.h"
30
31
32/**
33 * Handle for a plugin
34 */
35struct Plugin
36{
37 /**
38 * Name of the plugin
39 */
40 char *library_name;
41
42 /**
43 * Plugin API
44 */
45 struct GNUNET_RECLAIM_AttributePluginFunctions *api;
46};
47
48
49/**
50 * Plugins
51 */
52static struct Plugin **attr_plugins;
53
54
55/**
56 * Number of plugins
57 */
58static unsigned int num_plugins;
59
60
61/**
62 * Init canary
63 */
64static int initialized;
65
66
67/**
68 * Add a plugin
69 *
70 * @param cls closure
71 * @param library_name name of the API library
72 * @param lib_ret the plugin API pointer
73 */
74static void
75add_plugin (void *cls, const char *library_name, void *lib_ret)
76{
77 struct GNUNET_RECLAIM_AttributePluginFunctions *api = lib_ret;
78 struct Plugin *plugin;
79
80 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81 "Loading attribute plugin `%s'\n",
82 library_name);
83 plugin = GNUNET_new (struct Plugin);
84 plugin->api = api;
85 plugin->library_name = GNUNET_strdup (library_name);
86 GNUNET_array_append (attr_plugins, num_plugins, plugin);
87}
88
89
90/**
91 * Load plugins
92 */
93static void
94init ()
95{
96 if (GNUNET_YES == initialized)
97 return;
98 initialized = GNUNET_YES;
99 GNUNET_PLUGIN_load_all_in_context (GNUNET_OS_project_data_default (),
100 "libgnunet_plugin_reclaim_attribute_",
101 NULL,
102 &add_plugin,
103 NULL);
104}
105
106/**
107 * Dual function to #init().
108 */
109void __attribute__ ((destructor))
110RECLAIM_ATTRIBUTE_fini ()
111{
112 struct Plugin *plugin;
113 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
114 const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
115
116 if (pd != dpd)
117 GNUNET_OS_init (dpd);
118
119 for (unsigned int i = 0; i < num_plugins; i++)
120 {
121 plugin = attr_plugins[i];
122 GNUNET_break (NULL ==
123 GNUNET_PLUGIN_unload (plugin->library_name,
124 plugin->api));
125 GNUNET_free (plugin->library_name);
126 GNUNET_free (plugin);
127 }
128 GNUNET_free (attr_plugins);
129
130 if (pd != dpd)
131 GNUNET_OS_init (pd);
132
133 attr_plugins = NULL;
134}
135
136
137
138/**
139 * Convert a type name to the corresponding number
140 *
141 * @param typename name to convert
142 * @return corresponding number, UINT32_MAX on error
143 */
144uint32_t
145GNUNET_RECLAIM_attribute_typename_to_number (const char *typename)
146{
147 unsigned int i;
148 struct Plugin *plugin;
149 uint32_t ret;
150
151 init ();
152 for (i = 0; i < num_plugins; i++)
153 {
154 plugin = attr_plugins[i];
155 if (UINT32_MAX !=
156 (ret = plugin->api->typename_to_number (plugin->api->cls, typename)))
157 return ret;
158 }
159 return UINT32_MAX;
160}
161
162
163/**
164 * Convert a type number to the corresponding type string
165 *
166 * @param type number of a type
167 * @return corresponding typestring, NULL on error
168 */
169const char *
170GNUNET_RECLAIM_attribute_number_to_typename (uint32_t type)
171{
172 unsigned int i;
173 struct Plugin *plugin;
174 const char *ret;
175
176 init ();
177 for (i = 0; i < num_plugins; i++)
178 {
179 plugin = attr_plugins[i];
180 if (NULL !=
181 (ret = plugin->api->number_to_typename (plugin->api->cls, type)))
182 return ret;
183 }
184 return NULL;
185}
186
187
188/**
189 * Convert human-readable version of a 'claim' of an attribute to the binary
190 * representation
191 *
192 * @param type type of the claim
193 * @param s human-readable string
194 * @param data set to value in binary encoding (will be allocated)
195 * @param data_size set to number of bytes in @a data
196 * @return #GNUNET_OK on success
197 */
198int
199GNUNET_RECLAIM_attribute_string_to_value (uint32_t type,
200 const char *s,
201 void **data,
202 size_t *data_size)
203{
204 unsigned int i;
205 struct Plugin *plugin;
206
207 init ();
208 for (i = 0; i < num_plugins; i++)
209 {
210 plugin = attr_plugins[i];
211 if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls,
212 type,
213 s,
214 data,
215 data_size))
216 return GNUNET_OK;
217 }
218 return GNUNET_SYSERR;
219}
220
221
222/**
223 * Convert the 'claim' of an attribute to a string
224 *
225 * @param type the type of attribute
226 * @param data claim in binary encoding
227 * @param data_size number of bytes in @a data
228 * @return NULL on error, otherwise human-readable representation of the claim
229 */
230char *
231GNUNET_RECLAIM_attribute_value_to_string (uint32_t type,
232 const void *data,
233 size_t data_size)
234{
235 unsigned int i;
236 struct Plugin *plugin;
237 char *ret;
238
239 init ();
240 for (i = 0; i < num_plugins; i++)
241 {
242 plugin = attr_plugins[i];
243 if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls,
244 type,
245 data,
246 data_size)))
247 return ret;
248 }
249 return NULL;
250}
251
252
253/**
254 * Create a new attribute.
255 *
256 * @param attr_name the attribute name
257 * @param credential credential ID of the attribute (maybe NULL)
258 * @param type the attribute type
259 * @param data the attribute value
260 * @param data_size the attribute value size
261 * @return the new attribute
262 */
263struct GNUNET_RECLAIM_Attribute *
264GNUNET_RECLAIM_attribute_new (const char *attr_name,
265 const struct
266 GNUNET_RECLAIM_Identifier *credential,
267 uint32_t type,
268 const void *data,
269 size_t data_size)
270{
271 struct GNUNET_RECLAIM_Attribute *attr;
272 char *write_ptr;
273 char *attr_name_tmp = GNUNET_strdup (attr_name);
274
275 GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp);
276
277 attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute)
278 + strlen (attr_name_tmp) + 1 + data_size);
279 if (NULL != credential)
280 attr->credential = *credential;
281 attr->type = type;
282 attr->data_size = data_size;
283 attr->flag = 0;
284 write_ptr = (char *) &attr[1];
285 GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1);
286 attr->name = write_ptr;
287 write_ptr += strlen (attr->name) + 1;
288 GNUNET_memcpy (write_ptr, data, data_size);
289 attr->data = write_ptr;
290 GNUNET_free (attr_name_tmp);
291 return attr;
292}
293
294
295/**
296 * Add a new attribute to a claim list
297 *
298 * @param attr_name the name of the new attribute claim
299 * @param type the type of the claim
300 * @param data claim payload
301 * @param data_size claim payload size
302 */
303void
304GNUNET_RECLAIM_attribute_list_add (
305 struct GNUNET_RECLAIM_AttributeList *al,
306 const char *attr_name,
307 const struct GNUNET_RECLAIM_Identifier *credential,
308 uint32_t type,
309 const void *data,
310 size_t data_size)
311{
312 struct GNUNET_RECLAIM_AttributeListEntry *ale;
313
314 ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
315 ale->attribute =
316 GNUNET_RECLAIM_attribute_new (attr_name, credential,
317 type, data, data_size);
318 GNUNET_CONTAINER_DLL_insert (al->list_head,
319 al->list_tail,
320 ale);
321}
322
323
324/**
325 * Get required size for serialization buffer
326 *
327 * @param attrs the attribute list to serialize
328 * @return the required buffer size
329 */
330size_t
331GNUNET_RECLAIM_attribute_list_serialize_get_size (
332 const struct GNUNET_RECLAIM_AttributeList *al)
333{
334 struct GNUNET_RECLAIM_AttributeListEntry *ale;
335 size_t len = 0;
336
337 for (ale = al->list_head; NULL != ale; ale = ale->next)
338 {
339 GNUNET_assert (NULL != ale->attribute);
340 len += GNUNET_RECLAIM_attribute_serialize_get_size (ale->attribute);
341 }
342 return len;
343}
344
345
346/**
347 * Serialize an attribute list
348 *
349 * @param attrs the attribute list to serialize
350 * @param result the serialized attribute
351 * @return length of serialized data
352 */
353size_t
354GNUNET_RECLAIM_attribute_list_serialize (
355 const struct GNUNET_RECLAIM_AttributeList *al,
356 char *result)
357{
358 struct GNUNET_RECLAIM_AttributeListEntry *ale;
359 size_t len;
360 size_t total_len;
361 char *write_ptr;
362 write_ptr = result;
363 total_len = 0;
364 for (ale = al->list_head; NULL != ale; ale = ale->next)
365 {
366 GNUNET_assert (NULL != ale->attribute);
367 len = GNUNET_RECLAIM_attribute_serialize (ale->attribute, write_ptr);
368 total_len += len;
369 write_ptr += len;
370 }
371 return total_len;
372}
373
374
375/**
376 * Deserialize an attribute list
377 *
378 * @param data the serialized attribute list
379 * @param data_size the length of the serialized data
380 * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller
381 */
382struct GNUNET_RECLAIM_AttributeList *
383GNUNET_RECLAIM_attribute_list_deserialize (const char *data, size_t data_size)
384{
385 struct GNUNET_RECLAIM_AttributeList *al;
386 struct GNUNET_RECLAIM_AttributeListEntry *ale;
387 size_t attr_len;
388 const char *read_ptr;
389 size_t left = data_size;
390
391 al = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
392 if (data_size < sizeof(struct Attribute))
393 return al;
394 read_ptr = data;
395 while (left >= sizeof(struct Attribute))
396 {
397 ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
398 attr_len =
399 GNUNET_RECLAIM_attribute_deserialize (read_ptr,
400 left,
401 &ale->attribute);
402 if (-1 == attr_len)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
405 "Failed to deserialize malformed attribute.\n");
406 GNUNET_free (ale);
407 return al;
408 }
409 left -= attr_len;
410 GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
411 read_ptr += attr_len;
412 }
413 return al;
414}
415
416
417/**
418 * Make a (deep) copy of a claim list
419 * @param attrs claim list to copy
420 * @return copied claim list
421 */
422struct GNUNET_RECLAIM_AttributeList *
423GNUNET_RECLAIM_attribute_list_dup (
424 const struct GNUNET_RECLAIM_AttributeList *al)
425{
426 struct GNUNET_RECLAIM_AttributeListEntry *ale;
427 struct GNUNET_RECLAIM_AttributeListEntry *result_ale;
428 struct GNUNET_RECLAIM_AttributeList *result;
429
430 result = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
431 for (ale = al->list_head; NULL != ale; ale = ale->next)
432 {
433 result_ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
434 GNUNET_assert (NULL != ale->attribute);
435 {
436 result_ale->attribute =
437 GNUNET_RECLAIM_attribute_new (ale->attribute->name,
438 &ale->attribute->credential,
439 ale->attribute->type,
440 ale->attribute->data,
441 ale->attribute->data_size);
442
443 result_ale->attribute->id = ale->attribute->id;
444 result_ale->attribute->flag = ale->attribute->flag;
445 }
446 GNUNET_CONTAINER_DLL_insert (result->list_head,
447 result->list_tail,
448 result_ale);
449 }
450 return result;
451}
452
453
454/**
455 * Destroy claim list
456 *
457 * @param attrs list to destroy
458 */
459void
460GNUNET_RECLAIM_attribute_list_destroy (
461 struct GNUNET_RECLAIM_AttributeList *al)
462{
463 struct GNUNET_RECLAIM_AttributeListEntry *ale;
464 struct GNUNET_RECLAIM_AttributeListEntry *tmp_ale;
465
466 for (ale = al->list_head; NULL != ale;)
467 {
468 if (NULL != ale->attribute)
469 GNUNET_free (ale->attribute);
470 tmp_ale = ale;
471 ale = ale->next;
472 GNUNET_free (tmp_ale);
473 }
474 GNUNET_free (al);
475}
476
477
478/**
479 * Get required size for serialization buffer
480 *
481 * @param attr the attribute to serialize
482 * @return the required buffer size
483 */
484size_t
485GNUNET_RECLAIM_attribute_serialize_get_size (
486 const struct GNUNET_RECLAIM_Attribute *attr)
487{
488 return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
489}
490
491
492/**
493 * Serialize an attribute
494 *
495 * @param attr the attribute to serialize
496 * @param result the serialized attribute
497 * @return length of serialized data
498 */
499size_t
500GNUNET_RECLAIM_attribute_serialize (
501 const struct GNUNET_RECLAIM_Attribute *attr,
502 char *result)
503{
504 size_t data_len_ser;
505 size_t name_len;
506 struct Attribute *attr_ser;
507 char *write_ptr;
508
509 attr_ser = (struct Attribute *) result;
510 attr_ser->attribute_type = htons (attr->type);
511 attr_ser->attribute_flag = htonl (attr->flag);
512 attr_ser->attribute_id = attr->id;
513 attr_ser->credential_id = attr->credential;
514 name_len = strlen (attr->name);
515 attr_ser->name_len = htons (name_len);
516 write_ptr = (char *) &attr_ser[1];
517 GNUNET_memcpy (write_ptr, attr->name, name_len);
518 write_ptr += name_len;
519 // TODO plugin-ize
520 // data_len_ser = plugin->serialize_attribute_value (attr,
521 // &attr_ser[1]);
522 data_len_ser = attr->data_size;
523 GNUNET_memcpy (write_ptr, attr->data, attr->data_size);
524 attr_ser->data_size = htons (data_len_ser);
525
526 return sizeof(struct Attribute) + strlen (attr->name) + attr->data_size;
527}
528
529
530/**
531 * Deserialize an attribute
532 *
533 * @param data the serialized attribute
534 * @param data_size the length of the serialized data
535 *
536 * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
537 */
538ssize_t
539GNUNET_RECLAIM_attribute_deserialize (const char *data, size_t data_size,
540 struct GNUNET_RECLAIM_Attribute **attr)
541{
542 struct Attribute *attr_ser;
543 struct GNUNET_RECLAIM_Attribute *attribute;
544 size_t data_len;
545 size_t name_len;
546 char *write_ptr;
547
548 if (data_size < sizeof(struct Attribute))
549 return -1;
550
551 attr_ser = (struct Attribute *) data;
552 data_len = ntohs (attr_ser->data_size);
553 name_len = ntohs (attr_ser->name_len);
554 if (data_size < sizeof(struct Attribute) + data_len + name_len)
555 {
556 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
557 "Buffer too small to deserialize\n");
558 return -1;
559 }
560 attribute = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attribute)
561 + data_len + name_len + 1);
562 attribute->type = ntohs (attr_ser->attribute_type);
563 attribute->flag = ntohl (attr_ser->attribute_flag);
564 attribute->id = attr_ser->attribute_id;
565 attribute->credential = attr_ser->credential_id;
566 attribute->data_size = data_len;
567
568 write_ptr = (char *) &attribute[1];
569 GNUNET_memcpy (write_ptr, &attr_ser[1], name_len);
570 write_ptr[name_len] = '\0';
571 attribute->name = write_ptr;
572
573 write_ptr += name_len + 1;
574 GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len,
575 attribute->data_size);
576 *attr = attribute;
577 attribute->data = write_ptr;
578 return sizeof(struct Attribute) + data_len + name_len;
579}
580
581
582/* end of reclaim_attribute.c */
diff --git a/src/reclaim/reclaim_attribute.h b/src/reclaim/reclaim_attribute.h
deleted file mode 100644
index 285d75d83..000000000
--- a/src/reclaim/reclaim_attribute.h
+++ /dev/null
@@ -1,73 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @file reclaim-attribute/reclaim_attribute.h
23 * @brief GNUnet reclaim identity attributes
24 *
25 */
26#ifndef RECLAIM_ATTRIBUTE_H
27#define RECLAIM_ATTRIBUTE_H
28
29#include "gnunet_reclaim_service.h"
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33/**
34 * Serialized claim
35 */
36struct Attribute
37{
38 /**
39 * Attribute type
40 */
41 uint32_t attribute_type GNUNET_PACKED;
42
43 /**
44 * Attribute flag
45 */
46 uint32_t attribute_flag GNUNET_PACKED;
47
48 /**
49 * Attribute ID
50 */
51 struct GNUNET_RECLAIM_Identifier attribute_id;
52
53 /**
54 * Credential ID
55 */
56 struct GNUNET_RECLAIM_Identifier credential_id;
57
58 /**
59 * Name length
60 */
61 uint32_t name_len GNUNET_PACKED;
62
63 /**
64 * Data size
65 */
66 uint32_t data_size GNUNET_PACKED;
67
68 // followed by data_size Attribute value data
69};
70
71GNUNET_NETWORK_STRUCT_BEGIN
72
73#endif
diff --git a/src/reclaim/reclaim_credential.c b/src/reclaim/reclaim_credential.c
deleted file mode 100644
index b4aeedf29..000000000
--- a/src/reclaim/reclaim_credential.c
+++ /dev/null
@@ -1,1064 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 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 reclaim/reclaim_credential.c
23 * @brief helper library to manage identity attribute credentials
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_reclaim_plugin.h"
29#include "reclaim_credential.h"
30
31
32/**
33 * Handle for a plugin
34 */
35struct Plugin
36{
37 /**
38 * Name of the plugin
39 */
40 char *library_name;
41
42 /**
43 * Plugin API
44 */
45 struct GNUNET_RECLAIM_CredentialPluginFunctions *api;
46};
47
48
49/**
50 * Plugins
51 */
52static struct Plugin **credential_plugins;
53
54
55/**
56 * Number of plugins
57 */
58static unsigned int num_plugins;
59
60
61/**
62 * Init canary
63 */
64static int initialized;
65
66
67/**
68 * Add a plugin
69 *
70 * @param cls closure
71 * @param library_name name of the API library
72 * @param lib_ret the plugin API pointer
73 */
74static void
75add_plugin (void *cls, const char *library_name, void *lib_ret)
76{
77 struct GNUNET_RECLAIM_CredentialPluginFunctions *api = lib_ret;
78 struct Plugin *plugin;
79
80 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81 "Loading credential plugin `%s'\n",
82 library_name);
83 plugin = GNUNET_new (struct Plugin);
84 plugin->api = api;
85 plugin->library_name = GNUNET_strdup (library_name);
86 GNUNET_array_append (credential_plugins, num_plugins, plugin);
87}
88
89
90/**
91 * Load plugins
92 */
93static void
94init ()
95{
96 if (GNUNET_YES == initialized)
97 return;
98 initialized = GNUNET_YES;
99 GNUNET_PLUGIN_load_all_in_context (GNUNET_OS_project_data_default (),
100 "libgnunet_plugin_reclaim_credential_",
101 NULL,
102 &add_plugin,
103 NULL);
104}
105
106
107/**
108 * Dual function to #init().
109 */
110void __attribute__ ((destructor))
111RECLAIM_CREDENTIAL_fini ()
112{
113 struct Plugin *plugin;
114 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
115 const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
116
117 if (pd != dpd)
118 GNUNET_OS_init (dpd);
119
120 for (unsigned int i = 0; i < num_plugins; i++)
121 {
122 plugin = credential_plugins[i];
123 GNUNET_break (NULL ==
124 GNUNET_PLUGIN_unload (plugin->library_name,
125 plugin->api));
126 GNUNET_free (plugin->library_name);
127 GNUNET_free (plugin);
128 }
129 GNUNET_free (credential_plugins);
130
131 if (pd != dpd)
132 GNUNET_OS_init (pd);
133
134 credential_plugins = NULL;
135}
136
137
138/**
139 * Convert an credential type name to the corresponding number
140 *
141 * @param typename name to convert
142 * @return corresponding number, UINT32_MAX on error
143 */
144uint32_t
145GNUNET_RECLAIM_credential_typename_to_number (const char *typename)
146{
147 unsigned int i;
148 struct Plugin *plugin;
149 uint32_t ret;
150 init ();
151 for (i = 0; i < num_plugins; i++)
152 {
153 plugin = credential_plugins[i];
154 if (UINT32_MAX !=
155 (ret = plugin->api->typename_to_number (plugin->api->cls,
156 typename)))
157 return ret;
158 }
159 return UINT32_MAX;
160}
161
162
163/**
164 * Convert an credential type number to the corresponding credential type string
165 *
166 * @param type number of a type
167 * @return corresponding typestring, NULL on error
168 */
169const char *
170GNUNET_RECLAIM_credential_number_to_typename (uint32_t type)
171{
172 unsigned int i;
173 struct Plugin *plugin;
174 const char *ret;
175
176 init ();
177 for (i = 0; i < num_plugins; i++)
178 {
179 plugin = credential_plugins[i];
180 if (NULL !=
181 (ret = plugin->api->number_to_typename (plugin->api->cls, type)))
182 return ret;
183 }
184 return NULL;
185}
186
187
188/**
189 * Convert human-readable version of a 'claim' of an credential to the binary
190 * representation
191 *
192 * @param type type of the claim
193 * @param s human-readable string
194 * @param data set to value in binary encoding (will be allocated)
195 * @param data_size set to number of bytes in @a data
196 * @return #GNUNET_OK on success
197 */
198int
199GNUNET_RECLAIM_credential_string_to_value (uint32_t type,
200 const char *s,
201 void **data,
202 size_t *data_size)
203{
204 unsigned int i;
205 struct Plugin *plugin;
206
207 init ();
208 for (i = 0; i < num_plugins; i++)
209 {
210 plugin = credential_plugins[i];
211 if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls,
212 type,
213 s,
214 data,
215 data_size))
216 return GNUNET_OK;
217 }
218 return GNUNET_SYSERR;
219}
220
221
222/**
223 * Convert the 'claim' of an credential to a string
224 *
225 * @param type the type of credential
226 * @param data claim in binary encoding
227 * @param data_size number of bytes in @a data
228 * @return NULL on error, otherwise human-readable representation of the claim
229 */
230char *
231GNUNET_RECLAIM_credential_value_to_string (uint32_t type,
232 const void *data,
233 size_t data_size)
234{
235 unsigned int i;
236 struct Plugin *plugin;
237 char *ret;
238
239 init ();
240 for (i = 0; i < num_plugins; i++)
241 {
242 plugin = credential_plugins[i];
243 if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls,
244 type,
245 data,
246 data_size)))
247 return ret;
248 }
249 return NULL;
250}
251
252
253/**
254 * Create a new credential.
255 *
256 * @param attr_name the credential name
257 * @param type the credential type
258 * @param data the credential value
259 * @param data_size the credential value size
260 * @return the new credential
261 */
262struct GNUNET_RECLAIM_Credential *
263GNUNET_RECLAIM_credential_new (const char *attr_name,
264 uint32_t type,
265 const void *data,
266 size_t data_size)
267{
268 struct GNUNET_RECLAIM_Credential *attr;
269 char *write_ptr;
270 char *attr_name_tmp = GNUNET_strdup (attr_name);
271
272 GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp);
273
274 attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Credential)
275 + strlen (attr_name_tmp) + 1 + data_size);
276 attr->type = type;
277 attr->data_size = data_size;
278 attr->flag = 0;
279 write_ptr = (char *) &attr[1];
280 GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1);
281 attr->name = write_ptr;
282 write_ptr += strlen (attr->name) + 1;
283 GNUNET_memcpy (write_ptr, data, data_size);
284 attr->data = write_ptr;
285 GNUNET_free (attr_name_tmp);
286 return attr;
287}
288
289
290/**
291 * Get required size for serialization buffer
292 *
293 * @param attrs the attribute list to serialize
294 * @return the required buffer size
295 */
296size_t
297GNUNET_RECLAIM_credential_list_serialize_get_size (
298 const struct GNUNET_RECLAIM_CredentialList *credentials)
299{
300 struct GNUNET_RECLAIM_CredentialListEntry *le;
301 size_t len = 0;
302
303 for (le = credentials->list_head; NULL != le; le = le->next)
304 {
305 GNUNET_assert (NULL != le->credential);
306 len += GNUNET_RECLAIM_credential_serialize_get_size (le->credential);
307 len += sizeof(struct GNUNET_RECLAIM_CredentialListEntry);
308 }
309 return len;
310}
311
312
313/**
314 * Serialize an attribute list
315 *
316 * @param attrs the attribute list to serialize
317 * @param result the serialized attribute
318 * @return length of serialized data
319 */
320size_t
321GNUNET_RECLAIM_credential_list_serialize (
322 const struct GNUNET_RECLAIM_CredentialList *credentials,
323 char *result)
324{
325 struct GNUNET_RECLAIM_CredentialListEntry *le;
326 size_t len;
327 size_t total_len;
328 char *write_ptr;
329 write_ptr = result;
330 total_len = 0;
331 for (le = credentials->list_head; NULL != le; le = le->next)
332 {
333 GNUNET_assert (NULL != le->credential);
334 len = GNUNET_RECLAIM_credential_serialize (le->credential, write_ptr);
335 total_len += len;
336 write_ptr += len;
337 }
338 return total_len;
339}
340
341
342/**
343 * Deserialize an credential list
344 *
345 * @param data the serialized attribute list
346 * @param data_size the length of the serialized data
347 * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller
348 */
349struct GNUNET_RECLAIM_CredentialList *
350GNUNET_RECLAIM_credential_list_deserialize (const char *data, size_t data_size)
351{
352 struct GNUNET_RECLAIM_CredentialList *al;
353 struct GNUNET_RECLAIM_CredentialListEntry *ale;
354 size_t att_len;
355 const char *read_ptr;
356
357 al = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
358
359 if ((data_size < sizeof(struct
360 Credential)
361 + sizeof(struct GNUNET_RECLAIM_CredentialListEntry)))
362 return al;
363
364 read_ptr = data;
365 while (((data + data_size) - read_ptr) >= sizeof(struct Credential))
366 {
367 ale = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry);
368 ale->credential =
369 GNUNET_RECLAIM_credential_deserialize (read_ptr,
370 data_size - (read_ptr - data));
371 if (NULL == ale->credential)
372 {
373 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
374 "Failed to deserialize malformed credential.\n");
375 GNUNET_free (ale);
376 return al;
377 }
378 GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
379 att_len = GNUNET_RECLAIM_credential_serialize_get_size (ale->credential);
380 read_ptr += att_len;
381 }
382 return al;
383}
384
385
386/**
387 * Make a (deep) copy of the credential list
388 * @param attrs claim list to copy
389 * @return copied claim list
390 */
391struct GNUNET_RECLAIM_CredentialList *
392GNUNET_RECLAIM_credential_list_dup (
393 const struct GNUNET_RECLAIM_CredentialList *al)
394{
395 struct GNUNET_RECLAIM_CredentialListEntry *ale;
396 struct GNUNET_RECLAIM_CredentialListEntry *result_ale;
397 struct GNUNET_RECLAIM_CredentialList *result;
398
399 result = GNUNET_new (struct GNUNET_RECLAIM_CredentialList);
400 for (ale = al->list_head; NULL != ale; ale = ale->next)
401 {
402 result_ale = GNUNET_new (struct GNUNET_RECLAIM_CredentialListEntry);
403 GNUNET_assert (NULL != ale->credential);
404 result_ale->credential =
405 GNUNET_RECLAIM_credential_new (ale->credential->name,
406 ale->credential->type,
407 ale->credential->data,
408 ale->credential->data_size);
409 result_ale->credential->id = ale->credential->id;
410 GNUNET_CONTAINER_DLL_insert (result->list_head,
411 result->list_tail,
412 result_ale);
413 }
414 return result;
415}
416
417
418/**
419 * Destroy credential list
420 *
421 * @param attrs list to destroy
422 */
423void
424GNUNET_RECLAIM_credential_list_destroy (
425 struct GNUNET_RECLAIM_CredentialList *al)
426{
427 struct GNUNET_RECLAIM_CredentialListEntry *ale;
428 struct GNUNET_RECLAIM_CredentialListEntry *tmp_ale;
429
430 for (ale = al->list_head; NULL != ale;)
431 {
432 if (NULL != ale->credential)
433 GNUNET_free (ale->credential);
434 tmp_ale = ale;
435 ale = ale->next;
436 GNUNET_free (tmp_ale);
437 }
438 GNUNET_free (al);
439}
440
441
442/**
443 * Get required size for serialization buffer
444 *
445 * @param attr the credential to serialize
446 * @return the required buffer size
447 */
448size_t
449GNUNET_RECLAIM_credential_serialize_get_size (
450 const struct GNUNET_RECLAIM_Credential *credential)
451{
452 return sizeof(struct Credential) + strlen (credential->name)
453 + credential->data_size;
454}
455
456
457/**
458 * Serialize an credential
459 *
460 * @param attr the credential to serialize
461 * @param result the serialized credential
462 * @return length of serialized data
463 */
464size_t
465GNUNET_RECLAIM_credential_serialize (
466 const struct GNUNET_RECLAIM_Credential *credential,
467 char *result)
468{
469 size_t data_len_ser;
470 size_t name_len;
471 struct Credential *atts;
472 char *write_ptr;
473
474 atts = (struct Credential *) result;
475 atts->credential_type = htons (credential->type);
476 atts->credential_flag = htonl (credential->flag);
477 atts->credential_id = credential->id;
478 name_len = strlen (credential->name);
479 atts->name_len = htons (name_len);
480 write_ptr = (char *) &atts[1];
481 GNUNET_memcpy (write_ptr, credential->name, name_len);
482 write_ptr += name_len;
483 // TODO plugin-ize
484 // data_len_ser = plugin->serialize_attribute_value (attr,
485 // &attr_ser[1]);
486 data_len_ser = credential->data_size;
487 GNUNET_memcpy (write_ptr, credential->data, credential->data_size);
488 atts->data_size = htons (data_len_ser);
489
490 return sizeof(struct Credential) + strlen (credential->name)
491 + credential->data_size;
492}
493
494
495/**
496 * Deserialize an credential
497 *
498 * @param data the serialized credential
499 * @param data_size the length of the serialized data
500 *
501 * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
502 */
503struct GNUNET_RECLAIM_Credential *
504GNUNET_RECLAIM_credential_deserialize (const char *data, size_t data_size)
505{
506 struct GNUNET_RECLAIM_Credential *credential;
507 struct Credential *atts;
508 size_t data_len;
509 size_t name_len;
510 char *write_ptr;
511
512 if (data_size < sizeof(struct Credential))
513 return NULL;
514
515 atts = (struct Credential *) data;
516 data_len = ntohs (atts->data_size);
517 name_len = ntohs (atts->name_len);
518 if (data_size < sizeof(struct Credential) + data_len + name_len)
519 {
520 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521 "Buffer too small to deserialize\n");
522 return NULL;
523 }
524 credential = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Credential)
525 + data_len + name_len + 1);
526 credential->type = ntohs (atts->credential_type);
527 credential->flag = ntohl (atts->credential_flag);
528 credential->id = atts->credential_id;
529 credential->data_size = data_len;
530
531 write_ptr = (char *) &credential[1];
532 GNUNET_memcpy (write_ptr, &atts[1], name_len);
533 write_ptr[name_len] = '\0';
534 credential->name = write_ptr;
535
536 write_ptr += name_len + 1;
537 GNUNET_memcpy (write_ptr, (char *) &atts[1] + name_len,
538 credential->data_size);
539 credential->data = write_ptr;
540 return credential;
541}
542
543
544struct GNUNET_RECLAIM_AttributeList*
545GNUNET_RECLAIM_credential_get_attributes (const struct
546 GNUNET_RECLAIM_Credential *credential)
547{
548 unsigned int i;
549 struct Plugin *plugin;
550 struct GNUNET_RECLAIM_AttributeList *ret;
551 init ();
552 for (i = 0; i < num_plugins; i++)
553 {
554 plugin = credential_plugins[i];
555 if (NULL !=
556 (ret = plugin->api->get_attributes (plugin->api->cls,
557 credential)))
558 return ret;
559 }
560 return NULL;
561}
562
563
564char*
565GNUNET_RECLAIM_credential_get_issuer (const struct
566 GNUNET_RECLAIM_Credential *credential)
567{
568 unsigned int i;
569 struct Plugin *plugin;
570 char *ret;
571 init ();
572 for (i = 0; i < num_plugins; i++)
573 {
574 plugin = credential_plugins[i];
575 if (NULL !=
576 (ret = plugin->api->get_issuer (plugin->api->cls,
577 credential)))
578 return ret;
579 }
580 return NULL;
581}
582
583
584int
585GNUNET_RECLAIM_credential_get_expiration (const struct
586 GNUNET_RECLAIM_Credential *credential,
587 struct GNUNET_TIME_Absolute*exp)
588{
589 unsigned int i;
590 struct Plugin *plugin;
591 init ();
592 for (i = 0; i < num_plugins; i++)
593 {
594 plugin = credential_plugins[i];
595 if (GNUNET_OK != plugin->api->get_expiration (plugin->api->cls,
596 credential,
597 exp))
598 continue;
599 return GNUNET_OK;
600 }
601 return GNUNET_SYSERR;
602}
603
604
605/**
606 * Convert an presentation type name to the corresponding number
607 *
608 * @param typename name to convert
609 * @return corresponding number, UINT32_MAX on error
610 */
611uint32_t
612GNUNET_RECLAIM_presentation_typename_to_number (const char *typename)
613{
614 unsigned int i;
615 struct Plugin *plugin;
616 uint32_t ret;
617 init ();
618 for (i = 0; i < num_plugins; i++)
619 {
620 plugin = credential_plugins[i];
621 if (UINT32_MAX !=
622 (ret = plugin->api->typename_to_number_p (plugin->api->cls,
623 typename)))
624 return ret;
625 }
626 return UINT32_MAX;
627}
628
629
630/**
631 * Convert an presentation type number to the corresponding presentation type string
632 *
633 * @param type number of a type
634 * @return corresponding typestring, NULL on error
635 */
636const char *
637GNUNET_RECLAIM_presentation_number_to_typename (uint32_t type)
638{
639 unsigned int i;
640 struct Plugin *plugin;
641 const char *ret;
642
643 init ();
644 for (i = 0; i < num_plugins; i++)
645 {
646 plugin = credential_plugins[i];
647 if (NULL !=
648 (ret = plugin->api->number_to_typename_p (plugin->api->cls, type)))
649 return ret;
650 }
651 return NULL;
652}
653
654
655/**
656 * Convert human-readable version of a 'claim' of an presentation to the binary
657 * representation
658 *
659 * @param type type of the claim
660 * @param s human-readable string
661 * @param data set to value in binary encoding (will be allocated)
662 * @param data_size set to number of bytes in @a data
663 * @return #GNUNET_OK on success
664 */
665int
666GNUNET_RECLAIM_presentation_string_to_value (uint32_t type,
667 const char *s,
668 void **data,
669 size_t *data_size)
670{
671 unsigned int i;
672 struct Plugin *plugin;
673
674 init ();
675 for (i = 0; i < num_plugins; i++)
676 {
677 plugin = credential_plugins[i];
678 if (GNUNET_OK == plugin->api->string_to_value_p (plugin->api->cls,
679 type,
680 s,
681 data,
682 data_size))
683 return GNUNET_OK;
684 }
685 return GNUNET_SYSERR;
686}
687
688
689/**
690 * Convert the 'claim' of an presentation to a string
691 *
692 * @param type the type of presentation
693 * @param data claim in binary encoding
694 * @param data_size number of bytes in @a data
695 * @return NULL on error, otherwise human-readable representation of the claim
696 */
697char *
698GNUNET_RECLAIM_presentation_value_to_string (uint32_t type,
699 const void *data,
700 size_t data_size)
701{
702 unsigned int i;
703 struct Plugin *plugin;
704 char *ret;
705
706 init ();
707 for (i = 0; i < num_plugins; i++)
708 {
709 plugin = credential_plugins[i];
710 if (NULL != (ret = plugin->api->value_to_string_p (plugin->api->cls,
711 type,
712 data,
713 data_size)))
714 return ret;
715 }
716 return NULL;
717}
718
719
720struct GNUNET_RECLAIM_Presentation *
721GNUNET_RECLAIM_presentation_new (uint32_t type,
722 const void *data,
723 size_t data_size)
724{
725 struct GNUNET_RECLAIM_Presentation *attr;
726 char *write_ptr;
727
728 attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Presentation)
729 + data_size);
730 attr->type = type;
731 attr->data_size = data_size;
732 write_ptr = (char *) &attr[1];
733 GNUNET_memcpy (write_ptr, data, data_size);
734 attr->data = write_ptr;
735 return attr;
736}
737
738
739/**
740 * Get required size for serialization buffer
741 *
742 * @param attrs the attribute list to serialize
743 * @return the required buffer size
744 */
745size_t
746GNUNET_RECLAIM_presentation_list_serialize_get_size (
747 const struct GNUNET_RECLAIM_PresentationList *presentations)
748{
749 struct GNUNET_RECLAIM_PresentationListEntry *le;
750 size_t len = 0;
751
752 for (le = presentations->list_head; NULL != le; le = le->next)
753 {
754 GNUNET_assert (NULL != le->presentation);
755 len += GNUNET_RECLAIM_presentation_serialize_get_size (le->presentation);
756 }
757 return len;
758}
759
760
761/**
762 * Serialize an attribute list
763 *
764 * @param attrs the attribute list to serialize
765 * @param result the serialized attribute
766 * @return length of serialized data
767 */
768size_t
769GNUNET_RECLAIM_presentation_list_serialize (
770 const struct GNUNET_RECLAIM_PresentationList *presentations,
771 char *result)
772{
773 struct GNUNET_RECLAIM_PresentationListEntry *le;
774 size_t len;
775 size_t total_len;
776 char *write_ptr;
777 write_ptr = result;
778 total_len = 0;
779 for (le = presentations->list_head; NULL != le; le = le->next)
780 {
781 GNUNET_assert (NULL != le->presentation);
782 len = GNUNET_RECLAIM_presentation_serialize (le->presentation, write_ptr);
783 total_len += len;
784 write_ptr += len;
785 }
786 return total_len;
787}
788
789
790/**
791 * Deserialize an presentation list
792 *
793 * @param data the serialized attribute list
794 * @param data_size the length of the serialized data
795 * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller
796 */
797struct GNUNET_RECLAIM_PresentationList *
798GNUNET_RECLAIM_presentation_list_deserialize (const char *data, size_t
799 data_size)
800{
801 struct GNUNET_RECLAIM_PresentationList *al;
802 struct GNUNET_RECLAIM_PresentationListEntry *ale;
803 size_t att_len;
804 const char *read_ptr;
805
806 al = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
807
808 if (data_size < sizeof(struct Presentation))
809 return al;
810
811 read_ptr = data;
812 while (((data + data_size) - read_ptr) >= sizeof(struct Presentation))
813 {
814 ale = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
815 ale->presentation =
816 GNUNET_RECLAIM_presentation_deserialize (read_ptr,
817 data_size - (read_ptr - data));
818 if (NULL == ale->presentation)
819 {
820 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
821 "Failed to deserialize malformed presentation.\n");
822 GNUNET_free (ale);
823 return al;
824 }
825 GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
826 att_len = GNUNET_RECLAIM_presentation_serialize_get_size (
827 ale->presentation);
828 read_ptr += att_len;
829 }
830 return al;
831}
832
833
834/**
835 * Make a (deep) copy of the presentation list
836 * @param attrs claim list to copy
837 * @return copied claim list
838 */
839struct GNUNET_RECLAIM_PresentationList *
840GNUNET_RECLAIM_presentation_list_dup (
841 const struct GNUNET_RECLAIM_PresentationList *al)
842{
843 struct GNUNET_RECLAIM_PresentationListEntry *ale;
844 struct GNUNET_RECLAIM_PresentationListEntry *result_ale;
845 struct GNUNET_RECLAIM_PresentationList *result;
846
847 result = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
848 for (ale = al->list_head; NULL != ale; ale = ale->next)
849 {
850 result_ale = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
851 GNUNET_assert (NULL != ale->presentation);
852 result_ale->presentation =
853 GNUNET_RECLAIM_presentation_new (ale->presentation->type,
854 ale->presentation->data,
855 ale->presentation->data_size);
856 result_ale->presentation->credential_id = ale->presentation->credential_id;
857 GNUNET_CONTAINER_DLL_insert (result->list_head,
858 result->list_tail,
859 result_ale);
860 }
861 return result;
862}
863
864
865/**
866 * Destroy presentation list
867 *
868 * @param attrs list to destroy
869 */
870void
871GNUNET_RECLAIM_presentation_list_destroy (
872 struct GNUNET_RECLAIM_PresentationList *al)
873{
874 struct GNUNET_RECLAIM_PresentationListEntry *ale;
875 struct GNUNET_RECLAIM_PresentationListEntry *tmp_ale;
876
877 for (ale = al->list_head; NULL != ale;)
878 {
879 if (NULL != ale->presentation)
880 GNUNET_free (ale->presentation);
881 tmp_ale = ale;
882 ale = ale->next;
883 GNUNET_free (tmp_ale);
884 }
885 GNUNET_free (al);
886}
887
888
889/**
890 * Get required size for serialization buffer
891 *
892 * @param attr the presentation to serialize
893 * @return the required buffer size
894 */
895size_t
896GNUNET_RECLAIM_presentation_serialize_get_size (
897 const struct GNUNET_RECLAIM_Presentation *presentation)
898{
899 return sizeof(struct Presentation) + presentation->data_size;
900}
901
902
903/**
904 * Serialize an presentation
905 *
906 * @param attr the presentation to serialize
907 * @param result the serialized presentation
908 * @return length of serialized data
909 */
910size_t
911GNUNET_RECLAIM_presentation_serialize (
912 const struct GNUNET_RECLAIM_Presentation *presentation,
913 char *result)
914{
915 struct Presentation *atts;
916 char *write_ptr;
917
918 atts = (struct Presentation *) result;
919 atts->presentation_type = htons (presentation->type);
920 atts->credential_id = presentation->credential_id;
921 write_ptr = (char *) &atts[1];
922 GNUNET_memcpy (write_ptr, presentation->data, presentation->data_size);
923 atts->data_size = htons (presentation->data_size);
924
925 return sizeof(struct Presentation) + presentation->data_size;
926}
927
928
929/**
930 * Deserialize an presentation
931 *
932 * @param data the serialized presentation
933 * @param data_size the length of the serialized data
934 *
935 * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
936 */
937struct GNUNET_RECLAIM_Presentation *
938GNUNET_RECLAIM_presentation_deserialize (const char *data, size_t data_size)
939{
940 struct GNUNET_RECLAIM_Presentation *presentation;
941 struct Presentation *atts;
942 size_t data_len;
943 char *write_ptr;
944
945 if (data_size < sizeof(struct Presentation))
946 return NULL;
947
948 atts = (struct Presentation *) data;
949 data_len = ntohs (atts->data_size);
950 if (data_size < sizeof(struct Presentation) + data_len)
951 {
952 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
953 "Buffer too small to deserialize\n");
954 return NULL;
955 }
956 presentation = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Presentation)
957 + data_len);
958 presentation->type = ntohs (atts->presentation_type);
959 presentation->credential_id = atts->credential_id;
960 presentation->data_size = data_len;
961
962 write_ptr = (char *) &presentation[1];
963 GNUNET_memcpy (write_ptr, &atts[1], data_len);
964 presentation->data = write_ptr;
965 return presentation;
966}
967
968
969struct GNUNET_RECLAIM_AttributeList*
970GNUNET_RECLAIM_presentation_get_attributes (const struct
971 GNUNET_RECLAIM_Presentation *
972 presentation)
973{
974 unsigned int i;
975 struct Plugin *plugin;
976 struct GNUNET_RECLAIM_AttributeList *ret;
977 init ();
978 for (i = 0; i < num_plugins; i++)
979 {
980 plugin = credential_plugins[i];
981 if (NULL !=
982 (ret = plugin->api->get_attributes_p (plugin->api->cls,
983 presentation)))
984 return ret;
985 }
986 return NULL;
987}
988
989
990char*
991GNUNET_RECLAIM_presentation_get_issuer (const struct
992 GNUNET_RECLAIM_Presentation *
993 presentation)
994{
995 unsigned int i;
996 struct Plugin *plugin;
997 char *ret;
998 init ();
999 for (i = 0; i < num_plugins; i++)
1000 {
1001 plugin = credential_plugins[i];
1002 if (NULL !=
1003 (ret = plugin->api->get_issuer_p (plugin->api->cls,
1004 presentation)))
1005 return ret;
1006 }
1007 return NULL;
1008}
1009
1010
1011int
1012GNUNET_RECLAIM_presentation_get_expiration (const struct
1013 GNUNET_RECLAIM_Presentation *
1014 presentation,
1015 struct GNUNET_TIME_Absolute*exp)
1016{
1017 unsigned int i;
1018 struct Plugin *plugin;
1019 init ();
1020 for (i = 0; i < num_plugins; i++)
1021 {
1022 plugin = credential_plugins[i];
1023 if (GNUNET_OK != plugin->api->get_expiration_p (plugin->api->cls,
1024 presentation,
1025 exp))
1026 continue;
1027 return GNUNET_OK;
1028 }
1029 return GNUNET_SYSERR;
1030}
1031
1032
1033/**
1034 * Create a presentation from a credential and a lift of (selected)
1035 * attributes in the credential.
1036 *
1037 * @param cred the credential to use
1038 * @param attrs the attributes to present from the credential
1039 * @return the credential presentation presenting the attributes according
1040 * to the presentation mechanism of the credential
1041 * or NULL on error.
1042 */
1043int
1044GNUNET_RECLAIM_credential_get_presentation (
1045 const struct GNUNET_RECLAIM_Credential *cred,
1046 const struct GNUNET_RECLAIM_AttributeList *attrs,
1047 struct GNUNET_RECLAIM_Presentation **presentation)
1048{
1049 unsigned int i;
1050 struct Plugin *plugin;
1051 init ();
1052 for (i = 0; i < num_plugins; i++)
1053 {
1054 plugin = credential_plugins[i];
1055 if (GNUNET_OK != plugin->api->create_presentation (plugin->api->cls,
1056 cred,
1057 attrs,
1058 presentation))
1059 continue;
1060 (*presentation)->credential_id = cred->id;
1061 return GNUNET_OK;
1062 }
1063 return GNUNET_SYSERR;
1064}
diff --git a/src/reclaim/reclaim_credential.h b/src/reclaim/reclaim_credential.h
deleted file mode 100644
index 7704ed968..000000000
--- a/src/reclaim/reclaim_credential.h
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
22 * @file reclaim/reclaim_credential.h
23 * @brief GNUnet reclaim identity attribute credentials
24 *
25 */
26#ifndef RECLAIM_CREDENTIAL_H
27#define RECLAIM_CREDENTIAL_H
28
29#include "gnunet_reclaim_service.h"
30
31/**
32 * Serialized credential claim
33 */
34struct Credential
35{
36 /**
37 * Credential type
38 */
39 uint32_t credential_type;
40
41 /**
42 * Credential flag
43 */
44 uint32_t credential_flag;
45
46 /**
47 * Credential ID
48 */
49 struct GNUNET_RECLAIM_Identifier credential_id;
50
51 /**
52 * Name length
53 */
54 uint32_t name_len;
55
56 /**
57 * Data size
58 */
59 uint32_t data_size;
60
61 // followed by data_size Credential value data
62};
63
64
65/**
66 * Serialized presentation claim
67 */
68struct Presentation
69{
70 /**
71 * Presentation type
72 */
73 uint32_t presentation_type;
74
75 /**
76 * Presentation flag
77 */
78 uint32_t presentation_flag;
79
80 /**
81 * Credential ID
82 */
83 struct GNUNET_RECLAIM_Identifier credential_id;
84
85 /**
86 * Name length
87 */
88 uint32_t name_len;
89
90 /**
91 * Data size
92 */
93 uint32_t data_size;
94
95 // followed by data_size Presentation value data
96};
97
98
99#endif
diff --git a/src/reclaim/test_reclaim.conf b/src/reclaim/test_reclaim.conf
deleted file mode 100644
index ec19056e4..000000000
--- a/src/reclaim/test_reclaim.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ test_reclaim_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-reclaim-peer-1/
5
6[dht]
7START_ON_DEMAND = YES
8
9[rest]
10START_ON_DEMAND = YES
11PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/restlog
12
13[transport]
14PLUGINS =
15
16[reclaim]
17START_ON_DEMAND = YES
18TICKET_REFRESH_INTERVAL = 15s
19#PREFIX = valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=$GNUNET_TMP/idplog
20
21[gns]
22#PREFIX = valgrind --leak-check=full --track-origins=yes
23START_ON_DEMAND = YES
24AUTO_IMPORT_PKEY = YES
25MAX_PARALLEL_BACKGROUND_QUERIES = 10
26DEFAULT_LOOKUP_TIMEOUT = 15 s
27RECORD_PUT_INTERVAL = 1 h
28ZONE_PUBLISH_TIME_WINDOW = 1 h
29DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
30
31[reclaim-rest-plugin]
32address = http://localhost:8000/#/login
33psw = mysupersecretpassword
34expiration_time = 3600
diff --git a/src/reclaim/test_reclaim.sh b/src/reclaim/test_reclaim.sh
deleted file mode 100755
index da93b10f7..000000000
--- a/src/reclaim/test_reclaim.sh
+++ /dev/null
@@ -1,31 +0,0 @@
1#!/bin/sh
2#trap "gnunet-arm -e -c test_reclaim_lookup.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27gnunet-identity -C testego -c test_reclaim.conf
28valgrind gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
29gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
30gnunet-reclaim -e testego -D -c test_reclaim.conf
31gnunet-arm -e -c test_reclaim.conf
diff --git a/src/reclaim/test_reclaim_attribute.c b/src/reclaim/test_reclaim_attribute.c
deleted file mode 100644
index f8faf8021..000000000
--- a/src/reclaim/test_reclaim_attribute.c
+++ /dev/null
@@ -1,49 +0,0 @@
1#include "platform.h"
2#include "gnunet_common.h"
3#include "gnunet_reclaim_lib.h"
4#include "gnunet_container_lib.h"
5
6int
7main (int argc, char *argv[])
8{
9 struct GNUNET_RECLAIM_AttributeList *al;
10 struct GNUNET_RECLAIM_AttributeList *al_two;
11 struct GNUNET_RECLAIM_AttributeListEntry *ale;
12 char attrname[100];
13 char attrdata[100];
14 size_t ser_len_claimed;
15 size_t ser_len_actual;
16 char *ser_data;
17 int count = 0;
18
19 al = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
20 for (int i = 0; i < 12; i++)
21 {
22 memset (attrname, 0, 100);
23 memset (attrdata, 0, 100);
24 sprintf (attrname, "attr%d", i);
25 sprintf (attrdata, "%d", i);
26 ale = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
27 ale->attribute = GNUNET_RECLAIM_attribute_new (attrname,
28 &GNUNET_RECLAIM_ID_ZERO,
29 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
30 attrdata,
31 strlen (attrdata));
32 GNUNET_CONTAINER_DLL_insert (al->list_head,
33 al->list_tail,
34 ale);
35 }
36 ser_len_claimed = GNUNET_RECLAIM_attribute_list_serialize_get_size (al);
37 ser_data = GNUNET_malloc (ser_len_claimed);
38 ser_len_actual = GNUNET_RECLAIM_attribute_list_serialize (al,
39 ser_data);
40 GNUNET_assert (ser_len_claimed == ser_len_actual);
41 al_two = GNUNET_RECLAIM_attribute_list_deserialize (ser_data,
42 ser_len_actual);
43 for (ale = al_two->list_head; NULL != ale; ale = ale->next)
44 count++;
45 GNUNET_assert (12 == count);
46 //GNUNET_assert (-1 != deser_len);
47 GNUNET_free (ser_data);
48 GNUNET_RECLAIM_attribute_list_destroy (al);
49}
diff --git a/src/reclaim/test_reclaim_attribute.sh b/src/reclaim/test_reclaim_attribute.sh
deleted file mode 100755
index 744c898ed..000000000
--- a/src/reclaim/test_reclaim_attribute.sh
+++ /dev/null
@@ -1,40 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-identity -C testego -c test_reclaim.conf
29gnunet-identity -C rpego -c test_reclaim.conf
30TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
31gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
32gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf > /dev/null 2>&1
33if test $? != 0
34then
35 echo "Failed."
36 exit 1
37fi
38
39#curl localhost:7776/reclaim/attributes/testego
40gnunet-arm -e -c test_reclaim.conf
diff --git a/src/reclaim/test_reclaim_consume.sh b/src/reclaim/test_reclaim_consume.sh
deleted file mode 100755
index 9186d3cb1..000000000
--- a/src/reclaim/test_reclaim_consume.sh
+++ /dev/null
@@ -1,43 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1>/dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-identity -C testego -c test_reclaim.conf
29gnunet-identity -C rpego -c test_reclaim.conf
30SUBJECT_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
31TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
32gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf
33gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf
34TICKET=$(gnunet-reclaim -e testego -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf | awk '{print $1}')
35gnunet-reclaim -e rpego -C $TICKET -c test_reclaim.conf >/dev/null 2>&1
36
37if test $? != 0
38then
39 "Failed."
40 exit 1
41fi
42#curl http://localhost:7776/reclaim/tickets/testego
43gnunet-arm -e -c test_reclaim.conf
diff --git a/src/reclaim/test_reclaim_defaults.conf b/src/reclaim/test_reclaim_defaults.conf
deleted file mode 100644
index a9a197dea..000000000
--- a/src/reclaim/test_reclaim_defaults.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-idp-testing/
5
6[namestore-sqlite]
7FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
8
9[namecache-sqlite]
10FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db
11
12[identity]
13# Directory where we store information about our egos
14EGODIR = $GNUNET_TEST_HOME/identity/egos/
15
16[dhtcache]
17DATABASE = heap
18
19[transport]
20PLUGINS = tcp
21
22[transport-tcp]
23BINDTO = 127.0.0.1
24
diff --git a/src/reclaim/test_reclaim_issue.sh b/src/reclaim/test_reclaim_issue.sh
deleted file mode 100755
index cfddc9407..000000000
--- a/src/reclaim/test_reclaim_issue.sh
+++ /dev/null
@@ -1,42 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2>&1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf
27#gnunet-arm -i rest -c test_reclaim.conf
28gnunet-identity -C testego -c test_reclaim.conf
29gnunet-identity -C rpego -c test_reclaim.conf
30SUBJECT_KEY=$(gnunet-identity -d -e rpego -q -c test_reclaim.conf)
31TEST_KEY=$(gnunet-identity -d -e testego -q -c test_reclaim.conf)
32gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf > /dev/null 2>&1
33gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf > /dev/null 2>&1
34#gnunet-reclaim -e testego -D -c test_reclaim.conf
35gnunet-reclaim -e testego -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf > /dev/null 2>&1
36if test $? != 0
37then
38 echo "Failed."
39 exit 1
40fi
41#curl http://localhost:7776/reclaim/attributes/testego
42gnunet-arm -e -c test_reclaim.conf
diff --git a/src/reclaim/test_reclaim_revoke.sh b/src/reclaim/test_reclaim_revoke.sh
deleted file mode 100755
index da091a1ee..000000000
--- a/src/reclaim/test_reclaim_revoke.sh
+++ /dev/null
@@ -1,65 +0,0 @@
1#!/bin/bash
2trap "gnunet-arm -e -c test_reclaim.conf" SIGINT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f`
17
18# (1) PKEY1.user -> PKEY2.resu.user
19# (2) PKEY2.resu -> PKEY3
20# (3) PKEY3.user -> PKEY4
21
22
23which timeout >/dev/null 2&>1 && DO_TIMEOUT="timeout 30"
24
25TEST_ATTR="test"
26gnunet-arm -s -c test_reclaim.conf >/dev/null 2&>1
27gnunet-identity -C alice -c test_reclaim.conf
28gnunet-identity -C bob -c test_reclaim.conf
29gnunet-identity -C eve -c test_reclaim.conf
30ALICE_KEY=$(gnunet-identity -d -e alice -q -c test_reclaim.conf)
31BOB_KEY=$(gnunet-identity -d -e bob -q -c test_reclaim.conf)
32EVE_KEY=$(gnunet-identity -d -e eve -q -c test_reclaim.conf)
33gnunet-reclaim -e alice -E 15s -a email -V john@doe.gnu -c test_reclaim.conf
34gnunet-reclaim -e alice -E 15s -a name -V John -c test_reclaim.conf
35TICKET_BOB=$(gnunet-reclaim -e alice -i "email,name" -r $BOB_KEY -c test_reclaim.conf | awk '{print $1}')
36#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf
37TICKET_EVE=$(gnunet-reclaim -e alice -i "email" -r $EVE_KEY -c test_reclaim.conf | awk '{print $1}')
38gnunet-namestore -z alice -D
39echo "Revoking $TICKET"
40gnunet-reclaim -e alice -R $TICKET_EVE -c test_reclaim.conf
41gnunet-namestore -z alice -D
42sleep 16
43echo "Consuming $TICKET"
44
45gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf
46if test $? = 0
47then
48 echo "Eve can still resolve attributes..."
49 gnunet-arm -e -c test_reclaim.conf
50 exit 1
51fi
52
53gnunet-arm -e -c test_reclaim.conf
54gnunet-arm -s -c test_reclaim.conf >/dev/null 2&>1
55
56gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf
57#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf >/dev/null 2&>1
58if test $? != 0
59then
60 echo "Bob cannot resolve attributes..."
61 gnunet-arm -e -c test_reclaim.conf
62 exit 1
63fi
64
65gnunet-arm -e -c test_reclaim.conf