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.am141
-rw-r--r--src/reclaim/gnunet-reclaim.c560
-rw-r--r--src/reclaim/gnunet-service-reclaim.c2786
-rw-r--r--src/reclaim/jwt.c1
-rw-r--r--src/reclaim/oidc_helper.c440
-rw-r--r--src/reclaim/oidc_helper.h109
-rw-r--r--src/reclaim/plugin_gnsrecord_reclaim.c271
-rw-r--r--src/reclaim/plugin_reclaim_sqlite.c734
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c2171
-rw-r--r--src/reclaim/plugin_rest_reclaim.c1253
-rw-r--r--src/reclaim/reclaim.conf23
-rw-r--r--src/reclaim/reclaim.h410
-rw-r--r--src/reclaim/reclaim_api.c1383
-rwxr-xr-xsrc/reclaim/test_reclaim.sh31
-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
20 files changed, 10529 insertions, 0 deletions
diff --git a/src/reclaim/.gitignore b/src/reclaim/.gitignore
new file mode 100644
index 000000000..ef77fccdc
--- /dev/null
+++ b/src/reclaim/.gitignore
@@ -0,0 +1,2 @@
1gnunet-service-identity-provider
2gnunet-identity-token
diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am
new file mode 100644
index 000000000..2ee43d21a
--- /dev/null
+++ b/src/reclaim/Makefile.am
@@ -0,0 +1,141 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4 plugindir = $(libdir)/gnunet
5
6if MINGW
7 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
8endif
9
10if USE_COVERAGE
11 AM_CFLAGS = --coverage -O0
12 XLIB = -lgcov
13endif
14
15if HAVE_SQLITE
16SQLITE_PLUGIN = libgnunet_plugin_reclaim_sqlite.la
17endif
18
19EXTRA_DIST = \
20 test_reclaim_defaults.conf \
21 test_reclaim.conf \
22 $(check_SCRIPTS)
23
24pkgcfgdir= $(pkgdatadir)/config.d/
25
26libexecdir= $(pkglibdir)/libexec/
27
28pkgcfg_DATA = \
29 reclaim.conf
30
31lib_LTLIBRARIES = \
32 libgnunetreclaim.la
33plugin_LTLIBRARIES = \
34 libgnunet_plugin_rest_reclaim.la \
35 libgnunet_plugin_rest_openid_connect.la \
36 libgnunet_plugin_gnsrecord_reclaim.la \
37 $(SQLITE_PLUGIN)
38
39bin_PROGRAMS = \
40 gnunet-reclaim
41
42libexec_PROGRAMS = \
43 gnunet-service-reclaim
44
45libgnunet_plugin_gnsrecord_reclaim_la_SOURCES = \
46 plugin_gnsrecord_reclaim.c
47libgnunet_plugin_gnsrecord_reclaim_la_LIBADD = \
48 $(top_builddir)/src/util/libgnunetutil.la \
49 $(LTLIBINTL)
50libgnunet_plugin_gnsrecord_reclaim_la_LDFLAGS = \
51 $(GN_PLUGIN_LDFLAGS)
52
53libgnunet_plugin_reclaim_sqlite_la_SOURCES = \
54 plugin_reclaim_sqlite.c
55libgnunet_plugin_reclaim_sqlite_la_LIBADD = \
56 libgnunetreclaim.la \
57 $(top_builddir)/src/sq/libgnunetsq.la \
58 $(top_builddir)/src/statistics/libgnunetstatistics.la \
59 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
60 $(LTLIBINTL)
61libgnunet_plugin_reclaim_sqlite_la_LDFLAGS = \
62 $(GN_PLUGIN_LDFLAGS)
63
64
65
66gnunet_service_reclaim_SOURCES = \
67 gnunet-service-reclaim.c
68gnunet_service_reclaim_LDADD = \
69 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
70 $(top_builddir)/src/util/libgnunetutil.la \
71 $(top_builddir)/src/namestore/libgnunetnamestore.la \
72 $(top_builddir)/src/identity/libgnunetidentity.la \
73 $(top_builddir)/src/statistics/libgnunetstatistics.la \
74 $(top_builddir)/src/abe/libgnunetabe.la \
75 $(top_builddir)/src/credential/libgnunetcredential.la \
76 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
77 libgnunetreclaim.la \
78 $(top_builddir)/src/gns/libgnunetgns.la \
79 $(GN_LIBINTL)
80
81libgnunetreclaim_la_SOURCES = \
82 reclaim_api.c \
83 reclaim.h
84libgnunetreclaim_la_LIBADD = \
85 $(top_builddir)/src/util/libgnunetutil.la \
86 $(GN_LIBINTL) $(XLIB)
87libgnunetreclaim_la_LDFLAGS = \
88 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
89 -version-info 0:0:0
90
91libgnunet_plugin_rest_reclaim_la_SOURCES = \
92 plugin_rest_reclaim.c
93libgnunet_plugin_rest_reclaim_la_LIBADD = \
94 $(top_builddir)/src/identity/libgnunetidentity.la \
95 libgnunetreclaim.la \
96 $(top_builddir)/src/rest/libgnunetrest.la \
97 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
98 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
99 $(top_builddir)/src/namestore/libgnunetnamestore.la \
100 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
101 $(LTLIBINTL) -ljansson -lmicrohttpd
102libgnunet_plugin_rest_reclaim_la_LDFLAGS = \
103 $(GN_PLUGIN_LDFLAGS)
104
105libgnunet_plugin_rest_openid_connect_la_SOURCES = \
106 plugin_rest_openid_connect.c \
107 oidc_helper.c
108libgnunet_plugin_rest_openid_connect_la_LIBADD = \
109 $(top_builddir)/src/identity/libgnunetidentity.la \
110 libgnunetreclaim.la \
111 $(top_builddir)/src/rest/libgnunetrest.la \
112 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
113 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
114 $(top_builddir)/src/namestore/libgnunetnamestore.la \
115 $(top_builddir)/src/gns/libgnunetgns.la \
116 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
117 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
118 $(LTLIBINTL) -ljansson -lmicrohttpd
119libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \
120 $(GN_PLUGIN_LDFLAGS)
121
122gnunet_reclaim_SOURCES = \
123 gnunet-reclaim.c
124gnunet_reclaim_LDADD = \
125 $(top_builddir)/src/util/libgnunetutil.la \
126 $(top_builddir)/src/namestore/libgnunetnamestore.la \
127 libgnunetreclaim.la \
128 $(top_builddir)/src/identity/libgnunetidentity.la \
129 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
130 $(GN_LIBINTL)
131
132check_SCRIPTS = \
133 test_reclaim_attribute.sh \
134 test_reclaim_issue.sh \
135 test_reclaim_consume.sh \
136 test_reclaim_revoke.sh
137
138if ENABLE_TEST_RUN
139 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
140 TESTS = $(check_SCRIPTS)
141endif
diff --git a/src/reclaim/gnunet-reclaim.c b/src/reclaim/gnunet-reclaim.c
new file mode 100644
index 000000000..677e9f49f
--- /dev/null
+++ b/src/reclaim/gnunet-reclaim.c
@@ -0,0 +1,560 @@
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/**
19 * @author Martin Schanzenbach
20 * @file src/reclaim/gnunet-reclaim.c
21 * @brief Identity Provider utility
22 *
23 */
24
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_namestore_service.h"
28#include "gnunet_reclaim_service.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_signatures.h"
31
32/**
33 * return value
34 */
35static int ret;
36
37/**
38 * List attribute flag
39 */
40static int list;
41
42/**
43 * Relying party
44 */
45static char* rp;
46
47/**
48 * The attribute
49 */
50static char* attr_name;
51
52/**
53 * Attribute value
54 */
55static char* attr_value;
56
57/**
58 * Attributes to issue
59 */
60static char* issue_attrs;
61
62/**
63 * Ticket to consume
64 */
65static char* consume_ticket;
66
67/**
68 * Attribute type
69 */
70static char* type_str;
71
72/**
73 * Ticket to revoke
74 */
75static char* revoke_ticket;
76
77/**
78 * Ego name
79 */
80static char* ego_name;
81
82/**
83 * Identity handle
84 */
85static struct GNUNET_IDENTITY_Handle *identity_handle;
86
87/**
88 * reclaim handle
89 */
90static struct GNUNET_RECLAIM_Handle *reclaim_handle;
91
92/**
93 * reclaim operation
94 */
95static struct GNUNET_RECLAIM_Operation *reclaim_op;
96
97/**
98 * Attribute iterator
99 */
100static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator;
101
102/**
103 * Master ABE key
104 */
105static struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
106
107/**
108 * ego private key
109 */
110static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey;
111
112/**
113 * rp public key
114 */
115static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key;
116
117/**
118 * Ticket to consume
119 */
120static struct GNUNET_RECLAIM_Ticket ticket;
121
122/**
123 * Attribute list
124 */
125static struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
126
127/**
128 * Attribute expiration interval
129 */
130static struct GNUNET_TIME_Relative exp_interval;
131
132/**
133 * Timeout task
134 */
135static struct GNUNET_SCHEDULER_Task *timeout;
136
137/**
138 * Cleanup task
139 */
140static struct GNUNET_SCHEDULER_Task *cleanup_task;
141
142/**
143 * Claim to store
144 */
145struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
146
147static void
148do_cleanup(void *cls)
149{
150 cleanup_task = NULL;
151 if (NULL != timeout)
152 GNUNET_SCHEDULER_cancel (timeout);
153 if (NULL != reclaim_op)
154 GNUNET_RECLAIM_cancel (reclaim_op);
155 if (NULL != attr_iterator)
156 GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
157 if (NULL != reclaim_handle)
158 GNUNET_RECLAIM_disconnect (reclaim_handle);
159 if (NULL != identity_handle)
160 GNUNET_IDENTITY_disconnect (identity_handle);
161 if (NULL != abe_key)
162 GNUNET_free (abe_key);
163 if (NULL != attr_list)
164 GNUNET_free (attr_list);
165}
166
167static void
168ticket_issue_cb (void* cls,
169 const struct GNUNET_RECLAIM_Ticket *ticket)
170{
171 char* ticket_str;
172 reclaim_op = NULL;
173 if (NULL != ticket) {
174 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
175 sizeof (struct GNUNET_RECLAIM_Ticket));
176 printf("%s\n",
177 ticket_str);
178 GNUNET_free (ticket_str);
179 }
180 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
181}
182
183static void
184store_attr_cont (void *cls,
185 int32_t success,
186 const char*emsg)
187{
188 reclaim_op = NULL;
189 if (GNUNET_SYSERR == success) {
190 fprintf (stderr,
191 "%s\n", emsg);
192 }
193 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
194}
195
196static void
197process_attrs (void *cls,
198 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
199 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
200{
201 char *value_str;
202 const char* attr_type;
203
204 if (NULL == identity)
205 {
206 reclaim_op = NULL;
207 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
208 return;
209 }
210 if (NULL == attr)
211 {
212 ret = 1;
213 return;
214 }
215 value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
216 attr->data,
217 attr->data_size);
218 attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
219 fprintf (stdout,
220 "%s: %s [%s,v%u]\n", attr->name, value_str, attr_type, attr->version);
221}
222
223
224static void
225iter_error (void *cls)
226{
227 attr_iterator = NULL;
228 fprintf (stderr,
229 "Failed to iterate over attributes\n");
230 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
231}
232
233static void
234timeout_task (void *cls)
235{
236 timeout = NULL;
237 ret = 1;
238 fprintf (stderr,
239 "Timeout\n");
240 if (NULL == cleanup_task)
241 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
242}
243
244static void
245process_rvk (void *cls, int success, const char* msg)
246{
247 reclaim_op = NULL;
248 if (GNUNET_OK != success)
249 {
250 fprintf (stderr,
251 "Revocation failed.\n");
252 ret = 1;
253 }
254 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
255}
256
257static void
258iter_finished (void *cls)
259{
260 char *data;
261 size_t data_size;
262 int type;
263
264 attr_iterator = NULL;
265 if (list)
266 {
267 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
268 return;
269 }
270
271 if (issue_attrs)
272 {
273 reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
274 pkey,
275 &rp_key,
276 attr_list,
277 &ticket_issue_cb,
278 NULL);
279 return;
280 }
281 if (consume_ticket)
282 {
283 reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
284 pkey,
285 &ticket,
286 &process_attrs,
287 NULL);
288 timeout = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10),
289 &timeout_task,
290 NULL);
291 return;
292 }
293 if (revoke_ticket)
294 {
295 reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
296 pkey,
297 &ticket,
298 &process_rvk,
299 NULL);
300 return;
301 }
302 if (attr_name)
303 {
304 if (NULL == type_str)
305 type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
306 else
307 type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
308
309 GNUNET_assert (GNUNET_SYSERR != GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
310 attr_value,
311 (void**)&data,
312 &data_size));
313 if (NULL != claim)
314 {
315 claim->type = type;
316 claim->data = data;
317 claim->data_size = data_size;
318 }
319 else
320 {
321 claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name,
322 type,
323 data,
324 data_size);
325 }
326 reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
327 pkey,
328 claim,
329 &exp_interval,
330 &store_attr_cont,
331 NULL);
332 GNUNET_free (data);
333 GNUNET_free (claim);
334 return;
335 }
336 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
337}
338
339static void
340iter_cb (void *cls,
341 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
342 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
343{
344 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
345 char *attrs_tmp;
346 char *attr_str;
347 const char *attr_type;
348
349 if ((NULL != attr_name) && (NULL != claim))
350 {
351 if (0 == strcasecmp (attr_name, attr->name))
352 {
353 claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
354 attr->type,
355 attr->data,
356 attr->data_size);
357 }
358 }
359 else if (issue_attrs)
360 {
361 attrs_tmp = GNUNET_strdup (issue_attrs);
362 attr_str = strtok (attrs_tmp, ",");
363 while (NULL != attr_str) {
364 if (0 != strcasecmp (attr_str, attr->name)) {
365 attr_str = strtok (NULL, ",");
366 continue;
367 }
368 le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
369 le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
370 attr->type,
371 attr->data,
372 attr->data_size);
373 le->claim->version = attr->version;
374 GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
375 attr_list->list_tail,
376 le);
377 break;
378 }
379 GNUNET_free (attrs_tmp);
380 }
381 else if (list)
382 {
383 attr_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
384 attr->data,
385 attr->data_size);
386 attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
387 fprintf (stdout,
388 "%s: %s [%s,v%u]\n", attr->name, attr_str, attr_type, attr->version);
389 }
390 GNUNET_RECLAIM_get_attributes_next (attr_iterator);
391}
392
393static void
394start_get_attributes ()
395{
396 if (NULL == pkey)
397 {
398 fprintf (stderr,
399 "Ego %s not found\n", ego_name);
400 cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
401 return;
402 }
403
404 if (NULL != rp)
405 GNUNET_CRYPTO_ecdsa_public_key_from_string (rp,
406 strlen (rp),
407 &rp_key);
408 if (NULL != consume_ticket)
409 GNUNET_STRINGS_string_to_data (consume_ticket,
410 strlen (consume_ticket),
411 &ticket,
412 sizeof (struct GNUNET_RECLAIM_Ticket));
413 if (NULL != revoke_ticket)
414 GNUNET_STRINGS_string_to_data (revoke_ticket,
415 strlen (revoke_ticket),
416 &ticket,
417 sizeof (struct GNUNET_RECLAIM_Ticket));
418
419 attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
420 claim = NULL;
421 attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
422 pkey,
423 &iter_error,
424 NULL,
425 &iter_cb,
426 NULL,
427 &iter_finished,
428 NULL);
429
430
431}
432
433static int init = GNUNET_YES;
434
435static void
436ego_cb (void *cls,
437 struct GNUNET_IDENTITY_Ego *ego,
438 void **ctx,
439 const char *name)
440{
441 if (NULL == name) {
442 if (GNUNET_YES == init) {
443 init = GNUNET_NO;
444 start_get_attributes();
445 }
446 return;
447 }
448 if (0 != strcmp (name, ego_name))
449 return;
450 pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
451}
452
453
454static void
455run (void *cls,
456 char *const *args,
457 const char *cfgfile,
458 const struct GNUNET_CONFIGURATION_Handle *c)
459{
460 ret = 0;
461 if (NULL == ego_name)
462 {
463 ret = 1;
464 fprintf (stderr,
465 _("Ego is required\n"));
466 return;
467 }
468
469 if ( (NULL == attr_value) && (NULL != attr_name) )
470 {
471 ret = 1;
472 fprintf (stderr,
473 _("Attribute value missing!\n"));
474 return;
475 }
476
477 if ( (NULL == rp) && (NULL != issue_attrs) )
478 {
479 ret = 1;
480 fprintf (stderr,
481 _("Requesting party key is required!\n"));
482 return;
483 }
484
485 reclaim_handle = GNUNET_RECLAIM_connect (c);
486 //Get Ego
487 identity_handle = GNUNET_IDENTITY_connect (c,
488 &ego_cb,
489 NULL);
490
491
492}
493
494
495int
496main(int argc, char *const argv[])
497{
498 exp_interval = GNUNET_TIME_UNIT_HOURS;
499 struct GNUNET_GETOPT_CommandLineOption options[] = {
500
501 GNUNET_GETOPT_option_string ('a',
502 "add",
503 NULL,
504 gettext_noop ("Add attribute"),
505 &attr_name),
506
507 GNUNET_GETOPT_option_string ('V',
508 "value",
509 NULL,
510 gettext_noop ("Attribute value"),
511 &attr_value),
512 GNUNET_GETOPT_option_string ('e',
513 "ego",
514 NULL,
515 gettext_noop ("Ego"),
516 &ego_name),
517 GNUNET_GETOPT_option_string ('r',
518 "rp",
519 NULL,
520 gettext_noop ("Audience (relying party)"),
521 &rp),
522 GNUNET_GETOPT_option_flag ('D',
523 "dump",
524 gettext_noop ("List attributes for Ego"),
525 &list),
526 GNUNET_GETOPT_option_string ('i',
527 "issue",
528 NULL,
529 gettext_noop ("Issue a ticket"),
530 &issue_attrs),
531 GNUNET_GETOPT_option_string ('C',
532 "consume",
533 NULL,
534 gettext_noop ("Consume a ticket"),
535 &consume_ticket),
536 GNUNET_GETOPT_option_string ('R',
537 "revoke",
538 NULL,
539 gettext_noop ("Revoke a ticket"),
540 &revoke_ticket),
541 GNUNET_GETOPT_option_string ('t',
542 "type",
543 NULL,
544 gettext_noop ("Type of attribute"),
545 &type_str),
546 GNUNET_GETOPT_option_relative_time ('E',
547 "expiration",
548 NULL,
549 gettext_noop ("Expiration interval of the attribute"),
550 &exp_interval),
551
552 GNUNET_GETOPT_OPTION_END
553 };
554 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "ct",
555 "ct", options,
556 &run, NULL))
557 return 1;
558 else
559 return ret;
560}
diff --git a/src/reclaim/gnunet-service-reclaim.c b/src/reclaim/gnunet-service-reclaim.c
new file mode 100644
index 000000000..3321a79d8
--- /dev/null
+++ b/src/reclaim/gnunet-service-reclaim.c
@@ -0,0 +1,2786 @@
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/**
19 * @author Martin Schanzenbach
20 * @file src/reclaim/gnunet-service-reclaim.c
21 * @brief reclaim Service
22 *
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_constants.h"
27#include "gnunet_protocols.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_namestore_service.h"
31#include "gnunet_abe_lib.h"
32#include "gnunet_credential_service.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_gns_service.h"
35#include "gnunet_reclaim_plugin.h"
36#include "gnunet_reclaim_attribute_lib.h"
37#include "gnunet_signatures.h"
38#include "reclaim.h"
39
40/**
41 * First pass state
42 */
43#define STATE_INIT 0
44
45/**
46 * Normal operation state
47 */
48#define STATE_POST_INIT 1
49
50/**
51 * Minimum interval between updates
52 */
53#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
54
55/**
56 * Standard token expiration time
57 */
58#define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
59
60/**
61 * Identity handle
62 */
63static struct GNUNET_IDENTITY_Handle *identity_handle;
64
65/**
66 * Database handle
67 */
68static struct GNUNET_RECLAIM_PluginFunctions *TKT_database;
69
70/**
71 * Name of DB plugin
72 */
73static char *db_lib_name;
74
75/**
76 * Token expiration interval
77 */
78static struct GNUNET_TIME_Relative token_expiration_interval;
79
80/**
81 * Namestore handle
82 */
83static struct GNUNET_NAMESTORE_Handle *ns_handle;
84
85/**
86 * GNS handle
87 */
88static struct GNUNET_GNS_Handle *gns_handle;
89
90/**
91 * Credential handle
92 */
93static struct GNUNET_CREDENTIAL_Handle *credential_handle;
94
95/**
96 * Namestore qe
97 */
98static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
99
100/**
101 * Namestore iterator
102 */
103static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
104
105/**
106 * Timeout task
107 */
108static struct GNUNET_SCHEDULER_Task *timeout_task;
109
110/**
111 * Update task
112 */
113static struct GNUNET_SCHEDULER_Task *update_task;
114
115
116/**
117 * Currently processed token
118 */
119static struct IdentityToken *token;
120
121/**
122 * Label for currently processed token
123 */
124static char* label;
125
126/**
127 * Scopes for processed token
128 */
129static char* scopes;
130
131/**
132 * Handle to the statistics service.
133 */
134static struct GNUNET_STATISTICS_Handle *stats;
135
136/**
137 * Our configuration.
138 */
139static const struct GNUNET_CONFIGURATION_Handle *cfg;
140
141/**
142 * An idp client
143 */
144struct IdpClient;
145
146/**
147 * A ticket iteration operation.
148 */
149struct TicketIteration
150{
151 /**
152 * DLL
153 */
154 struct TicketIteration *next;
155
156 /**
157 * DLL
158 */
159 struct TicketIteration *prev;
160
161 /**
162 * Client which intiated this zone iteration
163 */
164 struct IdpClient *client;
165
166 /**
167 * Key of the identity we are iterating over.
168 */
169 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
170
171 /**
172 * Identity is audience
173 */
174 uint32_t is_audience;
175
176 /**
177 * The operation id fot the iteration in the response for the client
178 */
179 uint32_t r_id;
180
181 /**
182 * Offset of the iteration used to address next result of the
183 * iteration in the store
184 *
185 * Initialy set to 0 in handle_iteration_start
186 * Incremented with by every call to handle_iteration_next
187 */
188 uint32_t offset;
189
190};
191
192
193
194/**
195 * Callback after an ABE bootstrap
196 *
197 * @param cls closure
198 * @param abe_key the ABE key that exists or was created
199 */
200typedef void
201(*AbeBootstrapResult) (void *cls,
202 struct GNUNET_ABE_AbeMasterKey *abe_key);
203
204
205struct AbeBootstrapHandle
206{
207 /**
208 * Function to call when finished
209 */
210 AbeBootstrapResult proc;
211
212 /**
213 * Callback closure
214 */
215 char *proc_cls;
216
217 /**
218 * Key of the zone we are iterating over.
219 */
220 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
221
222 /**
223 * Namestore Queue Entry
224 */
225 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
226
227 /**
228 * The issuer egos ABE master key
229 */
230 struct GNUNET_ABE_AbeMasterKey *abe_key;
231};
232
233/**
234 * An attribute iteration operation.
235 */
236struct AttributeIterator
237{
238 /**
239 * Next element in the DLL
240 */
241 struct AttributeIterator *next;
242
243 /**
244 * Previous element in the DLL
245 */
246 struct AttributeIterator *prev;
247
248 /**
249 * IDP client which intiated this zone iteration
250 */
251 struct IdpClient *client;
252
253 /**
254 * Key of the zone we are iterating over.
255 */
256 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
257
258 /**
259 * The issuer egos ABE master key
260 */
261 struct GNUNET_ABE_AbeMasterKey *abe_key;
262
263 /**
264 * Namestore iterator
265 */
266 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
267
268 /**
269 * The operation id fot the zone iteration in the response for the client
270 */
271 uint32_t request_id;
272
273};
274
275
276
277/**
278 * An idp client
279 */
280struct IdpClient
281{
282
283 /**
284 * The client
285 */
286 struct GNUNET_SERVICE_Client *client;
287
288 /**
289 * Message queue for transmission to @e client
290 */
291 struct GNUNET_MQ_Handle *mq;
292
293 /**
294 * Head of the DLL of
295 * Attribute iteration operations in
296 * progress initiated by this client
297 */
298 struct AttributeIterator *attr_iter_head;
299
300 /**
301 * Tail of the DLL of
302 * Attribute iteration operations
303 * in progress initiated by this client
304 */
305 struct AttributeIterator *attr_iter_tail;
306
307 /**
308 * Head of DLL of ticket iteration ops
309 */
310 struct TicketIteration *ticket_iter_head;
311
312 /**
313 * Tail of DLL of ticket iteration ops
314 */
315 struct TicketIteration *ticket_iter_tail;
316
317 /**
318 * Head of DLL of ticket revocation ops
319 */
320 struct TicketRevocationHandle *revoke_op_head;
321
322 /**
323 * Tail of DLL of ticket revocation ops
324 */
325 struct TicketRevocationHandle *revoke_op_tail;
326
327 /**
328 * Head of DLL of ticket issue ops
329 */
330 struct TicketIssueHandle *issue_op_head;
331
332 /**
333 * Tail of DLL of ticket issue ops
334 */
335 struct TicketIssueHandle *issue_op_tail;
336
337 /**
338 * Head of DLL of ticket consume ops
339 */
340 struct ConsumeTicketHandle *consume_op_head;
341
342 /**
343 * Tail of DLL of ticket consume ops
344 */
345 struct ConsumeTicketHandle *consume_op_tail;
346
347 /**
348 * Head of DLL of attribute store ops
349 */
350 struct AttributeStoreHandle *store_op_head;
351
352 /**
353 * Tail of DLL of attribute store ops
354 */
355 struct AttributeStoreHandle *store_op_tail;
356
357};
358
359struct AttributeStoreHandle
360{
361 /**
362 * DLL
363 */
364 struct AttributeStoreHandle *next;
365
366 /**
367 * DLL
368 */
369 struct AttributeStoreHandle *prev;
370
371 /**
372 * Client connection
373 */
374 struct IdpClient *client;
375
376 /**
377 * Identity
378 */
379 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
380
381 /**
382 * Identity pubkey
383 */
384 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
385
386 /**
387 * The issuer egos ABE master key
388 */
389 struct GNUNET_ABE_AbeMasterKey *abe_key;
390
391 /**
392 * QueueEntry
393 */
394 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
395
396 /**
397 * The attribute to store
398 */
399 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
400
401 /**
402 * The attribute expiration interval
403 */
404 struct GNUNET_TIME_Relative exp;
405
406 /**
407 * request id
408 */
409 uint32_t r_id;
410};
411
412
413/* Prototype */
414struct ParallelLookup;
415
416struct ConsumeTicketHandle
417{
418 /**
419 * DLL
420 */
421 struct ConsumeTicketHandle *next;
422
423 /**
424 * DLL
425 */
426 struct ConsumeTicketHandle *prev;
427
428 /**
429 * Client connection
430 */
431 struct IdpClient *client;
432
433 /**
434 * Ticket
435 */
436 struct GNUNET_RECLAIM_Ticket ticket;
437
438 /**
439 * LookupRequest
440 */
441 struct GNUNET_GNS_LookupRequest *lookup_request;
442
443 /**
444 * Audience Key
445 */
446 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
447
448 /**
449 * Audience Key
450 */
451 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
452
453 /**
454 * Lookup DLL
455 */
456 struct ParallelLookup *parallel_lookups_head;
457
458 /**
459 * Lookup DLL
460 */
461 struct ParallelLookup *parallel_lookups_tail;
462
463 /**
464 * Kill task
465 */
466 struct GNUNET_SCHEDULER_Task *kill_task;
467
468 /**
469 * The ABE key
470 */
471 struct GNUNET_ABE_AbeKey *key;
472
473 /**
474 * Attributes
475 */
476 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
477
478 /**
479 * Lookup time
480 */
481 struct GNUNET_TIME_Absolute lookup_start_time;
482
483 /**
484 * request id
485 */
486 uint32_t r_id;
487};
488
489/**
490 * Handle for a parallel GNS lookup job
491 */
492struct ParallelLookup
493{
494 /* DLL */
495 struct ParallelLookup *next;
496
497 /* DLL */
498 struct ParallelLookup *prev;
499
500 /* The GNS request */
501 struct GNUNET_GNS_LookupRequest *lookup_request;
502
503 /* The handle the return to */
504 struct ConsumeTicketHandle *handle;
505
506 /**
507 * Lookup time
508 */
509 struct GNUNET_TIME_Absolute lookup_start_time;
510
511 /* The label to look up */
512 char *label;
513};
514
515/**
516 * Ticket revocation request handle
517 */
518struct TicketRevocationHandle
519{
520 /**
521 * DLL
522 */
523 struct TicketRevocationHandle *prev;
524
525 /**
526 * DLL
527 */
528 struct TicketRevocationHandle *next;
529
530 /**
531 * Client connection
532 */
533 struct IdpClient *client;
534
535 /**
536 * Attributes to reissue
537 */
538 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
539
540 /**
541 * Attributes to revoke
542 */
543 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *rvk_attrs;
544
545 /**
546 * Issuer Key
547 */
548 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
549
550 /**
551 * Ticket to issue
552 */
553 struct GNUNET_RECLAIM_Ticket ticket;
554
555 /**
556 * QueueEntry
557 */
558 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
559
560 /**
561 * Namestore iterator
562 */
563 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
564
565 /**
566 * The ABE master key
567 */
568 struct GNUNET_ABE_AbeMasterKey *abe_key;
569
570 /**
571 * Offset
572 */
573 uint32_t offset;
574
575 /**
576 * request id
577 */
578 uint32_t r_id;
579};
580
581
582
583/**
584 * Ticket issue request handle
585 */
586struct TicketIssueHandle
587{
588 /**
589 * DLL
590 */
591 struct TicketIssueHandle *prev;
592
593 /**
594 * DLL
595 */
596 struct TicketIssueHandle *next;
597
598 /**
599 * Client connection
600 */
601 struct IdpClient *client;
602
603 /**
604 * Attributes to issue
605 */
606 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
607
608 /**
609 * Issuer Key
610 */
611 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
612
613 /**
614 * Ticket to issue
615 */
616 struct GNUNET_RECLAIM_Ticket ticket;
617
618 /**
619 * QueueEntry
620 */
621 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
622
623 /**
624 * request id
625 */
626 uint32_t r_id;
627};
628
629
630/**
631 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
632 *
633 */
634struct EgoEntry
635{
636 /**
637 * DLL
638 */
639 struct EgoEntry *next;
640
641 /**
642 * DLL
643 */
644 struct EgoEntry *prev;
645
646 /**
647 * Ego handle
648 */
649 struct GNUNET_IDENTITY_Ego *ego;
650
651 /**
652 * Attribute map. Contains the attributes as json_t
653 */
654 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
655
656};
657
658/**
659 * Cleanup task
660 */
661static void
662cleanup()
663{
664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665 "Cleaning up\n");
666
667 if (NULL != stats)
668 {
669 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
670 stats = NULL;
671 }
672 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
673 TKT_database));
674 GNUNET_free (db_lib_name);
675 db_lib_name = NULL;
676 if (NULL != timeout_task)
677 GNUNET_SCHEDULER_cancel (timeout_task);
678 if (NULL != update_task)
679 GNUNET_SCHEDULER_cancel (update_task);
680 if (NULL != identity_handle)
681 GNUNET_IDENTITY_disconnect (identity_handle);
682 if (NULL != gns_handle)
683 GNUNET_GNS_disconnect (gns_handle);
684 if (NULL != credential_handle)
685 GNUNET_CREDENTIAL_disconnect (credential_handle);
686 if (NULL != ns_it)
687 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
688 if (NULL != ns_qe)
689 GNUNET_NAMESTORE_cancel (ns_qe);
690 if (NULL != ns_handle)
691 GNUNET_NAMESTORE_disconnect (ns_handle);
692 GNUNET_free_non_null (token);
693 GNUNET_free_non_null (label);
694
695}
696
697/**
698 * Shutdown task
699 *
700 * @param cls NULL
701 */
702static void
703do_shutdown (void *cls)
704{
705 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
706 "Shutting down...\n");
707 cleanup();
708}
709
710/**
711 * Finished storing newly bootstrapped ABE key
712 */
713static void
714bootstrap_store_cont (void *cls,
715 int32_t success,
716 const char *emsg)
717{
718 struct AbeBootstrapHandle *abh = cls;
719 if (GNUNET_SYSERR == success)
720 {
721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
722 "Failed to bootstrap ABE master %s\n",
723 emsg);
724 abh->proc (abh->proc_cls, NULL);
725 GNUNET_free (abh->abe_key);
726 GNUNET_free (abh);
727 return;
728 }
729 abh->proc (abh->proc_cls, abh->abe_key);
730 GNUNET_free (abh);
731}
732
733/**
734 * Generates and stores a new ABE key
735 */
736static void
737bootstrap_store_task (void *cls)
738{
739 struct AbeBootstrapHandle *abh = cls;
740 struct GNUNET_GNSRECORD_Data rd[1];
741 char *key;
742
743 rd[0].data_size = GNUNET_ABE_cpabe_serialize_master_key (abh->abe_key,
744 (void**)&key);
745 rd[0].data = key;
746 rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER;
747 rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
748 rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane?
749 abh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
750 &abh->identity,
751 "+",
752 1,
753 rd,
754 &bootstrap_store_cont,
755 abh);
756 GNUNET_free (key);
757}
758
759/**
760 * Error checking for ABE master
761 */
762static void
763bootstrap_abe_error (void *cls)
764{
765 struct AbeBootstrapHandle *abh = cls;
766 abh->proc (abh->proc_cls, NULL);
767 GNUNET_free (abh);
768}
769
770
771/**
772 * Handle ABE lookup in namestore
773 */
774static void
775bootstrap_abe_result (void *cls,
776 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
777 const char *label,
778 unsigned int rd_count,
779 const struct GNUNET_GNSRECORD_Data *rd)
780{
781 struct AbeBootstrapHandle *abh = cls;
782 struct GNUNET_ABE_AbeMasterKey *abe_key;
783
784 for (uint32_t i=0;i<rd_count;i++) {
785 if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type)
786 continue;
787 abe_key = GNUNET_ABE_cpabe_deserialize_master_key (rd[i].data,
788 rd[i].data_size);
789 abh->proc (abh->proc_cls, abe_key);
790 GNUNET_free (abh);
791 return;
792 }
793
794 //No ABE master found, bootstrapping...
795 abh->abe_key = GNUNET_ABE_cpabe_create_master_key ();
796 GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh);
797}
798
799/**
800 * Bootstrap ABE master if it does not yet exists.
801 * Will call the AbeBootstrapResult processor when done.
802 * will always recreate the ABE key of GNUNET_YES == recreate
803 */
804static void
805bootstrap_abe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
806 AbeBootstrapResult proc,
807 void* cls,
808 int recreate)
809{
810 struct AbeBootstrapHandle *abh;
811
812 abh = GNUNET_new (struct AbeBootstrapHandle);
813 abh->proc = proc;
814 abh->proc_cls = cls;
815 abh->identity = *identity;
816 if (GNUNET_YES == recreate)
817 {
818 abh->abe_key = GNUNET_ABE_cpabe_create_master_key ();
819 GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh);
820 } else {
821 abh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
822 identity,
823 "+",
824 &bootstrap_abe_error,
825 abh,
826 &bootstrap_abe_result,
827 abh);
828 }
829}
830
831
832
833static int
834create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
835 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
836 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
837{
838 struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
839
840 GNUNET_CRYPTO_hash_to_enc (new_key_hash,
841 &new_key_hash_str);
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
843 static const char ctx_key[] = "gnuid-aes-ctx-key";
844 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
845 new_key_hash, sizeof (struct GNUNET_HashCode),
846 ctx_key, strlen (ctx_key),
847 NULL, 0);
848 static const char ctx_iv[] = "gnuid-aes-ctx-iv";
849 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
850 new_key_hash, sizeof (struct GNUNET_HashCode),
851 ctx_iv, strlen (ctx_iv),
852 NULL, 0);
853 return GNUNET_OK;
854}
855
856/**
857 * Cleanup ticket consume handle
858 * @param handle the handle to clean up
859 */
860static void
861cleanup_ticket_issue_handle (struct TicketIssueHandle *handle)
862{
863 if (NULL != handle->attrs)
864 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
865 if (NULL != handle->ns_qe)
866 GNUNET_NAMESTORE_cancel (handle->ns_qe);
867 GNUNET_free (handle);
868}
869
870
871static void
872send_ticket_result (struct IdpClient *client,
873 uint32_t r_id,
874 const struct GNUNET_RECLAIM_Ticket *ticket,
875 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
876{
877 struct TicketResultMessage *irm;
878 struct GNUNET_MQ_Envelope *env;
879 struct GNUNET_RECLAIM_Ticket *ticket_buf;
880
881 /* store ticket in DB */
882 if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
883 ticket,
884 attrs))
885 {
886 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
887 "Unable to store ticket after issue\n");
888 GNUNET_break (0);
889 }
890
891 env = GNUNET_MQ_msg_extra (irm,
892 sizeof (struct GNUNET_RECLAIM_Ticket),
893 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
894 ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
895 *ticket_buf = *ticket;
896 irm->id = htonl (r_id);
897 GNUNET_MQ_send (client->mq,
898 env);
899}
900
901static void
902store_ticket_issue_cont (void *cls,
903 int32_t success,
904 const char *emsg)
905{
906 struct TicketIssueHandle *handle = cls;
907
908 handle->ns_qe = NULL;
909 GNUNET_CONTAINER_DLL_remove (handle->client->issue_op_head,
910 handle->client->issue_op_tail,
911 handle);
912 if (GNUNET_SYSERR == success)
913 {
914 cleanup_ticket_issue_handle (handle);
915 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
916 "Unknown Error\n");
917 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
918 return;
919 }
920 send_ticket_result (handle->client,
921 handle->r_id,
922 &handle->ticket,
923 handle->attrs);
924 cleanup_ticket_issue_handle (handle);
925}
926
927
928
929int
930serialize_abe_keyinfo2 (const struct GNUNET_RECLAIM_Ticket *ticket,
931 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
932 const struct GNUNET_ABE_AbeKey *rp_key,
933 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
934 char **result)
935{
936 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
937 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
938 char *enc_keyinfo;
939 char *serialized_key;
940 char *buf;
941 char *write_ptr;
942 char attrs_str_len;
943 ssize_t size;
944
945 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
946 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
947 struct GNUNET_HashCode new_key_hash;
948 ssize_t enc_size;
949
950 size = GNUNET_ABE_cpabe_serialize_key (rp_key,
951 (void**)&serialized_key);
952 attrs_str_len = 0;
953 for (le = attrs->list_head; NULL != le; le = le->next) {
954 attrs_str_len += strlen (le->claim->name) + 1;
955 }
956 buf = GNUNET_malloc (attrs_str_len + size);
957 write_ptr = buf;
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959 "Writing attributes\n");
960 for (le = attrs->list_head; NULL != le; le = le->next) {
961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 "%s\n", le->claim->name);
963
964
965 GNUNET_memcpy (write_ptr,
966 le->claim->name,
967 strlen (le->claim->name));
968 write_ptr[strlen (le->claim->name)] = ',';
969 write_ptr += strlen (le->claim->name) + 1;
970 }
971 write_ptr--;
972 write_ptr[0] = '\0'; //replace last , with a 0-terminator
973 write_ptr++;
974 GNUNET_memcpy (write_ptr,
975 serialized_key,
976 size);
977 GNUNET_free (serialized_key);
978 // ECDH keypair E = eG
979 *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
980 GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
981 &ecdh_pubkey);
982 enc_keyinfo = GNUNET_malloc (size + attrs_str_len);
983 // Derived key K = H(eB)
984 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
985 &ticket->audience,
986 &new_key_hash));
987 create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
988 enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
989 size + attrs_str_len,
990 &skey, &iv,
991 enc_keyinfo);
992 *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
993 enc_size);
994 GNUNET_memcpy (*result,
995 &ecdh_pubkey,
996 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
997 GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
998 enc_keyinfo,
999 enc_size);
1000 GNUNET_free (enc_keyinfo);
1001 GNUNET_free (buf);
1002 return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
1003}
1004
1005
1006
1007static void
1008issue_ticket_after_abe_bootstrap (void *cls,
1009 struct GNUNET_ABE_AbeMasterKey *abe_key)
1010{
1011 struct TicketIssueHandle *ih = cls;
1012 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1013 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1014 struct GNUNET_GNSRECORD_Data code_record[1];
1015 struct GNUNET_ABE_AbeKey *rp_key;
1016 char *code_record_data;
1017 char **attrs;
1018 char *label;
1019 char *policy;
1020 int attrs_len;
1021 uint32_t i;
1022 size_t code_record_len;
1023
1024 //Create new ABE key for RP
1025 attrs_len = 0;
1026 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1027 attrs_len++;
1028 attrs = GNUNET_malloc ((attrs_len + 1)*sizeof (char*));
1029 i = 0;
1030 for (le = ih->attrs->list_head; NULL != le; le = le->next) {
1031 GNUNET_asprintf (&policy, "%s_%lu",
1032 le->claim->name,
1033 le->claim->version);
1034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035 "Adding attribute to key: %s\n",
1036 policy);
1037 attrs[i] = policy;
1038 i++;
1039 }
1040 attrs[i] = NULL;
1041 rp_key = GNUNET_ABE_cpabe_create_key (abe_key,
1042 attrs);
1043
1044 //TODO review this wireformat
1045 code_record_len = serialize_abe_keyinfo2 (&ih->ticket,
1046 ih->attrs,
1047 rp_key,
1048 &ecdhe_privkey,
1049 &code_record_data);
1050 code_record[0].data = code_record_data;
1051 code_record[0].data_size = code_record_len;
1052 code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
1053 code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
1054 code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1055
1056 label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
1057 sizeof (uint64_t));
1058 //Publish record
1059 ih->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1060 &ih->identity,
1061 label,
1062 1,
1063 code_record,
1064 &store_ticket_issue_cont,
1065 ih);
1066 //for (; i > 0; i--)
1067 // GNUNET_free (attrs[i-1]);
1068 GNUNET_free (ecdhe_privkey);
1069 GNUNET_free (label);
1070 GNUNET_free (attrs);
1071 GNUNET_free (code_record_data);
1072 GNUNET_ABE_cpabe_delete_key (rp_key,
1073 GNUNET_YES);
1074 GNUNET_ABE_cpabe_delete_master_key (abe_key);
1075}
1076
1077
1078static int
1079check_issue_ticket_message(void *cls,
1080 const struct IssueTicketMessage *im)
1081{
1082 uint16_t size;
1083
1084 size = ntohs (im->header.size);
1085 if (size <= sizeof (struct IssueTicketMessage))
1086 {
1087 GNUNET_break (0);
1088 return GNUNET_SYSERR;
1089 }
1090 return GNUNET_OK;
1091}
1092
1093
1094static void
1095handle_issue_ticket_message (void *cls,
1096 const struct IssueTicketMessage *im)
1097{
1098 struct TicketIssueHandle *ih;
1099 struct IdpClient *idp = cls;
1100 size_t attrs_len;
1101
1102 ih = GNUNET_new (struct TicketIssueHandle);
1103 attrs_len = ntohs (im->attr_len);
1104 ih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len);
1105 ih->r_id = ntohl (im->id);
1106 ih->client = idp;
1107 ih->identity = im->identity;
1108 GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity,
1109 &ih->ticket.identity);
1110 ih->ticket.audience = im->rp;
1111 ih->ticket.rnd =
1112 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1113 UINT64_MAX);
1114 GNUNET_CONTAINER_DLL_insert (idp->issue_op_head,
1115 idp->issue_op_tail,
1116 ih);
1117 bootstrap_abe (&ih->identity, &issue_ticket_after_abe_bootstrap, ih, GNUNET_NO);
1118 GNUNET_SERVICE_client_continue (idp->client);
1119
1120}
1121
1122/**********************************************************
1123 * Revocation
1124 **********************************************************/
1125
1126/**
1127 * Cleanup revoke handle
1128 *
1129 * @param rh the ticket revocation handle
1130 */
1131static void
1132cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh)
1133{
1134 if (NULL != rh->attrs)
1135 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->attrs);
1136 if (NULL != rh->rvk_attrs)
1137 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->rvk_attrs);
1138 if (NULL != rh->abe_key)
1139 GNUNET_ABE_cpabe_delete_master_key (rh->abe_key);
1140 if (NULL != rh->ns_qe)
1141 GNUNET_NAMESTORE_cancel (rh->ns_qe);
1142 if (NULL != rh->ns_it)
1143 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
1144 GNUNET_free (rh);
1145}
1146
1147
1148/**
1149 * Send revocation result
1150 *
1151 * @param rh ticket revocation handle
1152 * @param success GNUNET_OK if successful result
1153 */
1154static void
1155send_revocation_finished (struct TicketRevocationHandle *rh,
1156 uint32_t success)
1157{
1158 struct GNUNET_MQ_Envelope *env;
1159 struct RevokeTicketResultMessage *trm;
1160
1161 GNUNET_break(TKT_database->delete_ticket (TKT_database->cls,
1162 &rh->ticket));
1163
1164 env = GNUNET_MQ_msg (trm,
1165 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
1166 trm->id = htonl (rh->r_id);
1167 trm->success = htonl (success);
1168 GNUNET_MQ_send (rh->client->mq,
1169 env);
1170 GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head,
1171 rh->client->revoke_op_tail,
1172 rh);
1173}
1174
1175
1176/**
1177 * Process ticket from database
1178 *
1179 * @param cls struct TicketIterationProcResult
1180 * @param ticket the ticket
1181 * @param attrs the attributes
1182 */
1183static void
1184ticket_reissue_proc (void *cls,
1185 const struct GNUNET_RECLAIM_Ticket *ticket,
1186 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
1187
1188static void
1189revocation_reissue_tickets (struct TicketRevocationHandle *rh);
1190
1191
1192static void reissue_next (void *cls)
1193{
1194 struct TicketRevocationHandle *rh = cls;
1195 revocation_reissue_tickets (rh);
1196}
1197
1198
1199static void
1200reissue_ticket_cont (void *cls,
1201 int32_t success,
1202 const char *emsg)
1203{
1204 struct TicketRevocationHandle *rh = cls;
1205
1206 rh->ns_qe = NULL;
1207 if (GNUNET_SYSERR == success)
1208 {
1209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1210 "Unknown Error\n");
1211 send_revocation_finished (rh, GNUNET_SYSERR);
1212 cleanup_revoke_ticket_handle (rh);
1213 return;
1214 }
1215 rh->offset++;
1216 GNUNET_SCHEDULER_add_now (&reissue_next, rh);
1217}
1218
1219
1220/**
1221 * Process ticket from database
1222 *
1223 * @param cls struct TicketIterationProcResult
1224 * @param ticket the ticket
1225 * @param attrs the attributes
1226 */
1227static void
1228ticket_reissue_proc (void *cls,
1229 const struct GNUNET_RECLAIM_Ticket *ticket,
1230 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
1231{
1232 struct TicketRevocationHandle *rh = cls;
1233 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1234 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le_rollover;
1235 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1236 struct GNUNET_GNSRECORD_Data code_record[1];
1237 struct GNUNET_ABE_AbeKey *rp_key;
1238 char *code_record_data;
1239 char **attr_arr;
1240 char *label;
1241 char *policy;
1242 int attrs_len;
1243 uint32_t i;
1244 int reissue_ticket;
1245 size_t code_record_len;
1246
1247
1248 if (NULL == ticket)
1249 {
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251 "Iteration done\n");
1252 return;
1253 }
1254
1255 if (0 == memcmp (&ticket->audience,
1256 &rh->ticket.audience,
1257 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1258 {
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "Do not reissue for this identity.!\n");
1261 label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd,
1262 sizeof (uint64_t));
1263 //Delete record
1264 rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1265 &rh->identity,
1266 label,
1267 0,
1268 NULL,
1269 &reissue_ticket_cont,
1270 rh);
1271
1272 GNUNET_free (label);
1273 return;
1274 }
1275
1276 /*
1277 * Check if any attribute of this ticket intersects with a rollover attribute
1278 */
1279 reissue_ticket = GNUNET_NO;
1280 for (le = attrs->list_head; NULL != le; le = le->next)
1281 {
1282 for (le_rollover = rh->rvk_attrs->list_head;
1283 NULL != le_rollover;
1284 le_rollover = le_rollover->next)
1285 {
1286 if (0 == strcmp (le_rollover->claim->name,
1287 le->claim->name))
1288 {
1289 reissue_ticket = GNUNET_YES;
1290 le->claim->version = le_rollover->claim->version;
1291 }
1292 }
1293 }
1294
1295 if (GNUNET_NO == reissue_ticket)
1296 {
1297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1298 "Skipping ticket.\n");
1299
1300 rh->offset++;
1301 GNUNET_SCHEDULER_add_now (&reissue_next, rh);
1302
1303
1304 return;
1305 }
1306
1307 //Create new ABE key for RP
1308 attrs_len = 0;
1309
1310 /* If this is the RP we want to revoke attributes of, the do so */
1311
1312 for (le = attrs->list_head; NULL != le; le = le->next)
1313 attrs_len++;
1314 attr_arr = GNUNET_malloc ((attrs_len + 1)*sizeof (char*));
1315 i = 0;
1316 for (le = attrs->list_head; NULL != le; le = le->next) {
1317 GNUNET_asprintf (&policy, "%s_%lu",
1318 le->claim->name,
1319 le->claim->version);
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "Recreating key with %s\n", policy);
1322 attr_arr[i] = policy;
1323 i++;
1324 }
1325 attr_arr[i] = NULL;
1326 rp_key = GNUNET_ABE_cpabe_create_key (rh->abe_key,
1327 attr_arr);
1328
1329 //TODO review this wireformat
1330 code_record_len = serialize_abe_keyinfo2 (ticket,
1331 attrs,
1332 rp_key,
1333 &ecdhe_privkey,
1334 &code_record_data);
1335 code_record[0].data = code_record_data;
1336 code_record[0].data_size = code_record_len;
1337 code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
1338 code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
1339 code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1340
1341 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
1342 sizeof (uint64_t));
1343 //Publish record
1344 rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1345 &rh->identity,
1346 label,
1347 1,
1348 code_record,
1349 &reissue_ticket_cont,
1350 rh);
1351 //for (; i > 0; i--)
1352 // GNUNET_free (attr_arr[i-1]);
1353 GNUNET_free (ecdhe_privkey);
1354 GNUNET_free (label);
1355 GNUNET_free (attr_arr);
1356 GNUNET_free (code_record_data);
1357 GNUNET_ABE_cpabe_delete_key (rp_key, GNUNET_YES);
1358}
1359
1360
1361/* Prototype for below function */
1362static void
1363attr_reenc_cont (void *cls,
1364 int32_t success,
1365 const char *emsg);
1366
1367static void
1368revocation_reissue_tickets (struct TicketRevocationHandle *rh)
1369{
1370 int ret;
1371 /* Done, issue new keys */
1372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1373 "Revocation Phase III: Reissuing Tickets\n");
1374 if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls,
1375 &rh->ticket.identity,
1376 GNUNET_NO,
1377 rh->offset,
1378 &ticket_reissue_proc,
1379 rh)))
1380 {
1381 GNUNET_break (0);
1382 }
1383 if (GNUNET_NO == ret)
1384 {
1385 send_revocation_finished (rh, GNUNET_OK);
1386 cleanup_revoke_ticket_handle (rh);
1387 return;
1388 }
1389}
1390
1391/**
1392 * Failed to check for attribute
1393 */
1394static void
1395check_attr_error (void *cls)
1396{
1397 struct TicketRevocationHandle *rh = cls;
1398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1399 "Unable to check for existing attribute\n");
1400 rh->ns_qe = NULL;
1401 send_revocation_finished (rh, GNUNET_SYSERR);
1402 cleanup_revoke_ticket_handle (rh);
1403}
1404
1405
1406/**
1407 * Revoke next attribte by reencryption with
1408 * new ABE master
1409 */
1410static void
1411reenc_next_attribute (void *cls);
1412
1413/**
1414 * Check for existing attribute and overwrite
1415 */
1416static void
1417check_attr_cb (void *cls,
1418 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1419 const char *label,
1420 unsigned int rd_count,
1421 const struct GNUNET_GNSRECORD_Data *rd_old)
1422{
1423 struct TicketRevocationHandle *rh = cls;
1424 struct GNUNET_GNSRECORD_Data rd[1];
1425 char* buf;
1426 char* enc_buf;
1427 size_t enc_size;
1428 char* rd_buf;
1429 size_t buf_size;
1430 char* policy;
1431 uint32_t attr_ver;
1432
1433 rh->ns_qe = NULL;
1434 if (1 != rd_count) {
1435 GNUNET_SCHEDULER_add_now (&reenc_next_attribute,
1436 rh);
1437 return;
1438 }
1439
1440 buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim);
1441 buf = GNUNET_malloc (buf_size);
1442 rh->attrs->list_head->claim->version++;
1443 GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim,
1444 buf);
1445 GNUNET_asprintf (&policy, "%s_%lu",
1446 rh->attrs->list_head->claim->name,
1447 rh->attrs->list_head->claim->version);
1448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1449 "Encrypting with policy %s\n", policy);
1450 /**
1451 * Encrypt the attribute value and store in namestore
1452 */
1453 enc_size = GNUNET_ABE_cpabe_encrypt (buf,
1454 buf_size,
1455 policy, //Policy
1456 rh->abe_key,
1457 (void**)&enc_buf);
1458 GNUNET_free (buf);
1459 if (GNUNET_SYSERR == enc_size)
1460 {
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 "Unable to re-encrypt with policy %s\n",
1463 policy);
1464 GNUNET_free (policy);
1465 send_revocation_finished (rh, GNUNET_SYSERR);
1466 cleanup_revoke_ticket_handle (rh);
1467 return;
1468 }
1469 GNUNET_free (policy);
1470
1471 rd[0].data_size = enc_size + sizeof (uint32_t);
1472 rd_buf = GNUNET_malloc (rd[0].data_size);
1473 attr_ver = htonl (rh->attrs->list_head->claim->version);
1474 GNUNET_memcpy (rd_buf,
1475 &attr_ver,
1476 sizeof (uint32_t));
1477 GNUNET_memcpy (rd_buf+sizeof (uint32_t),
1478 enc_buf,
1479 enc_size);
1480 rd[0].data = rd_buf;
1481 rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR;
1482 rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1483 rd[0].expiration_time = rd_old[0].expiration_time;
1484 rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1485 &rh->identity,
1486 rh->attrs->list_head->claim->name,
1487 1,
1488 rd,
1489 &attr_reenc_cont,
1490 rh);
1491 GNUNET_free (enc_buf);
1492 GNUNET_free (rd_buf);
1493}
1494
1495
1496/**
1497 * Revoke next attribte by reencryption with
1498 * new ABE master
1499 */
1500static void
1501reenc_next_attribute (void *cls)
1502{
1503 struct TicketRevocationHandle *rh = cls;
1504 if (NULL == rh->attrs->list_head)
1505 {
1506 revocation_reissue_tickets (rh);
1507 return;
1508 }
1509 /* First check if attribute still exists */
1510 rh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
1511 &rh->identity,
1512 rh->attrs->list_head->claim->name,
1513 &check_attr_error,
1514 rh,
1515 &check_attr_cb,
1516 rh);
1517}
1518
1519
1520/**
1521 * Namestore callback after revoked attribute
1522 * is stored
1523 */
1524static void
1525attr_reenc_cont (void *cls,
1526 int32_t success,
1527 const char *emsg)
1528{
1529 struct TicketRevocationHandle *rh = cls;
1530 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1531
1532 rh->ns_qe = NULL;
1533 if (GNUNET_SYSERR == success)
1534 {
1535 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1536 "Failed to reencrypt attribute %s\n",
1537 emsg);
1538 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1539 return;
1540 }
1541 if (NULL == rh->attrs->list_head)
1542 {
1543 revocation_reissue_tickets (rh);
1544 return;
1545 }
1546 le = rh->attrs->list_head;
1547 GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head,
1548 rh->attrs->list_tail,
1549 le);
1550 GNUNET_assert (NULL != rh->rvk_attrs);
1551 GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head,
1552 rh->rvk_attrs->list_tail,
1553 le);
1554
1555
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Re-encrypting next attribute\n");
1558 reenc_next_attribute (rh);
1559}
1560
1561
1562static void
1563process_attributes_to_update (void *cls,
1564 const struct GNUNET_RECLAIM_Ticket *ticket,
1565 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
1566{
1567 struct TicketRevocationHandle *rh = cls;
1568
1569 rh->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1571 "Revocation Phase I: Collecting attributes\n");
1572 /* Reencrypt all attributes with new key */
1573 if (NULL == rh->attrs->list_head)
1574 {
1575 /* No attributes to reencrypt */
1576 send_revocation_finished (rh, GNUNET_OK);
1577 cleanup_revoke_ticket_handle (rh);
1578 return;
1579 } else {
1580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1581 "Revocation Phase II: Re-encrypting attributes\n");
1582 reenc_next_attribute (rh);
1583 }
1584
1585}
1586
1587
1588
1589static void
1590get_ticket_after_abe_bootstrap (void *cls,
1591 struct GNUNET_ABE_AbeMasterKey *abe_key)
1592{
1593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1594 "Finished ABE bootstrap\n");
1595 struct TicketRevocationHandle *rh = cls;
1596 rh->abe_key = abe_key;
1597 TKT_database->get_ticket_attributes (TKT_database->cls,
1598 &rh->ticket,
1599 &process_attributes_to_update,
1600 rh);
1601}
1602
1603static int
1604check_revoke_ticket_message(void *cls,
1605 const struct RevokeTicketMessage *im)
1606{
1607 uint16_t size;
1608
1609 size = ntohs (im->header.size);
1610 if (size <= sizeof (struct RevokeTicketMessage))
1611 {
1612 GNUNET_break (0);
1613 return GNUNET_SYSERR;
1614 }
1615 return GNUNET_OK;
1616}
1617
1618static void
1619handle_revoke_ticket_message (void *cls,
1620 const struct RevokeTicketMessage *rm)
1621{
1622 struct TicketRevocationHandle *rh;
1623 struct IdpClient *idp = cls;
1624 struct GNUNET_RECLAIM_Ticket *ticket;
1625
1626 rh = GNUNET_new (struct TicketRevocationHandle);
1627 ticket = (struct GNUNET_RECLAIM_Ticket*)&rm[1];
1628 rh->rvk_attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1629 rh->ticket = *ticket;
1630 rh->r_id = ntohl (rm->id);
1631 rh->client = idp;
1632 rh->identity = rm->identity;
1633 GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity,
1634 &rh->ticket.identity);
1635 GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head,
1636 idp->revoke_op_tail,
1637 rh);
1638 bootstrap_abe (&rh->identity, &get_ticket_after_abe_bootstrap, rh, GNUNET_NO);
1639 GNUNET_SERVICE_client_continue (idp->client);
1640
1641}
1642
1643/**
1644 * Cleanup ticket consume handle
1645 * @param handle the handle to clean up
1646 */
1647static void
1648cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle)
1649{
1650 struct ParallelLookup *lu;
1651 struct ParallelLookup *tmp;
1652 if (NULL != handle->lookup_request)
1653 GNUNET_GNS_lookup_cancel (handle->lookup_request);
1654 for (lu = handle->parallel_lookups_head;
1655 NULL != lu;) {
1656 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1657 GNUNET_free (lu->label);
1658 tmp = lu->next;
1659 GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1660 handle->parallel_lookups_tail,
1661 lu);
1662 GNUNET_free (lu);
1663 lu = tmp;
1664 }
1665
1666 if (NULL != handle->key)
1667 GNUNET_ABE_cpabe_delete_key (handle->key,
1668 GNUNET_YES);
1669 if (NULL != handle->attrs)
1670 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
1671 GNUNET_free (handle);
1672}
1673
1674
1675
1676static int
1677check_consume_ticket_message(void *cls,
1678 const struct ConsumeTicketMessage *cm)
1679{
1680 uint16_t size;
1681
1682 size = ntohs (cm->header.size);
1683 if (size <= sizeof (struct ConsumeTicketMessage))
1684 {
1685 GNUNET_break (0);
1686 return GNUNET_SYSERR;
1687 }
1688 return GNUNET_OK;
1689}
1690
1691static void
1692process_parallel_lookup2 (void *cls, uint32_t rd_count,
1693 const struct GNUNET_GNSRECORD_Data *rd)
1694{
1695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1696 "Parallel lookup finished (count=%u)\n", rd_count);
1697 struct ParallelLookup *parallel_lookup = cls;
1698 struct ConsumeTicketHandle *handle = parallel_lookup->handle;
1699 struct ConsumeTicketResultMessage *crm;
1700 struct GNUNET_MQ_Envelope *env;
1701 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
1702 struct GNUNET_TIME_Absolute decrypt_duration;
1703 char *data;
1704 char *data_tmp;
1705 ssize_t attr_len;
1706 size_t attrs_len;
1707
1708 GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1709 handle->parallel_lookups_tail,
1710 parallel_lookup);
1711 GNUNET_free (parallel_lookup->label);
1712
1713 GNUNET_STATISTICS_update (stats,
1714 "attribute_lookup_time_total",
1715 GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us,
1716 GNUNET_YES);
1717 GNUNET_STATISTICS_update (stats,
1718 "attribute_lookups_count",
1719 1,
1720 GNUNET_YES);
1721
1722
1723 GNUNET_free (parallel_lookup);
1724 if (1 != rd_count)
1725 GNUNET_break(0);//TODO
1726 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1727 {
1728 decrypt_duration = GNUNET_TIME_absolute_get ();
1729 attr_len = GNUNET_ABE_cpabe_decrypt (rd->data + sizeof (uint32_t),
1730 rd->data_size - sizeof (uint32_t),
1731 handle->key,
1732 (void**)&data);
1733 if (GNUNET_SYSERR != attr_len)
1734 {
1735 GNUNET_STATISTICS_update (stats,
1736 "abe_decrypt_time_total",
1737 GNUNET_TIME_absolute_get_duration (decrypt_duration).rel_value_us,
1738 GNUNET_YES);
1739 GNUNET_STATISTICS_update (stats,
1740 "abe_decrypt_count",
1741 1,
1742 GNUNET_YES);
1743
1744 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1745 attr_le->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (data,
1746 attr_len);
1747 attr_le->claim->version = ntohl(*(uint32_t*)rd->data);
1748 GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head,
1749 handle->attrs->list_tail,
1750 attr_le);
1751 GNUNET_free (data);
1752 }
1753 }
1754 if (NULL != handle->parallel_lookups_head)
1755 return; //Wait for more
1756 /* Else we are done */
1757
1758 /* Store ticket in DB */
1759 if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
1760 &handle->ticket,
1761 handle->attrs))
1762 {
1763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1764 "Unable to store ticket after consume\n");
1765 GNUNET_break (0);
1766 }
1767
1768 GNUNET_SCHEDULER_cancel (handle->kill_task);
1769 attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (handle->attrs);
1770 env = GNUNET_MQ_msg_extra (crm,
1771 attrs_len,
1772 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
1773 crm->id = htonl (handle->r_id);
1774 crm->attrs_len = htons (attrs_len);
1775 crm->identity = handle->ticket.identity;
1776 data_tmp = (char *) &crm[1];
1777 GNUNET_RECLAIM_ATTRIBUTE_list_serialize (handle->attrs,
1778 data_tmp);
1779 GNUNET_MQ_send (handle->client->mq, env);
1780 GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
1781 handle->client->consume_op_tail,
1782 handle);
1783 cleanup_consume_ticket_handle (handle);
1784}
1785
1786void
1787abort_parallel_lookups2 (void *cls)
1788{
1789 struct ConsumeTicketHandle *handle = cls;
1790 struct ParallelLookup *lu;
1791 struct ParallelLookup *tmp;
1792 struct AttributeResultMessage *arm;
1793 struct GNUNET_MQ_Envelope *env;
1794
1795 handle->kill_task = NULL;
1796 for (lu = handle->parallel_lookups_head;
1797 NULL != lu;) {
1798 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1799 GNUNET_free (lu->label);
1800 tmp = lu->next;
1801 GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1802 handle->parallel_lookups_tail,
1803 lu);
1804 GNUNET_free (lu);
1805 lu = tmp;
1806 }
1807 env = GNUNET_MQ_msg (arm,
1808 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1809 arm->id = htonl (handle->r_id);
1810 arm->attr_len = htons (0);
1811 GNUNET_MQ_send (handle->client->mq, env);
1812
1813}
1814
1815
1816static void
1817process_consume_abe_key (void *cls, uint32_t rd_count,
1818 const struct GNUNET_GNSRECORD_Data *rd)
1819{
1820 struct ConsumeTicketHandle *handle = cls;
1821 struct GNUNET_HashCode new_key_hash;
1822 struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
1823 struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
1824 struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key;
1825 struct ParallelLookup *parallel_lookup;
1826 size_t size;
1827 char *buf;
1828 char *scope;
1829
1830 handle->lookup_request = NULL;
1831 if (1 != rd_count)
1832 {
1833 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1834 "Number of keys %d != 1.",
1835 rd_count);
1836 cleanup_consume_ticket_handle (handle);
1837 GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
1838 handle->client->consume_op_tail,
1839 handle);
1840 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1841 return;
1842 }
1843
1844 //Decrypt
1845 ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data;
1846
1847 buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1848
1849 //Calculate symmetric key from ecdh parameters
1850 GNUNET_assert (GNUNET_OK ==
1851 GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity,
1852 ecdh_key,
1853 &new_key_hash));
1854 create_sym_key_from_ecdh (&new_key_hash,
1855 &enc_key,
1856 &enc_iv);
1857 size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1858 rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1859 &enc_key,
1860 &enc_iv,
1861 buf);
1862
1863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1864 "Decrypted bytes: %zd Expected bytes: %zd\n",
1865 size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1866 GNUNET_STATISTICS_update (stats,
1867 "abe_key_lookup_time_total",
1868 GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us,
1869 GNUNET_YES);
1870 GNUNET_STATISTICS_update (stats,
1871 "abe_key_lookups_count",
1872 1,
1873 GNUNET_YES);
1874 scopes = GNUNET_strdup (buf);
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Scopes %s\n", scopes);
1877 handle->key = GNUNET_ABE_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1),
1878 rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)
1879 - strlen (scopes) - 1);
1880
1881 for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ","))
1882 {
1883 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1884 "Looking up %s\n", scope);
1885 parallel_lookup = GNUNET_new (struct ParallelLookup);
1886 parallel_lookup->handle = handle;
1887 parallel_lookup->label = GNUNET_strdup (scope);
1888 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get();
1889 parallel_lookup->lookup_request
1890 = GNUNET_GNS_lookup (gns_handle,
1891 scope,
1892 &handle->ticket.identity,
1893 GNUNET_GNSRECORD_TYPE_ID_ATTR,
1894 GNUNET_GNS_LO_DEFAULT,
1895 &process_parallel_lookup2,
1896 parallel_lookup);
1897 GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head,
1898 handle->parallel_lookups_tail,
1899 parallel_lookup);
1900 }
1901 GNUNET_free (scopes);
1902 GNUNET_free (buf);
1903 handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3),
1904 &abort_parallel_lookups2,
1905 handle);
1906}
1907
1908
1909static void
1910handle_consume_ticket_message (void *cls,
1911 const struct ConsumeTicketMessage *cm)
1912{
1913 struct ConsumeTicketHandle *ch;
1914 struct IdpClient *idp = cls;
1915 char* rnd_label;
1916
1917 ch = GNUNET_new (struct ConsumeTicketHandle);
1918 ch->r_id = ntohl (cm->id);
1919 ch->client = idp;
1920 ch->identity = cm->identity;
1921 ch->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1922 GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity,
1923 &ch->identity_pub);
1924 ch->ticket = *((struct GNUNET_RECLAIM_Ticket*)&cm[1]);
1925 rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd,
1926 sizeof (uint64_t));
1927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1928 "Looking for ABE key under %s\n", rnd_label);
1929 ch->lookup_start_time = GNUNET_TIME_absolute_get ();
1930 ch->lookup_request
1931 = GNUNET_GNS_lookup (gns_handle,
1932 rnd_label,
1933 &ch->ticket.identity,
1934 GNUNET_GNSRECORD_TYPE_ABE_KEY,
1935 GNUNET_GNS_LO_DEFAULT,
1936 &process_consume_abe_key,
1937 ch);
1938 GNUNET_CONTAINER_DLL_insert (idp->consume_op_head,
1939 idp->consume_op_tail,
1940 ch);
1941 GNUNET_free (rnd_label);
1942 GNUNET_SERVICE_client_continue (idp->client);
1943}
1944
1945/**
1946 * Cleanup attribute store handle
1947 *
1948 * @param handle handle to clean up
1949 */
1950static void
1951cleanup_as_handle (struct AttributeStoreHandle *handle)
1952{
1953 if (NULL != handle->ns_qe)
1954 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1955 if (NULL != handle->claim)
1956 GNUNET_free (handle->claim);
1957 if (NULL != handle->abe_key)
1958 GNUNET_ABE_cpabe_delete_master_key (handle->abe_key);
1959 GNUNET_free (handle);
1960}
1961
1962static void
1963attr_store_cont (void *cls,
1964 int32_t success,
1965 const char *emsg)
1966{
1967 struct AttributeStoreHandle *as_handle = cls;
1968 struct GNUNET_MQ_Envelope *env;
1969 struct AttributeStoreResultMessage *acr_msg;
1970
1971 as_handle->ns_qe = NULL;
1972 GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head,
1973 as_handle->client->store_op_tail,
1974 as_handle);
1975
1976 if (GNUNET_SYSERR == success)
1977 {
1978 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1979 "Failed to store attribute %s\n",
1980 emsg);
1981 cleanup_as_handle (as_handle);
1982 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1983 return;
1984 }
1985
1986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1987 "Sending ATTRIBUTE_STORE_RESPONSE message\n");
1988 env = GNUNET_MQ_msg (acr_msg,
1989 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE);
1990 acr_msg->id = htonl (as_handle->r_id);
1991 acr_msg->op_result = htonl (GNUNET_OK);
1992 GNUNET_MQ_send (as_handle->client->mq,
1993 env);
1994 cleanup_as_handle (as_handle);
1995}
1996
1997static void
1998attr_store_task (void *cls)
1999{
2000 struct AttributeStoreHandle *as_handle = cls;
2001 struct GNUNET_GNSRECORD_Data rd[1];
2002 char* buf;
2003 char* policy;
2004 char* enc_buf;
2005 char* rd_buf;
2006 size_t enc_size;
2007 size_t buf_size;
2008 uint32_t attr_ver;
2009
2010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2011 "Storing attribute\n");
2012 buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (as_handle->claim);
2013 buf = GNUNET_malloc (buf_size);
2014
2015 GNUNET_RECLAIM_ATTRIBUTE_serialize (as_handle->claim,
2016 buf);
2017
2018 GNUNET_asprintf (&policy,
2019 "%s_%lu",
2020 as_handle->claim->name,
2021 as_handle->claim->version);
2022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2023 "Encrypting with policy %s\n", policy);
2024 /**
2025 * Encrypt the attribute value and store in namestore
2026 */
2027 enc_size = GNUNET_ABE_cpabe_encrypt (buf,
2028 buf_size,
2029 policy, //Policy
2030 as_handle->abe_key,
2031 (void**)&enc_buf);
2032 if (GNUNET_SYSERR == enc_size)
2033 {
2034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2035 "Failed to encrypt with policy %s\n",
2036 policy);
2037 GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head,
2038 as_handle->client->store_op_tail,
2039 as_handle);
2040
2041 cleanup_as_handle (as_handle);
2042 GNUNET_free (buf);
2043 GNUNET_free (policy);
2044 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
2045 return;
2046 }
2047 GNUNET_free (buf);
2048 GNUNET_free (policy);
2049 rd[0].data_size = enc_size + sizeof (uint32_t);
2050 rd_buf = GNUNET_malloc (rd[0].data_size);
2051 attr_ver = htonl (as_handle->claim->version);
2052 GNUNET_memcpy (rd_buf,
2053 &attr_ver,
2054 sizeof (uint32_t));
2055 GNUNET_memcpy (rd_buf+sizeof (uint32_t),
2056 enc_buf,
2057 enc_size);
2058 rd[0].data = rd_buf;
2059 rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR;
2060 rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
2061 rd[0].expiration_time = as_handle->exp.rel_value_us;
2062 as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
2063 &as_handle->identity,
2064 as_handle->claim->name,
2065 1,
2066 rd,
2067 &attr_store_cont,
2068 as_handle);
2069 GNUNET_free (enc_buf);
2070 GNUNET_free (rd_buf);
2071}
2072
2073
2074static void
2075store_after_abe_bootstrap (void *cls,
2076 struct GNUNET_ABE_AbeMasterKey *abe_key)
2077{
2078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2079 "Finished ABE bootstrap\n");
2080 struct AttributeStoreHandle *ash = cls;
2081 ash->abe_key = abe_key;
2082 GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
2083}
2084
2085static int
2086check_attribute_store_message(void *cls,
2087 const struct AttributeStoreMessage *sam)
2088{
2089 uint16_t size;
2090
2091 size = ntohs (sam->header.size);
2092 if (size <= sizeof (struct AttributeStoreMessage))
2093 {
2094 GNUNET_break (0);
2095 return GNUNET_SYSERR;
2096 }
2097 return GNUNET_OK;
2098}
2099
2100
2101static void
2102handle_attribute_store_message (void *cls,
2103 const struct AttributeStoreMessage *sam)
2104{
2105 struct AttributeStoreHandle *as_handle;
2106 struct IdpClient *idp = cls;
2107 size_t data_len;
2108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2109 "Received ATTRIBUTE_STORE message\n");
2110
2111 data_len = ntohs (sam->attr_len);
2112
2113 as_handle = GNUNET_new (struct AttributeStoreHandle);
2114 as_handle->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&sam[1],
2115 data_len);
2116
2117 as_handle->r_id = ntohl (sam->id);
2118 as_handle->identity = sam->identity;
2119 as_handle->exp.rel_value_us = GNUNET_ntohll (sam->exp);
2120 GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity,
2121 &as_handle->identity_pkey);
2122
2123 GNUNET_SERVICE_client_continue (idp->client);
2124 as_handle->client = idp;
2125 GNUNET_CONTAINER_DLL_insert (idp->store_op_head,
2126 idp->store_op_tail,
2127 as_handle);
2128 bootstrap_abe (&as_handle->identity, &store_after_abe_bootstrap, as_handle, GNUNET_NO);
2129}
2130
2131static void
2132cleanup_attribute_iter_handle (struct AttributeIterator *ai)
2133{
2134 if (NULL != ai->abe_key)
2135 GNUNET_ABE_cpabe_delete_master_key (ai->abe_key);
2136 GNUNET_free (ai);
2137}
2138
2139static void
2140attr_iter_error (void *cls)
2141{
2142 struct AttributeIterator *ai = cls;
2143 //TODO
2144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2145 "Failed to iterate over attributes\n");
2146 GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
2147 ai->client->attr_iter_tail,
2148 ai);
2149 cleanup_attribute_iter_handle (ai);
2150 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
2151}
2152
2153static void
2154attr_iter_finished (void *cls)
2155{
2156 struct AttributeIterator *ai = cls;
2157 struct GNUNET_MQ_Envelope *env;
2158 struct AttributeResultMessage *arm;
2159
2160 env = GNUNET_MQ_msg (arm,
2161 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
2162 arm->id = htonl (ai->request_id);
2163 arm->attr_len = htons (0);
2164 GNUNET_MQ_send (ai->client->mq, env);
2165 GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
2166 ai->client->attr_iter_tail,
2167 ai);
2168 cleanup_attribute_iter_handle (ai);
2169}
2170
2171static void
2172attr_iter_cb (void *cls,
2173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
2174 const char *label,
2175 unsigned int rd_count,
2176 const struct GNUNET_GNSRECORD_Data *rd)
2177{
2178 struct AttributeIterator *ai = cls;
2179 struct AttributeResultMessage *arm;
2180 struct GNUNET_ABE_AbeKey *key;
2181 struct GNUNET_MQ_Envelope *env;
2182 ssize_t msg_extra_len;
2183 char* attr_ser;
2184 char* attrs[2];
2185 char* data_tmp;
2186 char* policy;
2187 uint32_t attr_ver;
2188
2189 if (rd_count != 1)
2190 {
2191 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
2192 1);
2193 return;
2194 }
2195
2196 if (GNUNET_GNSRECORD_TYPE_ID_ATTR != rd->record_type)
2197 {
2198 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
2199 1);
2200 return;
2201 }
2202 attr_ver = ntohl(*((uint32_t*)rd->data));
2203 GNUNET_asprintf (&policy, "%s_%lu",
2204 label, attr_ver);
2205 attrs[0] = policy;
2206 attrs[1] = 0;
2207 key = GNUNET_ABE_cpabe_create_key (ai->abe_key,
2208 attrs);
2209 msg_extra_len = GNUNET_ABE_cpabe_decrypt (rd->data+sizeof (uint32_t),
2210 rd->data_size-sizeof (uint32_t),
2211 key,
2212 (void**)&attr_ser);
2213 if (GNUNET_SYSERR == msg_extra_len)
2214 {
2215 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
2216 1);
2217 return;
2218 }
2219
2220 GNUNET_ABE_cpabe_delete_key (key,
2221 GNUNET_YES);
2222 //GNUNET_free (policy);
2223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2224 "Found attribute: %s\n", label);
2225 env = GNUNET_MQ_msg_extra (arm,
2226 msg_extra_len,
2227 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
2228 arm->id = htonl (ai->request_id);
2229 arm->attr_len = htons (msg_extra_len);
2230 GNUNET_CRYPTO_ecdsa_key_get_public (zone,
2231 &arm->identity);
2232 data_tmp = (char *) &arm[1];
2233 GNUNET_memcpy (data_tmp,
2234 attr_ser,
2235 msg_extra_len);
2236 GNUNET_MQ_send (ai->client->mq, env);
2237 GNUNET_free (attr_ser);
2238 GNUNET_ABE_cpabe_delete_master_key (ai->abe_key);
2239 ai->abe_key = NULL;
2240}
2241
2242
2243void
2244iterate_after_abe_bootstrap (void *cls,
2245 struct GNUNET_ABE_AbeMasterKey *abe_key)
2246{
2247 struct AttributeIterator *ai = cls;
2248 ai->abe_key = abe_key;
2249 ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
2250 &ai->identity,
2251 &attr_iter_error,
2252 ai,
2253 &attr_iter_cb,
2254 ai,
2255 &attr_iter_finished,
2256 ai);
2257}
2258
2259
2260static void
2261iterate_next_after_abe_bootstrap (void *cls,
2262 struct GNUNET_ABE_AbeMasterKey *abe_key)
2263{
2264 struct AttributeIterator *ai = cls;
2265 ai->abe_key = abe_key;
2266 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
2267 1);
2268}
2269
2270
2271
2272static void
2273handle_iteration_start (void *cls,
2274 const struct AttributeIterationStartMessage *ais_msg)
2275{
2276 struct IdpClient *idp = cls;
2277 struct AttributeIterator *ai;
2278
2279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2280 "Received ATTRIBUTE_ITERATION_START message\n");
2281 ai = GNUNET_new (struct AttributeIterator);
2282 ai->request_id = ntohl (ais_msg->id);
2283 ai->client = idp;
2284 ai->identity = ais_msg->identity;
2285
2286 GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head,
2287 idp->attr_iter_tail,
2288 ai);
2289 bootstrap_abe (&ai->identity, &iterate_after_abe_bootstrap, ai, GNUNET_NO);
2290 GNUNET_SERVICE_client_continue (idp->client);
2291}
2292
2293
2294static void
2295handle_iteration_stop (void *cls,
2296 const struct AttributeIterationStopMessage *ais_msg)
2297{
2298 struct IdpClient *idp = cls;
2299 struct AttributeIterator *ai;
2300 uint32_t rid;
2301
2302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2303 "Received `%s' message\n",
2304 "ATTRIBUTE_ITERATION_STOP");
2305 rid = ntohl (ais_msg->id);
2306 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
2307 if (ai->request_id == rid)
2308 break;
2309 if (NULL == ai)
2310 {
2311 GNUNET_break (0);
2312 GNUNET_SERVICE_client_drop (idp->client);
2313 return;
2314 }
2315 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
2316 idp->attr_iter_tail,
2317 ai);
2318 GNUNET_free (ai);
2319 GNUNET_SERVICE_client_continue (idp->client);
2320}
2321
2322
2323static void
2324handle_iteration_next (void *cls,
2325 const struct AttributeIterationNextMessage *ais_msg)
2326{
2327 struct IdpClient *idp = cls;
2328 struct AttributeIterator *ai;
2329 uint32_t rid;
2330
2331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2332 "Received ATTRIBUTE_ITERATION_NEXT message\n");
2333 rid = ntohl (ais_msg->id);
2334 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
2335 if (ai->request_id == rid)
2336 break;
2337 if (NULL == ai)
2338 {
2339 GNUNET_break (0);
2340 GNUNET_SERVICE_client_drop (idp->client);
2341 return;
2342 }
2343 bootstrap_abe (&ai->identity,
2344 &iterate_next_after_abe_bootstrap,
2345 ai,
2346 GNUNET_NO);
2347 GNUNET_SERVICE_client_continue (idp->client);
2348}
2349
2350/**
2351 * Ticket iteration processor result
2352 */
2353enum ZoneIterationResult
2354{
2355 /**
2356 * Iteration start.
2357 */
2358 IT_START = 0,
2359
2360 /**
2361 * Found tickets,
2362 * Continue to iterate with next iteration_next call
2363 */
2364 IT_SUCCESS_MORE_AVAILABLE = 1,
2365
2366 /**
2367 * Iteration complete
2368 */
2369 IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
2370};
2371
2372
2373/**
2374 * Context for ticket iteration
2375 */
2376struct TicketIterationProcResult
2377{
2378 /**
2379 * The ticket iteration handle
2380 */
2381 struct TicketIteration *ti;
2382
2383 /**
2384 * Iteration result: iteration done?
2385 * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but
2386 * we got one for now and have sent it to the client
2387 * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
2388 * #IT_START: if we are still trying to find a result.
2389 */
2390 int res_iteration_finished;
2391
2392};
2393
2394static void
2395cleanup_ticket_iter_handle (struct TicketIteration *ti)
2396{
2397 GNUNET_free (ti);
2398}
2399
2400/**
2401 * Process ticket from database
2402 *
2403 * @param cls struct TicketIterationProcResult
2404 * @param ticket the ticket
2405 * @param attrs the attributes
2406 */
2407static void
2408ticket_iterate_proc (void *cls,
2409 const struct GNUNET_RECLAIM_Ticket *ticket,
2410 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
2411{
2412 struct TicketIterationProcResult *proc = cls;
2413
2414 if (NULL == ticket)
2415 {
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417 "Iteration done\n");
2418 proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2419 return;
2420 }
2421 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
2422 send_ticket_result (proc->ti->client,
2423 proc->ti->r_id,
2424 ticket,
2425 attrs);
2426
2427}
2428
2429/**
2430 * Perform ticket iteration step
2431 *
2432 * @param ti ticket iterator to process
2433 */
2434static void
2435run_ticket_iteration_round (struct TicketIteration *ti)
2436{
2437 struct TicketIterationProcResult proc;
2438 struct GNUNET_MQ_Envelope *env;
2439 struct TicketResultMessage *trm;
2440 int ret;
2441
2442 memset (&proc, 0, sizeof (proc));
2443 proc.ti = ti;
2444 proc.res_iteration_finished = IT_START;
2445 while (IT_START == proc.res_iteration_finished)
2446 {
2447 if (GNUNET_SYSERR ==
2448 (ret = TKT_database->iterate_tickets (TKT_database->cls,
2449 &ti->identity,
2450 ti->is_audience,
2451 ti->offset,
2452 &ticket_iterate_proc,
2453 &proc)))
2454 {
2455 GNUNET_break (0);
2456 break;
2457 }
2458 if (GNUNET_NO == ret)
2459 proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2460 ti->offset++;
2461 }
2462 if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
2463 {
2464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465 "More results available\n");
2466 return; /* more later */
2467 }
2468 /* send empty response to indicate end of list */
2469 env = GNUNET_MQ_msg (trm,
2470 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
2471 trm->id = htonl (ti->r_id);
2472 GNUNET_MQ_send (ti->client->mq,
2473 env);
2474 GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
2475 ti->client->ticket_iter_tail,
2476 ti);
2477 cleanup_ticket_iter_handle (ti);
2478}
2479
2480static void
2481handle_ticket_iteration_start (void *cls,
2482 const struct TicketIterationStartMessage *tis_msg)
2483{
2484 struct IdpClient *client = cls;
2485 struct TicketIteration *ti;
2486
2487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2488 "Received TICKET_ITERATION_START message\n");
2489 ti = GNUNET_new (struct TicketIteration);
2490 ti->r_id = ntohl (tis_msg->id);
2491 ti->offset = 0;
2492 ti->client = client;
2493 ti->identity = tis_msg->identity;
2494 ti->is_audience = ntohl (tis_msg->is_audience);
2495
2496 GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
2497 client->ticket_iter_tail,
2498 ti);
2499 run_ticket_iteration_round (ti);
2500 GNUNET_SERVICE_client_continue (client->client);
2501}
2502
2503
2504static void
2505handle_ticket_iteration_stop (void *cls,
2506 const struct TicketIterationStopMessage *tis_msg)
2507{
2508 struct IdpClient *client = cls;
2509 struct TicketIteration *ti;
2510 uint32_t rid;
2511
2512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2513 "Received `%s' message\n",
2514 "TICKET_ITERATION_STOP");
2515 rid = ntohl (tis_msg->id);
2516 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2517 if (ti->r_id == rid)
2518 break;
2519 if (NULL == ti)
2520 {
2521 GNUNET_break (0);
2522 GNUNET_SERVICE_client_drop (client->client);
2523 return;
2524 }
2525 GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
2526 client->ticket_iter_tail,
2527 ti);
2528 cleanup_ticket_iter_handle (ti);
2529 GNUNET_SERVICE_client_continue (client->client);
2530}
2531
2532
2533static void
2534handle_ticket_iteration_next (void *cls,
2535 const struct TicketIterationNextMessage *tis_msg)
2536{
2537 struct IdpClient *client = cls;
2538 struct TicketIteration *ti;
2539 uint32_t rid;
2540
2541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2542 "Received TICKET_ITERATION_NEXT message\n");
2543 rid = ntohl (tis_msg->id);
2544 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2545 if (ti->r_id == rid)
2546 break;
2547 if (NULL == ti)
2548 {
2549 GNUNET_break (0);
2550 GNUNET_SERVICE_client_drop (client->client);
2551 return;
2552 }
2553 run_ticket_iteration_round (ti);
2554 GNUNET_SERVICE_client_continue (client->client);
2555}
2556
2557
2558
2559
2560/**
2561 * Main function that will be run
2562 *
2563 * @param cls closure
2564 * @param c the configuration used
2565 * @param server the service handle
2566 */
2567static void
2568run (void *cls,
2569 const struct GNUNET_CONFIGURATION_Handle *c,
2570 struct GNUNET_SERVICE_Handle *server)
2571{
2572 char *database;
2573 cfg = c;
2574
2575 stats = GNUNET_STATISTICS_create ("reclaim", cfg);
2576
2577 //Connect to identity and namestore services
2578 ns_handle = GNUNET_NAMESTORE_connect (cfg);
2579 if (NULL == ns_handle)
2580 {
2581 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
2582 }
2583
2584 gns_handle = GNUNET_GNS_connect (cfg);
2585 if (NULL == gns_handle)
2586 {
2587 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
2588 }
2589 credential_handle = GNUNET_CREDENTIAL_connect (cfg);
2590 if (NULL == credential_handle)
2591 {
2592 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
2593 }
2594 identity_handle = GNUNET_IDENTITY_connect (cfg,
2595 NULL,
2596 NULL);
2597 /* Loading DB plugin */
2598 if (GNUNET_OK !=
2599 GNUNET_CONFIGURATION_get_value_string (cfg,
2600 "reclaim",
2601 "database",
2602 &database))
2603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2604 "No database backend configured\n");
2605 GNUNET_asprintf (&db_lib_name,
2606 "libgnunet_plugin_reclaim_%s",
2607 database);
2608 TKT_database = GNUNET_PLUGIN_load (db_lib_name,
2609 (void *) cfg);
2610 GNUNET_free (database);
2611 if (NULL == TKT_database)
2612 {
2613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2614 "Could not load database backend `%s'\n",
2615 db_lib_name);
2616 GNUNET_SCHEDULER_shutdown ();
2617 return;
2618 }
2619
2620 if (GNUNET_OK ==
2621 GNUNET_CONFIGURATION_get_value_time (cfg,
2622 "reclaim",
2623 "TOKEN_EXPIRATION_INTERVAL",
2624 &token_expiration_interval))
2625 {
2626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2627 "Time window for zone iteration: %s\n",
2628 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
2629 GNUNET_YES));
2630 } else {
2631 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
2632 }
2633
2634 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
2635}
2636
2637/**
2638 * Called whenever a client is disconnected.
2639 *
2640 * @param cls closure
2641 * @param client identification of the client
2642 * @param app_ctx @a client
2643 */
2644static void
2645client_disconnect_cb (void *cls,
2646 struct GNUNET_SERVICE_Client *client,
2647 void *app_ctx)
2648{
2649 struct IdpClient *idp = app_ctx;
2650 struct AttributeIterator *ai;
2651 struct TicketIteration *ti;
2652 struct TicketRevocationHandle *rh;
2653 struct TicketIssueHandle *iss;
2654 struct ConsumeTicketHandle *ct;
2655 struct AttributeStoreHandle *as;
2656
2657 //TODO other operations
2658
2659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2660 "Client %p disconnected\n",
2661 client);
2662
2663 while (NULL != (iss = idp->issue_op_head))
2664 {
2665 GNUNET_CONTAINER_DLL_remove (idp->issue_op_head,
2666 idp->issue_op_tail,
2667 iss);
2668 cleanup_ticket_issue_handle (iss);
2669 }
2670 while (NULL != (ct = idp->consume_op_head))
2671 {
2672 GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
2673 idp->consume_op_tail,
2674 ct);
2675 cleanup_consume_ticket_handle (ct);
2676 }
2677 while (NULL != (as = idp->store_op_head))
2678 {
2679 GNUNET_CONTAINER_DLL_remove (idp->store_op_head,
2680 idp->store_op_tail,
2681 as);
2682 cleanup_as_handle (as);
2683 }
2684
2685 while (NULL != (ai = idp->attr_iter_head))
2686 {
2687 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
2688 idp->attr_iter_tail,
2689 ai);
2690 cleanup_attribute_iter_handle (ai);
2691 }
2692 while (NULL != (rh = idp->revoke_op_head))
2693 {
2694 GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head,
2695 idp->revoke_op_tail,
2696 rh);
2697 cleanup_revoke_ticket_handle (rh);
2698 }
2699 while (NULL != (ti = idp->ticket_iter_head))
2700 {
2701 GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
2702 idp->ticket_iter_tail,
2703 ti);
2704 cleanup_ticket_iter_handle (ti);
2705 }
2706 GNUNET_free (idp);
2707}
2708
2709
2710/**
2711 * Add a client to our list of active clients.
2712 *
2713 * @param cls NULL
2714 * @param client client to add
2715 * @param mq message queue for @a client
2716 * @return internal namestore client structure for this client
2717 */
2718static void *
2719client_connect_cb (void *cls,
2720 struct GNUNET_SERVICE_Client *client,
2721 struct GNUNET_MQ_Handle *mq)
2722{
2723 struct IdpClient *idp;
2724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2725 "Client %p connected\n",
2726 client);
2727 idp = GNUNET_new (struct IdpClient);
2728 idp->client = client;
2729 idp->mq = mq;
2730 return idp;
2731}
2732
2733
2734
2735/**
2736 * Define "main" method using service macro.
2737 */
2738GNUNET_SERVICE_MAIN
2739("reclaim",
2740 GNUNET_SERVICE_OPTION_NONE,
2741 &run,
2742 &client_connect_cb,
2743 &client_disconnect_cb,
2744 NULL,
2745 GNUNET_MQ_hd_var_size (attribute_store_message,
2746 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
2747 struct AttributeStoreMessage,
2748 NULL),
2749 GNUNET_MQ_hd_fixed_size (iteration_start,
2750 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
2751 struct AttributeIterationStartMessage,
2752 NULL),
2753 GNUNET_MQ_hd_fixed_size (iteration_next,
2754 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
2755 struct AttributeIterationNextMessage,
2756 NULL),
2757 GNUNET_MQ_hd_fixed_size (iteration_stop,
2758 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
2759 struct AttributeIterationStopMessage,
2760 NULL),
2761 GNUNET_MQ_hd_var_size (issue_ticket_message,
2762 GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
2763 struct IssueTicketMessage,
2764 NULL),
2765 GNUNET_MQ_hd_var_size (consume_ticket_message,
2766 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
2767 struct ConsumeTicketMessage,
2768 NULL),
2769 GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2770 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
2771 struct TicketIterationStartMessage,
2772 NULL),
2773 GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2774 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
2775 struct TicketIterationNextMessage,
2776 NULL),
2777 GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2778 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
2779 struct TicketIterationStopMessage,
2780 NULL),
2781 GNUNET_MQ_hd_var_size (revoke_ticket_message,
2782 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
2783 struct RevokeTicketMessage,
2784 NULL),
2785 GNUNET_MQ_handler_end());
2786/* end of gnunet-service-reclaim.c */
diff --git a/src/reclaim/jwt.c b/src/reclaim/jwt.c
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/reclaim/jwt.c
@@ -0,0 +1 @@
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c
new file mode 100644
index 000000000..1e9e64fec
--- /dev/null
+++ b/src/reclaim/oidc_helper.c
@@ -0,0 +1,440 @@
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
19/**
20 * @file reclaim/oidc_helper.c
21 * @brief helper library for OIDC related functions
22 * @author Martin Schanzenbach
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_signatures.h"
27#include "gnunet_reclaim_service.h"
28#include "gnunet_reclaim_attribute_lib.h"
29#include <jansson.h>
30#include <inttypes.h>
31#include "oidc_helper.h"
32
33static char*
34create_jwt_header(void)
35{
36 json_t *root;
37 char *json_str;
38
39 root = json_object ();
40 json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
41 json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
42
43 json_str = json_dumps (root, JSON_INDENT(0) | JSON_COMPACT);
44 json_decref (root);
45 return json_str;
46}
47
48static void
49replace_char(char* str, char find, char replace){
50 char *current_pos = strchr(str,find);
51 while (current_pos){
52 *current_pos = replace;
53 current_pos = strchr(current_pos,find);
54 }
55}
56
57//RFC4648
58static void
59fix_base64(char* str) {
60 char *padding;
61 //First, remove trailing padding '='
62 padding = strtok(str, "=");
63 while (NULL != padding)
64 padding = strtok(NULL, "=");
65
66 //Replace + with -
67 replace_char (str, '+', '-');
68
69 //Replace / with _
70 replace_char (str, '/', '_');
71
72}
73
74/**
75 * Create a JWT from attributes
76 *
77 * @param aud_key the public of the audience
78 * @param sub_key the public key of the subject
79 * @param attrs the attribute list
80 * @param expiration_time the validity of the token
81 * @param secret_key the key used to sign the JWT
82 * @return a new base64-encoded JWT string.
83 */
84char*
85OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
86 const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
87 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
88 const struct GNUNET_TIME_Relative *expiration_time,
89 const char *nonce,
90 const char *secret_key)
91{
92 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
93 struct GNUNET_HashCode signature;
94 struct GNUNET_TIME_Absolute exp_time;
95 struct GNUNET_TIME_Absolute time_now;
96 char* audience;
97 char* subject;
98 char* header;
99 char* body_str;
100 char* result;
101 char* header_base64;
102 char* body_base64;
103 char* signature_target;
104 char* signature_base64;
105 char* attr_val_str;
106 json_t* body;
107
108 //iat REQUIRED time now
109 time_now = GNUNET_TIME_absolute_get();
110 //exp REQUIRED time expired from config
111 exp_time = GNUNET_TIME_absolute_add (time_now, *expiration_time);
112 //auth_time only if max_age
113 //nonce only if nonce
114 // OPTIONAL acr,amr,azp
115 subject = GNUNET_STRINGS_data_to_string_alloc (sub_key,
116 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
117 audience = GNUNET_STRINGS_data_to_string_alloc (aud_key,
118 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
119 header = create_jwt_header ();
120 body = json_object ();
121
122 //iss REQUIRED case sensitive server uri with https
123 //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid)
124 json_object_set_new (body,
125 "iss", json_string (SERVER_ADDRESS));
126 //sub REQUIRED public key identity, not exceed 255 ASCII length
127 json_object_set_new (body,
128 "sub", json_string (subject));
129 //aud REQUIRED public key client_id must be there
130 json_object_set_new (body,
131 "aud", json_string (audience));
132 //iat
133 json_object_set_new (body,
134 "iat", json_integer (time_now.abs_value_us / (1000*1000)));
135 //exp
136 json_object_set_new (body,
137 "exp", json_integer (exp_time.abs_value_us / (1000*1000)));
138 //nbf
139 json_object_set_new (body,
140 "nbf", json_integer (time_now.abs_value_us / (1000*1000)));
141 //nonce
142 if (NULL != nonce)
143 json_object_set_new (body,
144 "nonce", json_string (nonce));
145
146 for (le = attrs->list_head; NULL != le; le = le->next)
147 {
148 attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type,
149 le->claim->data,
150 le->claim->data_size);
151 json_object_set_new (body,
152 le->claim->name,
153 json_string (attr_val_str));
154 GNUNET_free (attr_val_str);
155 }
156 body_str = json_dumps (body, JSON_INDENT(0) | JSON_COMPACT);
157 json_decref (body);
158
159 GNUNET_STRINGS_base64_encode (header,
160 strlen (header),
161 &header_base64);
162 fix_base64(header_base64);
163
164 GNUNET_STRINGS_base64_encode (body_str,
165 strlen (body_str),
166 &body_base64);
167 fix_base64(body_base64);
168
169 GNUNET_free (subject);
170 GNUNET_free (audience);
171
172 /**
173 * Creating the JWT signature. This might not be
174 * standards compliant, check.
175 */
176 GNUNET_asprintf (&signature_target, "%s.%s", header_base64, body_base64);
177 GNUNET_CRYPTO_hmac_raw (secret_key, strlen (secret_key), signature_target, strlen (signature_target), &signature);
178 GNUNET_STRINGS_base64_encode ((const char*)&signature,
179 sizeof (struct GNUNET_HashCode),
180 &signature_base64);
181 fix_base64(signature_base64);
182
183 GNUNET_asprintf (&result, "%s.%s.%s",
184 header_base64, body_base64, signature_base64);
185
186 GNUNET_free (signature_target);
187 GNUNET_free (header);
188 GNUNET_free (body_str);
189 GNUNET_free (signature_base64);
190 GNUNET_free (body_base64);
191 GNUNET_free (header_base64);
192 return result;
193}
194/**
195 * Builds an OIDC authorization code including
196 * a reclaim ticket and nonce
197 *
198 * @param issuer the issuer of the ticket, used to sign the ticket and nonce
199 * @param ticket the ticket to include in the code
200 * @param nonce the nonce to include in the code
201 * @return a new authorization code (caller must free)
202 */
203char*
204OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
205 const struct GNUNET_RECLAIM_Ticket *ticket,
206 const char* nonce)
207{
208 char *ticket_str;
209 json_t *code_json;
210 char *signature_payload;
211 char *signature_str;
212 char *authz_code;
213 size_t signature_payload_len;
214 struct GNUNET_CRYPTO_EcdsaSignature signature;
215 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
216
217 signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
218 if (NULL != nonce)
219 signature_payload_len += strlen (nonce);
220
221 signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
222 purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload;
223 purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
224 purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
225 memcpy (&purpose[1],
226 ticket,
227 sizeof (struct GNUNET_RECLAIM_Ticket));
228 if (NULL != nonce)
229 memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket),
230 nonce,
231 strlen (nonce));
232 if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer,
233 purpose,
234 &signature))
235 {
236 GNUNET_free (signature_payload);
237 return NULL;
238 }
239 signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature,
240 sizeof (signature));
241 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
242 sizeof (struct GNUNET_RECLAIM_Ticket));
243
244 code_json = json_object ();
245 json_object_set_new (code_json,
246 "ticket",
247 json_string (ticket_str));
248 if (NULL != nonce)
249 json_object_set_new (code_json,
250 "nonce",
251 json_string (nonce));
252 json_object_set_new (code_json,
253 "signature",
254 json_string (signature_str));
255 authz_code = json_dumps (code_json,
256 JSON_INDENT(0) | JSON_COMPACT);
257 GNUNET_free (signature_payload);
258 GNUNET_free (signature_str);
259 GNUNET_free (ticket_str);
260 json_decref (code_json);
261 return authz_code;
262}
263
264
265
266
267/**
268 * Parse reclaim ticket and nonce from
269 * authorization code.
270 * This also verifies the signature in the code.
271 *
272 * @param audience the expected audience of the code
273 * @param code the string representation of the code
274 * @param ticket where to store the ticket
275 * @param nonce where to store the nonce
276 * @return GNUNET_OK if successful, else GNUNET_SYSERR
277 */
278int
279OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
280 const char* code,
281 struct GNUNET_RECLAIM_Ticket **ticket,
282 char **nonce)
283{
284 json_error_t error;
285 json_t *code_json;
286 json_t *ticket_json;
287 json_t *nonce_json;
288 json_t *signature_json;
289 const char *ticket_str;
290 const char *signature_str;
291 const char *nonce_str;
292 char *code_output;
293 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
294 struct GNUNET_CRYPTO_EcdsaSignature signature;
295 size_t signature_payload_len;
296
297 code_output = NULL;
298 GNUNET_STRINGS_base64_decode (code,
299 strlen(code),
300 (void**)&code_output);
301 code_json = json_loads (code_output, 0 , &error);
302 GNUNET_free (code_output);
303 ticket_json = json_object_get (code_json, "ticket");
304 nonce_json = json_object_get (code_json, "nonce");
305 signature_json = json_object_get (code_json, "signature");
306 *ticket = NULL;
307 *nonce = NULL;
308
309 if ((NULL == ticket_json || !json_is_string (ticket_json)) ||
310 (NULL == signature_json || !json_is_string (signature_json)))
311 {
312 json_decref (code_json);
313 return GNUNET_SYSERR;
314 }
315 ticket_str = json_string_value (ticket_json);
316 signature_str = json_string_value (signature_json);
317 nonce_str = NULL;
318 if (NULL != nonce_json)
319 nonce_str = json_string_value (nonce_json);
320 signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
321 if (NULL != nonce_str)
322 signature_payload_len += strlen (nonce_str);
323 purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
324 signature_payload_len);
325 purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
326 purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
327 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str,
328 strlen (ticket_str),
329 &purpose[1],
330 sizeof (struct GNUNET_RECLAIM_Ticket)))
331 {
332 GNUNET_free (purpose);
333 json_decref (code_json);
334 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
335 "Cannot parse ticket!\n");
336 return GNUNET_SYSERR;
337 }
338 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str,
339 strlen (signature_str),
340 &signature,
341 sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
342 {
343 GNUNET_free (purpose);
344 json_decref (code_json);
345 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
346 "Cannot parse signature!\n");
347 return GNUNET_SYSERR;
348 }
349 *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
350 memcpy (*ticket,
351 &purpose[1],
352 sizeof (struct GNUNET_RECLAIM_Ticket));
353 if (0 != memcmp (audience,
354 &(*ticket)->audience,
355 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
356 {
357 GNUNET_free (purpose);
358 GNUNET_free (*ticket);
359 json_decref (code_json);
360 *ticket = NULL;
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 "Audience in ticket does not match client!\n");
363 return GNUNET_SYSERR;
364
365 }
366 if (NULL != nonce_str)
367 memcpy (((char*)&purpose[1]) + sizeof (struct GNUNET_RECLAIM_Ticket),
368 nonce_str,
369 strlen (nonce_str));
370 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
371 purpose,
372 &signature,
373 &(*ticket)->identity))
374 {
375 GNUNET_free (purpose);
376 GNUNET_free (*ticket);
377 json_decref (code_json);
378 *ticket = NULL;
379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
380 "Signature of authZ code invalid!\n");
381 return GNUNET_SYSERR;
382 }
383 *nonce = GNUNET_strdup (nonce_str);
384 return GNUNET_OK;
385}
386
387/**
388 * Build a token response for a token request
389 * TODO: Maybe we should add the scope here?
390 *
391 * @param access_token the access token to include
392 * @param id_token the id_token to include
393 * @param expiration_time the expiration time of the token(s)
394 * @param token_response where to store the response
395 */
396void
397OIDC_build_token_response (const char *access_token,
398 const char *id_token,
399 const struct GNUNET_TIME_Relative *expiration_time,
400 char **token_response)
401{
402 json_t *root_json;
403
404 root_json = json_object ();
405
406 GNUNET_assert (NULL != access_token);
407 GNUNET_assert (NULL != id_token);
408 GNUNET_assert (NULL != expiration_time);
409 json_object_set_new (root_json,
410 "access_token",
411 json_string (access_token));
412 json_object_set_new (root_json,
413 "token_type",
414 json_string ("Bearer"));
415 json_object_set_new (root_json,
416 "expires_in",
417 json_integer (expiration_time->rel_value_us / (1000 * 1000)));
418 json_object_set_new (root_json,
419 "id_token",
420 json_string (id_token));
421 *token_response = json_dumps (root_json,
422 JSON_INDENT(0) | JSON_COMPACT);
423 json_decref (root_json);
424}
425
426/**
427 * Generate a new access token
428 */
429char*
430OIDC_access_token_new ()
431{
432 char* access_token_number;
433 char* access_token;
434 uint64_t random_number;
435
436 random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
437 GNUNET_asprintf (&access_token_number, "%" PRIu64, random_number);
438 GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
439 return access_token;
440}
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h
new file mode 100644
index 000000000..7a0f45bf9
--- /dev/null
+++ b/src/reclaim/oidc_helper.h
@@ -0,0 +1,109 @@
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
19/**
20 * @file reclaim/oidc_helper.h
21 * @brief helper library for OIDC related functions
22 * @author Martin Schanzenbach
23 */
24
25#ifndef JWT_H
26#define JWT_H
27
28#define JWT_ALG "alg"
29
30/* Use 512bit HMAC */
31#define JWT_ALG_VALUE "HS512"
32
33#define JWT_TYP "typ"
34
35#define JWT_TYP_VALUE "jwt"
36
37#define SERVER_ADDRESS "https://reclaim.id"
38
39/**
40 * Create a JWT from attributes
41 *
42 * @param aud_key the public of the audience
43 * @param sub_key the public key of the subject
44 * @param attrs the attribute list
45 * @param expiration_time the validity of the token
46 * @param secret_key the key used to sign the JWT
47 * @return a new base64-encoded JWT string.
48 */
49char*
50OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
51 const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
52 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
53 const struct GNUNET_TIME_Relative *expiration_time,
54 const char *nonce,
55 const char *secret_key);
56
57/**
58 * Builds an OIDC authorization code including
59 * a reclaim ticket and nonce
60 *
61 * @param issuer the issuer of the ticket, used to sign the ticket and nonce
62 * @param ticket the ticket to include in the code
63 * @param nonce the nonce to include in the code
64 * @return a new authorization code (caller must free)
65 */
66char*
67OIDC_build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
68 const struct GNUNET_RECLAIM_Ticket *ticket,
69 const char* nonce);
70
71/**
72 * Parse reclaim ticket and nonce from
73 * authorization code.
74 * This also verifies the signature in the code.
75 *
76 * @param audience the expected audience of the code
77 * @param code the string representation of the code
78 * @param ticket where to store the ticket
79 * @param nonce where to store the nonce
80 * @return GNUNET_OK if successful, else GNUNET_SYSERR
81 */
82int
83OIDC_parse_authz_code (const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
84 const char* code,
85 struct GNUNET_RECLAIM_Ticket **ticket,
86 char **nonce);
87
88/**
89 * Build a token response for a token request
90 * TODO: Maybe we should add the scope here?
91 *
92 * @param access_token the access token to include
93 * @param id_token the id_token to include
94 * @param expiration_time the expiration time of the token(s)
95 * @param token_response where to store the response
96 */
97void
98OIDC_build_token_response (const char *access_token,
99 const char *id_token,
100 const struct GNUNET_TIME_Relative *expiration_time,
101 char **token_response);
102/**
103 * Generate a new access token
104 */
105char*
106OIDC_access_token_new ();
107
108
109#endif
diff --git a/src/reclaim/plugin_gnsrecord_reclaim.c b/src/reclaim/plugin_gnsrecord_reclaim.c
new file mode 100644
index 000000000..781b88abc
--- /dev/null
+++ b/src/reclaim/plugin_gnsrecord_reclaim.c
@@ -0,0 +1,271 @@
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
19/**
20 * @file reclaim/plugin_gnsrecord_reclaim.c
21 * @brief gnsrecord plugin to provide the API for identity records
22 * @author Martin Schanzenbach
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_gnsrecord_lib.h"
27#include "gnunet_gnsrecord_plugin.h"
28
29
30/**
31 * Convert the 'value' of a record to a string.
32 *
33 * @param cls closure, unused
34 * @param type type of the record
35 * @param data value in binary encoding
36 * @param data_size number of bytes in @a data
37 * @return NULL on error, otherwise human-readable representation of the value
38 */
39static char *
40value_to_string (void *cls,
41 uint32_t type,
42 const void *data,
43 size_t data_size)
44{
45 const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
46 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience_pubkey;
47 const char *scopes;
48 char *ecdhe_str;
49 char *aud_str;
50 char *result;
51
52 switch (type)
53 {
54 case GNUNET_GNSRECORD_TYPE_ID_ATTR:
55 return GNUNET_STRINGS_data_to_string_alloc (data, data_size);
56 case GNUNET_GNSRECORD_TYPE_ID_TOKEN: //DEPRECATED
57 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT:
58 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT:
59 return GNUNET_strndup (data, data_size);
60 case GNUNET_GNSRECORD_TYPE_ABE_KEY:
61 case GNUNET_GNSRECORD_TYPE_ABE_MASTER:
62 return GNUNET_STRINGS_data_to_string_alloc (data, data_size);
63 case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: //DEPRECATED
64 ecdhe_privkey = data;
65 audience_pubkey = data+sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
66 scopes = (char*) audience_pubkey+(sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
67 ecdhe_str = GNUNET_STRINGS_data_to_string_alloc (ecdhe_privkey,
68 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
69 aud_str = GNUNET_STRINGS_data_to_string_alloc (audience_pubkey,
70 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
71 GNUNET_asprintf (&result,
72 "%s;%s;%s",
73 ecdhe_str, aud_str, scopes);
74 GNUNET_free (aud_str);
75 GNUNET_free (ecdhe_str);
76 return result;
77
78 default:
79 return NULL;
80 }
81}
82
83
84/**
85 * Convert human-readable version of a 'value' of a record to the binary
86 * representation.
87 *
88 * @param cls closure, unused
89 * @param type type of the record
90 * @param s human-readable string
91 * @param data set to value in binary encoding (will be allocated)
92 * @param data_size set to number of bytes in @a data
93 * @return #GNUNET_OK on success
94 */
95static int
96string_to_value (void *cls,
97 uint32_t type,
98 const char *s,
99 void **data,
100 size_t *data_size)
101{
102 char* ecdhe_str;
103 char* aud_keystr;
104 char* write_ptr;
105 char* tmp_tok;
106 char* str;
107
108 if (NULL == s)
109 return GNUNET_SYSERR;
110 switch (type)
111 {
112 case GNUNET_GNSRECORD_TYPE_ID_ATTR:
113 return GNUNET_STRINGS_string_to_data (s,
114 strlen (s),
115 *data,
116 *data_size);
117 case GNUNET_GNSRECORD_TYPE_ID_TOKEN:
118 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT:
119 case GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT:
120 *data = GNUNET_strdup (s);
121 *data_size = strlen (s);
122 return GNUNET_OK;
123 case GNUNET_GNSRECORD_TYPE_ABE_KEY:
124 case GNUNET_GNSRECORD_TYPE_ABE_MASTER:
125 return GNUNET_STRINGS_string_to_data (s,
126 strlen (s),
127 *data,
128 *data_size);
129 case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA:
130 tmp_tok = GNUNET_strdup (s);
131 ecdhe_str = strtok (tmp_tok, ";");
132 if (NULL == ecdhe_str)
133 {
134 GNUNET_free (tmp_tok);
135 return GNUNET_SYSERR;
136 }
137 aud_keystr = strtok (NULL, ";");
138 if (NULL == aud_keystr)
139 {
140 GNUNET_free (tmp_tok);
141 return GNUNET_SYSERR;
142 }
143 str = strtok (NULL, ";");
144 if (NULL == str)
145 {
146 GNUNET_free (tmp_tok);
147 return GNUNET_SYSERR;
148 }
149 *data_size = strlen (str) + 1
150 +sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
151 +sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
152 *data = GNUNET_malloc (*data_size);
153
154 write_ptr = *data;
155 GNUNET_STRINGS_string_to_data (ecdhe_str,
156 strlen (ecdhe_str),
157 write_ptr,
158 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
159 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
160 GNUNET_STRINGS_string_to_data (aud_keystr,
161 strlen (aud_keystr),
162 write_ptr,
163 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
164 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
165 GNUNET_memcpy (write_ptr, str, strlen (str) + 1); //with 0-Terminator
166 GNUNET_free (tmp_tok);
167 return GNUNET_OK;
168
169 default:
170 return GNUNET_SYSERR;
171 }
172}
173
174
175/**
176 * Mapping of record type numbers to human-readable
177 * record type names.
178 */
179static struct {
180 const char *name;
181 uint32_t number;
182} name_map[] = {
183 { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR },
184 { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN },
185 { "ABE_KEY", GNUNET_GNSRECORD_TYPE_ABE_KEY },
186 { "ABE_MASTER", GNUNET_GNSRECORD_TYPE_ABE_MASTER },
187 { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA },
188 { "RECLAIM_OIDC_CLIENT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT },
189 { "RECLAIM_OIDC_REDIRECT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT },
190 { NULL, UINT32_MAX }
191};
192
193
194/**
195 * Convert a type name (i.e. "AAAA") to the corresponding number.
196 *
197 * @param cls closure, unused
198 * @param dns_typename name to convert
199 * @return corresponding number, UINT32_MAX on error
200 */
201static uint32_t
202typename_to_number (void *cls,
203 const char *dns_typename)
204{
205 unsigned int i;
206
207 i=0;
208 while ( (NULL != name_map[i].name) &&
209 (0 != strcasecmp (dns_typename, name_map[i].name)) )
210 i++;
211 return name_map[i].number;
212}
213
214
215/**
216 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
217 *
218 * @param cls closure, unused
219 * @param type number of a type to convert
220 * @return corresponding typestring, NULL on error
221 */
222static const char *
223number_to_typename (void *cls,
224 uint32_t type)
225{
226 unsigned int i;
227
228 i=0;
229 while ( (NULL != name_map[i].name) &&
230 (type != name_map[i].number) )
231 i++;
232 return name_map[i].name;
233}
234
235
236/**
237 * Entry point for the plugin.
238 *
239 * @param cls NULL
240 * @return the exported block API
241 */
242void *
243libgnunet_plugin_gnsrecord_reclaim_init (void *cls)
244{
245 struct GNUNET_GNSRECORD_PluginFunctions *api;
246
247 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
248 api->value_to_string = &value_to_string;
249 api->string_to_value = &string_to_value;
250 api->typename_to_number = &typename_to_number;
251 api->number_to_typename = &number_to_typename;
252 return api;
253}
254
255
256/**
257 * Exit point from the plugin.
258 *
259 * @param cls the return value from #libgnunet_plugin_block_test_init
260 * @return NULL
261 */
262void *
263libgnunet_plugin_gnsrecord_reclaim_done (void *cls)
264{
265 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
266
267 GNUNET_free (api);
268 return NULL;
269}
270
271/* end of plugin_gnsrecord_dns.c */
diff --git a/src/reclaim/plugin_reclaim_sqlite.c b/src/reclaim/plugin_reclaim_sqlite.c
new file mode 100644
index 000000000..b545a94e8
--- /dev/null
+++ b/src/reclaim/plugin_reclaim_sqlite.c
@@ -0,0 +1,734 @@
1 /*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2017 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
19/**
20 * @file reclaim/plugin_reclaim_sqlite.c
21 * @brief sqlite-based idp backend
22 * @author Martin Schanzenbach
23 */
24
25#include "platform.h"
26#include "gnunet_reclaim_service.h"
27#include "gnunet_reclaim_plugin.h"
28#include "gnunet_reclaim_attribute_lib.h"
29#include "gnunet_sq_lib.h"
30#include <sqlite3.h>
31
32/**
33 * After how many ms "busy" should a DB operation fail for good? A
34 * low value makes sure that we are more responsive to requests
35 * (especially PUTs). A high value guarantees a higher success rate
36 * (SELECTs in iterate can take several seconds despite LIMIT=1).
37 *
38 * The default value of 1s should ensure that users do not experience
39 * huge latencies while at the same time allowing operations to
40 * succeed with reasonable probability.
41 */
42#define BUSY_TIMEOUT_MS 1000
43
44
45/**
46 * Log an error message at log-level 'level' that indicates
47 * a failure of the command 'cmd' on file 'filename'
48 * with the message given by strerror(errno).
49 */
50#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "reclaim", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
51
52#define LOG(kind,...) GNUNET_log_from (kind, "reclaim-sqlite", __VA_ARGS__)
53
54
55/**
56 * Context for all functions in this plugin.
57 */
58struct Plugin
59{
60
61 const struct GNUNET_CONFIGURATION_Handle *cfg;
62
63 /**
64 * Database filename.
65 */
66 char *fn;
67
68 /**
69 * Native SQLite database handle.
70 */
71 sqlite3 *dbh;
72
73 /**
74 * Precompiled SQL to store ticket.
75 */
76 sqlite3_stmt *store_ticket;
77
78 /**
79 * Precompiled SQL to delete existing ticket.
80 */
81 sqlite3_stmt *delete_ticket;
82
83 /**
84 * Precompiled SQL to iterate tickets.
85 */
86 sqlite3_stmt *iterate_tickets;
87
88 /**
89 * Precompiled SQL to get ticket attributes.
90 */
91 sqlite3_stmt *get_ticket_attrs;
92
93 /**
94 * Precompiled SQL to iterate tickets by audience.
95 */
96 sqlite3_stmt *iterate_tickets_by_audience;
97};
98
99
100/**
101 * @brief Prepare a SQL statement
102 *
103 * @param dbh handle to the database
104 * @param zSql SQL statement, UTF-8 encoded
105 * @param ppStmt set to the prepared statement
106 * @return 0 on success
107 */
108static int
109sq_prepare (sqlite3 *dbh,
110 const char *zSql,
111 sqlite3_stmt **ppStmt)
112{
113 char *dummy;
114 int result;
115
116 result =
117 sqlite3_prepare_v2 (dbh,
118 zSql,
119 strlen (zSql),
120 ppStmt,
121 (const char **) &dummy);
122 LOG (GNUNET_ERROR_TYPE_DEBUG,
123 "Prepared `%s' / %p: %d\n",
124 zSql,
125 *ppStmt,
126 result);
127 return result;
128}
129
130/**
131 * Create our database indices.
132 *
133 * @param dbh handle to the database
134 */
135static void
136create_indices (sqlite3 * dbh)
137{
138 /* create indices */
139 if ( (SQLITE_OK !=
140 sqlite3_exec (dbh,
141 "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)",
142 NULL, NULL, NULL)) ||
143 (SQLITE_OK !=
144 sqlite3_exec (dbh,
145 "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)",
146 NULL, NULL, NULL)) )
147 LOG (GNUNET_ERROR_TYPE_ERROR,
148 "Failed to create indices: %s\n",
149 sqlite3_errmsg (dbh));
150}
151
152
153
154#if 0
155#define CHECK(a) GNUNET_break(a)
156#define ENULL NULL
157#else
158#define ENULL &e
159#define ENULL_DEFINED 1
160#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); }
161#endif
162
163
164/**
165 * Initialize the database connections and associated
166 * data structures (create tables and indices
167 * as needed as well).
168 *
169 * @param plugin the plugin context (state for this module)
170 * @return #GNUNET_OK on success
171 */
172static int
173database_setup (struct Plugin *plugin)
174{
175 sqlite3_stmt *stmt;
176 char *afsdir;
177#if ENULL_DEFINED
178 char *e;
179#endif
180
181 if (GNUNET_OK !=
182 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
183 "reclaim-sqlite",
184 "FILENAME",
185 &afsdir))
186 {
187 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
188 "reclaim-sqlite",
189 "FILENAME");
190 return GNUNET_SYSERR;
191 }
192 if (GNUNET_OK !=
193 GNUNET_DISK_file_test (afsdir))
194 {
195 if (GNUNET_OK !=
196 GNUNET_DISK_directory_create_for_file (afsdir))
197 {
198 GNUNET_break (0);
199 GNUNET_free (afsdir);
200 return GNUNET_SYSERR;
201 }
202 }
203 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
204 plugin->fn = afsdir;
205
206 /* Open database and precompile statements */
207 if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
208 {
209 LOG (GNUNET_ERROR_TYPE_ERROR,
210 _("Unable to initialize SQLite: %s.\n"),
211 sqlite3_errmsg (plugin->dbh));
212 return GNUNET_SYSERR;
213 }
214 CHECK (SQLITE_OK ==
215 sqlite3_exec (plugin->dbh,
216 "PRAGMA temp_store=MEMORY", NULL, NULL,
217 ENULL));
218 CHECK (SQLITE_OK ==
219 sqlite3_exec (plugin->dbh,
220 "PRAGMA synchronous=NORMAL", NULL, NULL,
221 ENULL));
222 CHECK (SQLITE_OK ==
223 sqlite3_exec (plugin->dbh,
224 "PRAGMA legacy_file_format=OFF", NULL, NULL,
225 ENULL));
226 CHECK (SQLITE_OK ==
227 sqlite3_exec (plugin->dbh,
228 "PRAGMA auto_vacuum=INCREMENTAL", NULL,
229 NULL, ENULL));
230 CHECK (SQLITE_OK ==
231 sqlite3_exec (plugin->dbh,
232 "PRAGMA encoding=\"UTF-8\"", NULL,
233 NULL, ENULL));
234 CHECK (SQLITE_OK ==
235 sqlite3_exec (plugin->dbh,
236 "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
237 ENULL));
238 CHECK (SQLITE_OK ==
239 sqlite3_exec (plugin->dbh,
240 "PRAGMA page_size=4092", NULL, NULL,
241 ENULL));
242
243 CHECK (SQLITE_OK ==
244 sqlite3_busy_timeout (plugin->dbh,
245 BUSY_TIMEOUT_MS));
246
247
248 /* Create table */
249 CHECK (SQLITE_OK ==
250 sq_prepare (plugin->dbh,
251 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'",
252 &stmt));
253 if ((sqlite3_step (stmt) == SQLITE_DONE) &&
254 (sqlite3_exec
255 (plugin->dbh,
256 "CREATE TABLE identity001tickets ("
257 " identity BLOB NOT NULL DEFAULT '',"
258 " audience BLOB NOT NULL DEFAULT '',"
259 " rnd INT8 NOT NULL DEFAULT '',"
260 " attributes BLOB NOT NULL DEFAULT ''"
261 ")",
262 NULL, NULL, NULL) != SQLITE_OK))
263 {
264 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR,
265 "sqlite3_exec");
266 sqlite3_finalize (stmt);
267 return GNUNET_SYSERR;
268 }
269 sqlite3_finalize (stmt);
270
271 create_indices (plugin->dbh);
272
273 if ( (SQLITE_OK !=
274 sq_prepare (plugin->dbh,
275 "INSERT INTO identity001tickets (identity, audience, rnd, attributes)"
276 " VALUES (?, ?, ?, ?)",
277 &plugin->store_ticket)) ||
278 (SQLITE_OK !=
279 sq_prepare (plugin->dbh,
280 "DELETE FROM identity001tickets WHERE identity=? AND rnd=?",
281 &plugin->delete_ticket)) ||
282 (SQLITE_OK !=
283 sq_prepare (plugin->dbh,
284 "SELECT identity,audience,rnd,attributes"
285 " FROM identity001tickets WHERE identity=? AND rnd=?",
286 &plugin->get_ticket_attrs)) ||
287 (SQLITE_OK !=
288 sq_prepare (plugin->dbh,
289 "SELECT identity,audience,rnd,attributes"
290 " FROM identity001tickets WHERE identity=?"
291 " ORDER BY rnd LIMIT 1 OFFSET ?",
292 &plugin->iterate_tickets)) ||
293 (SQLITE_OK !=
294 sq_prepare (plugin->dbh,
295 "SELECT identity,audience,rnd,attributes"
296 " FROM identity001tickets WHERE audience=?"
297 " ORDER BY rnd LIMIT 1 OFFSET ?",
298 &plugin->iterate_tickets_by_audience)) )
299 {
300 LOG_SQLITE (plugin,
301 GNUNET_ERROR_TYPE_ERROR,
302 "precompiling");
303 return GNUNET_SYSERR;
304 }
305 return GNUNET_OK;
306}
307
308
309/**
310 * Shutdown database connection and associate data
311 * structures.
312 * @param plugin the plugin context (state for this module)
313 */
314static void
315database_shutdown (struct Plugin *plugin)
316{
317 int result;
318 sqlite3_stmt *stmt;
319
320 if (NULL != plugin->store_ticket)
321 sqlite3_finalize (plugin->store_ticket);
322 if (NULL != plugin->delete_ticket)
323 sqlite3_finalize (plugin->delete_ticket);
324 if (NULL != plugin->iterate_tickets)
325 sqlite3_finalize (plugin->iterate_tickets);
326 if (NULL != plugin->iterate_tickets_by_audience)
327 sqlite3_finalize (plugin->iterate_tickets_by_audience);
328 if (NULL != plugin->get_ticket_attrs)
329 sqlite3_finalize (plugin->get_ticket_attrs);
330 result = sqlite3_close (plugin->dbh);
331 if (result == SQLITE_BUSY)
332 {
333 LOG (GNUNET_ERROR_TYPE_WARNING,
334 _("Tried to close sqlite without finalizing all prepared statements.\n"));
335 stmt = sqlite3_next_stmt (plugin->dbh,
336 NULL);
337 while (NULL != stmt)
338 {
339 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
340 "sqlite",
341 "Closing statement %p\n",
342 stmt);
343 result = sqlite3_finalize (stmt);
344 if (result != SQLITE_OK)
345 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
346 "sqlite",
347 "Failed to close statement %p: %d\n",
348 stmt,
349 result);
350 stmt = sqlite3_next_stmt (plugin->dbh,
351 NULL);
352 }
353 result = sqlite3_close (plugin->dbh);
354 }
355 if (SQLITE_OK != result)
356 LOG_SQLITE (plugin,
357 GNUNET_ERROR_TYPE_ERROR,
358 "sqlite3_close");
359
360 GNUNET_free_non_null (plugin->fn);
361}
362
363
364/**
365 * Store a ticket in the database.
366 *
367 * @param cls closure (internal context for the plugin)
368 * @param ticket the ticket to persist
369 * @param attrs the attributes associated with the ticket
370 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
371 */
372static int
373reclaim_sqlite_store_ticket (void *cls,
374 const struct GNUNET_RECLAIM_Ticket *ticket,
375 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
376{
377 struct Plugin *plugin = cls;
378 size_t attrs_len;
379 char *attrs_ser;
380 int n;
381
382 {
383 /* First delete duplicates */
384 struct GNUNET_SQ_QueryParam dparams[] = {
385 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
386 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
387 GNUNET_SQ_query_param_end
388 };
389 if (GNUNET_OK !=
390 GNUNET_SQ_bind (plugin->delete_ticket,
391 dparams))
392 {
393 LOG_SQLITE (plugin,
394 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
395 "sqlite3_bind_XXXX");
396 GNUNET_SQ_reset (plugin->dbh,
397 plugin->delete_ticket);
398 return GNUNET_SYSERR;
399 }
400 n = sqlite3_step (plugin->delete_ticket);
401 GNUNET_SQ_reset (plugin->dbh,
402 plugin->delete_ticket);
403
404 attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
405 attrs_ser = GNUNET_malloc (attrs_len);
406 GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs,
407 attrs_ser);
408 struct GNUNET_SQ_QueryParam sparams[] = {
409 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
410 GNUNET_SQ_query_param_auto_from_type (&ticket->audience),
411 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
412 GNUNET_SQ_query_param_fixed_size (attrs_ser, attrs_len),
413 GNUNET_SQ_query_param_end
414 };
415
416 if (GNUNET_OK !=
417 GNUNET_SQ_bind (plugin->store_ticket,
418 sparams))
419 {
420 LOG_SQLITE (plugin,
421 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
422 "sqlite3_bind_XXXX");
423 GNUNET_SQ_reset (plugin->dbh,
424 plugin->store_ticket);
425 return GNUNET_SYSERR;
426 }
427 n = sqlite3_step (plugin->store_ticket);
428 GNUNET_SQ_reset (plugin->dbh,
429 plugin->store_ticket);
430 GNUNET_free (attrs_ser);
431 }
432 switch (n)
433 {
434 case SQLITE_DONE:
435 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
436 "sqlite",
437 "Ticket stored\n");
438 return GNUNET_OK;
439 case SQLITE_BUSY:
440 LOG_SQLITE (plugin,
441 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
442 "sqlite3_step");
443 return GNUNET_NO;
444 default:
445 LOG_SQLITE (plugin,
446 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
447 "sqlite3_step");
448 return GNUNET_SYSERR;
449 }
450}
451
452
453/**
454 * Store a ticket in the database.
455 *
456 * @param cls closure (internal context for the plugin)
457 * @param ticket the ticket to delete
458 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
459 */
460static int
461reclaim_sqlite_delete_ticket (void *cls,
462 const struct GNUNET_RECLAIM_Ticket *ticket)
463{
464 struct Plugin *plugin = cls;
465 int n;
466
467 {
468 struct GNUNET_SQ_QueryParam sparams[] = {
469 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
470 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
471 GNUNET_SQ_query_param_end
472 };
473
474 if (GNUNET_OK !=
475 GNUNET_SQ_bind (plugin->delete_ticket,
476 sparams))
477 {
478 LOG_SQLITE (plugin,
479 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
480 "sqlite3_bind_XXXX");
481 GNUNET_SQ_reset (plugin->dbh,
482 plugin->store_ticket);
483 return GNUNET_SYSERR;
484 }
485 n = sqlite3_step (plugin->delete_ticket);
486 GNUNET_SQ_reset (plugin->dbh,
487 plugin->delete_ticket);
488 }
489 switch (n)
490 {
491 case SQLITE_DONE:
492 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
493 "sqlite",
494 "Ticket deleted\n");
495 return GNUNET_OK;
496 case SQLITE_BUSY:
497 LOG_SQLITE (plugin,
498 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
499 "sqlite3_step");
500 return GNUNET_NO;
501 default:
502 LOG_SQLITE (plugin,
503 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
504 "sqlite3_step");
505 return GNUNET_SYSERR;
506 }
507}
508
509
510/**
511 * The given 'sqlite' statement has been prepared to be run.
512 * It will return a record which should be given to the iterator.
513 * Runs the statement and parses the returned record.
514 *
515 * @param plugin plugin context
516 * @param stmt to run (and then clean up)
517 * @param iter iterator to call with the result
518 * @param iter_cls closure for @a iter
519 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
520 */
521static int
522get_ticket_and_call_iterator (struct Plugin *plugin,
523 sqlite3_stmt *stmt,
524 GNUNET_RECLAIM_TicketIterator iter,
525 void *iter_cls)
526{
527 struct GNUNET_RECLAIM_Ticket ticket;
528 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
529 int ret;
530 int sret;
531 size_t attrs_len;
532 char *attrs_ser;
533
534 ret = GNUNET_NO;
535 if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
536 {
537 struct GNUNET_SQ_ResultSpec rs[] = {
538 GNUNET_SQ_result_spec_auto_from_type (&ticket.identity),
539 GNUNET_SQ_result_spec_auto_from_type (&ticket.audience),
540 GNUNET_SQ_result_spec_uint64 (&ticket.rnd),
541 GNUNET_SQ_result_spec_variable_size ((void**)&attrs_ser,
542 &attrs_len),
543 GNUNET_SQ_result_spec_end
544
545 };
546 ret = GNUNET_SQ_extract_result (stmt,
547 rs);
548 if (GNUNET_OK != ret)
549 {
550 GNUNET_break (0);
551 ret = GNUNET_SYSERR;
552 }
553 else
554 {
555 attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attrs_ser,
556 attrs_len);
557 if (NULL != iter)
558 iter (iter_cls,
559 &ticket,
560 attrs);
561 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
562 ret = GNUNET_YES;
563 }
564 GNUNET_SQ_cleanup_result (rs);
565 }
566 else
567 {
568 if (SQLITE_DONE != sret)
569 LOG_SQLITE (plugin,
570 GNUNET_ERROR_TYPE_ERROR,
571 "sqlite_step");
572 }
573 GNUNET_SQ_reset (plugin->dbh,
574 stmt);
575 return ret;
576}
577
578
579/**
580 * Lookup tickets in the datastore.
581 *
582 * @param cls closure (internal context for the plugin)
583 * @param ticket the ticket to retrieve attributes for
584 * @param iter function to call with the result
585 * @param iter_cls closure for @a iter
586 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
587 */
588static int
589reclaim_sqlite_ticket_get_attrs (void *cls,
590 const struct GNUNET_RECLAIM_Ticket *ticket,
591 GNUNET_RECLAIM_TicketIterator iter,
592 void *iter_cls)
593{
594 struct Plugin *plugin = cls;
595 struct GNUNET_SQ_QueryParam params[] = {
596 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
597 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
598 GNUNET_SQ_query_param_end
599 };
600
601 if (GNUNET_OK !=
602 GNUNET_SQ_bind (plugin->get_ticket_attrs,
603 params))
604 {
605 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
606 "sqlite3_bind_XXXX");
607 GNUNET_SQ_reset (plugin->dbh,
608 plugin->get_ticket_attrs);
609 return GNUNET_SYSERR;
610 }
611 return get_ticket_and_call_iterator (plugin,
612 plugin->get_ticket_attrs,
613 iter,
614 iter_cls);
615}
616
617
618/**
619 * Iterate over the results for a particular key and zone in the
620 * datastore. Will return at most one result to the iterator.
621 *
622 * @param cls closure (internal context for the plugin)
623 * @param identity the issuing identity or audience (depending on audience switch)
624 * @param audience GNUNET_YES if identity is audience
625 * @param offset offset in the list of all matching records
626 * @param iter function to call with the result
627 * @param iter_cls closure for @a iter
628 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
629 */
630static int
631reclaim_sqlite_iterate_tickets (void *cls,
632 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
633 int audience,
634 uint64_t offset,
635 GNUNET_RECLAIM_TicketIterator iter,
636 void *iter_cls)
637{
638 struct Plugin *plugin = cls;
639 sqlite3_stmt *stmt;
640 int err;
641
642 if (NULL == identity)
643 {
644 GNUNET_break (0);
645 return GNUNET_SYSERR;
646 }
647 struct GNUNET_SQ_QueryParam params[] = {
648 GNUNET_SQ_query_param_auto_from_type (identity),
649 GNUNET_SQ_query_param_uint64 (&offset),
650 GNUNET_SQ_query_param_end
651 };
652 if (GNUNET_YES == audience)
653 {
654 stmt = plugin->iterate_tickets_by_audience;
655 err = GNUNET_SQ_bind (stmt,
656 params);
657 }
658 else
659 {
660 stmt = plugin->iterate_tickets;
661 err = GNUNET_SQ_bind (stmt,
662 params);
663 }
664 if (GNUNET_OK != err)
665 {
666 LOG_SQLITE (plugin,
667 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
668 "sqlite3_bind_XXXX");
669 GNUNET_SQ_reset (plugin->dbh,
670 stmt);
671 return GNUNET_SYSERR;
672 }
673 return get_ticket_and_call_iterator (plugin,
674 stmt,
675 iter,
676 iter_cls);
677}
678
679
680/**
681 * Entry point for the plugin.
682 *
683 * @param cls the "struct GNUNET_RECLAIM_PluginEnvironment*"
684 * @return NULL on error, otherwise the plugin context
685 */
686void *
687libgnunet_plugin_reclaim_sqlite_init (void *cls)
688{
689 static struct Plugin plugin;
690 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
691 struct GNUNET_RECLAIM_PluginFunctions *api;
692
693 if (NULL != plugin.cfg)
694 return NULL; /* can only initialize once! */
695 memset (&plugin, 0, sizeof (struct Plugin));
696 plugin.cfg = cfg;
697 if (GNUNET_OK != database_setup (&plugin))
698 {
699 database_shutdown (&plugin);
700 return NULL;
701 }
702 api = GNUNET_new (struct GNUNET_RECLAIM_PluginFunctions);
703 api->cls = &plugin;
704 api->store_ticket = &reclaim_sqlite_store_ticket;
705 api->delete_ticket = &reclaim_sqlite_delete_ticket;
706 api->iterate_tickets = &reclaim_sqlite_iterate_tickets;
707 api->get_ticket_attributes = &reclaim_sqlite_ticket_get_attrs;
708 LOG (GNUNET_ERROR_TYPE_INFO,
709 _("Sqlite database running\n"));
710 return api;
711}
712
713
714/**
715 * Exit point from the plugin.
716 *
717 * @param cls the plugin context (as returned by "init")
718 * @return always NULL
719 */
720void *
721libgnunet_plugin_reclaim_sqlite_done (void *cls)
722{
723 struct GNUNET_RECLAIM_PluginFunctions *api = cls;
724 struct Plugin *plugin = api->cls;
725
726 database_shutdown (plugin);
727 plugin->cfg = NULL;
728 GNUNET_free (api);
729 LOG (GNUNET_ERROR_TYPE_DEBUG,
730 "sqlite plugin is finished\n");
731 return NULL;
732}
733
734/* end of plugin_reclaim_sqlite.c */
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c
new file mode 100644
index 000000000..24673c692
--- /dev/null
+++ b/src/reclaim/plugin_rest_openid_connect.c
@@ -0,0 +1,2171 @@
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/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file identity/plugin_rest_openid_connect.c
22 * @brief GNUnet Namestore REST plugin
23 *
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_rest_lib.h"
33#include "gnunet_jsonapi_lib.h"
34#include "gnunet_jsonapi_util.h"
35#include "microhttpd.h"
36#include <jansson.h>
37#include <inttypes.h>
38#include "gnunet_signatures.h"
39#include "gnunet_reclaim_attribute_lib.h"
40#include "gnunet_reclaim_service.h"
41#include "oidc_helper.h"
42
43/**
44 * REST root namespace
45 */
46#define GNUNET_REST_API_NS_OIDC "/openid"
47
48/**
49 * Authorize endpoint
50 */
51#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize"
52
53/**
54 * Token endpoint
55 */
56#define GNUNET_REST_API_NS_TOKEN "/openid/token"
57
58/**
59 * UserInfo endpoint
60 */
61#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo"
62
63/**
64 * Login namespace
65 */
66#define GNUNET_REST_API_NS_LOGIN "/openid/login"
67
68/**
69 * Attribute key
70 */
71#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute"
72
73/**
74 * Ticket key
75 */
76#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
77
78
79/**
80 * Value key
81 */
82#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value"
83
84/**
85 * State while collecting all egos
86 */
87#define ID_REST_STATE_INIT 0
88
89/**
90 * Done collecting egos
91 */
92#define ID_REST_STATE_POST_INIT 1
93
94/**
95 * OIDC grant_type key
96 */
97#define OIDC_GRANT_TYPE_KEY "grant_type"
98
99/**
100 * OIDC grant_type key
101 */
102#define OIDC_GRANT_TYPE_VALUE "authorization_code"
103
104/**
105 * OIDC code key
106 */
107#define OIDC_CODE_KEY "code"
108
109/**
110 * OIDC response_type key
111 */
112#define OIDC_RESPONSE_TYPE_KEY "response_type"
113
114/**
115 * OIDC client_id key
116 */
117#define OIDC_CLIENT_ID_KEY "client_id"
118
119/**
120 * OIDC scope key
121 */
122#define OIDC_SCOPE_KEY "scope"
123
124/**
125 * OIDC redirect_uri key
126 */
127#define OIDC_REDIRECT_URI_KEY "redirect_uri"
128
129/**
130 * OIDC state key
131 */
132#define OIDC_STATE_KEY "state"
133
134/**
135 * OIDC nonce key
136 */
137#define OIDC_NONCE_KEY "nonce"
138
139/**
140 * OIDC cookie header key
141 */
142#define OIDC_COOKIE_HEADER_KEY "cookie"
143
144/**
145 * OIDC cookie header information key
146 */
147#define OIDC_AUTHORIZATION_HEADER_KEY "authorization"
148
149/**
150 * OIDC cookie header information key
151 */
152#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
153
154/**
155 * OIDC expected response_type while authorizing
156 */
157#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
158
159/**
160 * OIDC expected scope part while authorizing
161 */
162#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
163
164/**
165 * OIDC ignored parameter array
166 */
167static char* OIDC_ignored_parameter_array [] =
168{
169 "display",
170 "prompt",
171 "ui_locales",
172 "response_mode",
173 "id_token_hint",
174 "login_hint",
175 "acr_values"
176};
177
178/**
179 * OIDC authorized identities and times hashmap
180 */
181struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
182
183/**
184 * OIDC authorized identities and times hashmap
185 */
186struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
187
188/**
189 * OIDC ticket/code use only once
190 */
191struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
192
193/**
194 * OIDC access_token to ticket and ego
195 */
196struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
197
198/**
199 * The configuration handle
200 */
201const struct GNUNET_CONFIGURATION_Handle *cfg;
202
203/**
204 * HTTP methods allows for this plugin
205 */
206static char* allow_methods;
207
208/**
209 * @brief struct returned by the initialization function of the plugin
210 */
211struct Plugin
212{
213 const struct GNUNET_CONFIGURATION_Handle *cfg;
214};
215
216/**
217 * OIDC needed variables
218 */
219struct OIDC_Variables
220{
221 /**
222 * The RP client public key
223 */
224 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
225
226 /**
227 * The OIDC client id of the RP
228 */
229 char *client_id;
230
231 /**
232 * The OIDC redirect uri
233 */
234 char *redirect_uri;
235
236 /**
237 * The list of oidc scopes
238 */
239 char *scope;
240
241 /**
242 * The OIDC state
243 */
244 char *state;
245
246 /**
247 * The OIDC nonce
248 */
249 char *nonce;
250
251 /**
252 * The OIDC response type
253 */
254 char *response_type;
255
256 /**
257 * The identity chosen by the user to login
258 */
259 char *login_identity;
260
261 /**
262 * The response JSON
263 */
264 json_t *response;
265
266};
267
268/**
269 * The ego list
270 */
271struct EgoEntry
272{
273 /**
274 * DLL
275 */
276 struct EgoEntry *next;
277
278 /**
279 * DLL
280 */
281 struct EgoEntry *prev;
282
283 /**
284 * Ego Identifier
285 */
286 char *identifier;
287
288 /**
289 * Public key string
290 */
291 char *keystring;
292
293 /**
294 * The Ego
295 */
296 struct GNUNET_IDENTITY_Ego *ego;
297};
298
299
300struct RequestHandle
301{
302 /**
303 * Ego list
304 */
305 struct EgoEntry *ego_head;
306
307 /**
308 * Ego list
309 */
310 struct EgoEntry *ego_tail;
311
312 /**
313 * Selected ego
314 */
315 struct EgoEntry *ego_entry;
316
317 /**
318 * Pointer to ego private key
319 */
320 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
321
322 /**
323 * OIDC variables
324 */
325 struct OIDC_Variables *oidc;
326
327 /**
328 * The processing state
329 */
330 int state;
331
332 /**
333 * Handle to Identity service.
334 */
335 struct GNUNET_IDENTITY_Handle *identity_handle;
336
337 /**
338 * Rest connection
339 */
340 struct GNUNET_REST_RequestHandle *rest_handle;
341
342 /**
343 * GNS handle
344 */
345 struct GNUNET_GNS_Handle *gns_handle;
346
347 /**
348 * GNS lookup op
349 */
350 struct GNUNET_GNS_LookupRequest *gns_op;
351
352 /**
353 * Handle to NAMESTORE
354 */
355 struct GNUNET_NAMESTORE_Handle *namestore_handle;
356
357 /**
358 * Iterator for NAMESTORE
359 */
360 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
361
362 /**
363 * Attribute claim list
364 */
365 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
366
367 /**
368 * IDENTITY Operation
369 */
370 struct GNUNET_IDENTITY_Operation *op;
371
372 /**
373 * Identity Provider
374 */
375 struct GNUNET_RECLAIM_Handle *idp;
376
377 /**
378 * Idp Operation
379 */
380 struct GNUNET_RECLAIM_Operation *idp_op;
381
382 /**
383 * Attribute iterator
384 */
385 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
386
387 /**
388 * Ticket iterator
389 */
390 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
391
392 /**
393 * A ticket
394 */
395 struct GNUNET_RECLAIM_Ticket ticket;
396
397 /**
398 * Desired timeout for the lookup (default is no timeout).
399 */
400 struct GNUNET_TIME_Relative timeout;
401
402 /**
403 * ID of a task associated with the resolution process.
404 */
405 struct GNUNET_SCHEDULER_Task *timeout_task;
406
407 /**
408 * The plugin result processor
409 */
410 GNUNET_REST_ResultProcessor proc;
411
412 /**
413 * The closure of the result processor
414 */
415 void *proc_cls;
416
417 /**
418 * The url
419 */
420 char *url;
421
422 /**
423 * The tld for redirect
424 */
425 char *tld;
426
427 /**
428 * The redirect prefix
429 */
430 char *redirect_prefix;
431
432 /**
433 * The redirect suffix
434 */
435 char *redirect_suffix;
436
437 /**
438 * Error response message
439 */
440 char *emsg;
441
442 /**
443 * Error response description
444 */
445 char *edesc;
446
447 /**
448 * Reponse code
449 */
450 int response_code;
451
452 /**
453 * Response object
454 */
455 struct GNUNET_JSONAPI_Document *resp_object;
456
457};
458
459/**
460 * Cleanup lookup handle
461 * @param handle Handle to clean up
462 */
463static void
464cleanup_handle (struct RequestHandle *handle)
465{
466 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
467 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
468 struct EgoEntry *ego_entry;
469 struct EgoEntry *ego_tmp;
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471 "Cleaning up\n");
472 if (NULL != handle->resp_object)
473 GNUNET_JSONAPI_document_delete (handle->resp_object);
474 if (NULL != handle->timeout_task)
475 GNUNET_SCHEDULER_cancel (handle->timeout_task);
476 if (NULL != handle->identity_handle)
477 GNUNET_IDENTITY_disconnect (handle->identity_handle);
478 if (NULL != handle->attr_it)
479 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
480 if (NULL != handle->ticket_it)
481 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
482 if (NULL != handle->idp)
483 GNUNET_RECLAIM_disconnect (handle->idp);
484 if (NULL != handle->url)
485 GNUNET_free (handle->url);
486 if (NULL != handle->tld)
487 GNUNET_free (handle->tld);
488 if (NULL != handle->redirect_prefix)
489 GNUNET_free (handle->redirect_prefix);
490 if (NULL != handle->redirect_suffix)
491 GNUNET_free (handle->redirect_suffix);
492 if (NULL != handle->emsg)
493 GNUNET_free (handle->emsg);
494 if (NULL != handle->edesc)
495 GNUNET_free (handle->edesc);
496 if (NULL != handle->gns_op)
497 GNUNET_GNS_lookup_cancel (handle->gns_op);
498 if (NULL != handle->gns_handle)
499 GNUNET_GNS_disconnect (handle->gns_handle);
500
501 if (NULL != handle->namestore_handle)
502 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
503 if (NULL != handle->oidc)
504 {
505 if (NULL != handle->oidc->client_id)
506 GNUNET_free(handle->oidc->client_id);
507 if (NULL != handle->oidc->login_identity)
508 GNUNET_free(handle->oidc->login_identity);
509 if (NULL != handle->oidc->nonce)
510 GNUNET_free(handle->oidc->nonce);
511 if (NULL != handle->oidc->redirect_uri)
512 GNUNET_free(handle->oidc->redirect_uri);
513 if (NULL != handle->oidc->response_type)
514 GNUNET_free(handle->oidc->response_type);
515 if (NULL != handle->oidc->scope)
516 GNUNET_free(handle->oidc->scope);
517 if (NULL != handle->oidc->state)
518 GNUNET_free(handle->oidc->state);
519 if (NULL != handle->oidc->response)
520 json_decref(handle->oidc->response);
521 GNUNET_free(handle->oidc);
522 }
523 if ( NULL != handle->attr_list )
524 {
525 for (claim_entry = handle->attr_list->list_head;
526 NULL != claim_entry;)
527 {
528 claim_tmp = claim_entry;
529 claim_entry = claim_entry->next;
530 GNUNET_free(claim_tmp->claim);
531 GNUNET_free(claim_tmp);
532 }
533 GNUNET_free (handle->attr_list);
534 }
535 for (ego_entry = handle->ego_head;
536 NULL != ego_entry;)
537 {
538 ego_tmp = ego_entry;
539 ego_entry = ego_entry->next;
540 GNUNET_free (ego_tmp->identifier);
541 GNUNET_free (ego_tmp->keystring);
542 GNUNET_free (ego_tmp);
543 }
544 if (NULL != handle->attr_it)
545 {
546 GNUNET_free(handle->attr_it);
547 }
548 GNUNET_free (handle);
549}
550
551static void
552cleanup_handle_delayed (void *cls)
553{
554 cleanup_handle (cls);
555}
556
557
558/**
559 * Task run on error, sends error message. Cleans up everything.
560 *
561 * @param cls the `struct RequestHandle`
562 */
563static void
564do_error (void *cls)
565{
566 struct RequestHandle *handle = cls;
567 struct MHD_Response *resp;
568 char *json_error;
569
570 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
571 handle->emsg,
572 (NULL != handle->edesc) ? handle->edesc : "",
573 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
574 (NULL != handle->oidc->state) ? handle->oidc->state : "",
575 (NULL != handle->oidc->state) ? "\"" : "");
576 if ( 0 == handle->response_code )
577 {
578 handle->response_code = MHD_HTTP_BAD_REQUEST;
579 }
580 resp = GNUNET_REST_create_response (json_error);
581 if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
582 {
583 MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
584 }
585 MHD_add_response_header (resp, "Content-Type", "application/json");
586 handle->proc (handle->proc_cls, resp, handle->response_code);
587 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
588 GNUNET_free (json_error);
589}
590
591
592/**
593 * Task run on error in userinfo endpoint, sends error header. Cleans up
594 * everything
595 *
596 * @param cls the `struct RequestHandle`
597 */
598static void
599do_userinfo_error (void *cls)
600{
601 struct RequestHandle *handle = cls;
602 struct MHD_Response *resp;
603 char *error;
604
605 GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
606 handle->emsg,
607 (NULL != handle->edesc) ? handle->edesc : "");
608 resp = GNUNET_REST_create_response ("");
609 MHD_add_response_header(resp, "WWW-Authenticate", error);
610 handle->proc (handle->proc_cls, resp, handle->response_code);
611 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
612 GNUNET_free (error);
613}
614
615
616/**
617 * Task run on error, sends error message and redirects. Cleans up everything.
618 *
619 * @param cls the `struct RequestHandle`
620 */
621static void
622do_redirect_error (void *cls)
623{
624 struct RequestHandle *handle = cls;
625 struct MHD_Response *resp;
626 char* redirect;
627 GNUNET_asprintf (&redirect,
628 "%s?error=%s&error_description=%s%s%s",
629 handle->oidc->redirect_uri, handle->emsg, handle->edesc,
630 (NULL != handle->oidc->state) ? "&state=" : "",
631 (NULL != handle->oidc->state) ? handle->oidc->state : "");
632 resp = GNUNET_REST_create_response ("");
633 MHD_add_response_header (resp, "Location", redirect);
634 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
635 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
636 GNUNET_free (redirect);
637}
638
639/**
640 * Task run on timeout, sends error message. Cleans up everything.
641 *
642 * @param cls the `struct RequestHandle`
643 */
644static void
645do_timeout (void *cls)
646{
647 struct RequestHandle *handle = cls;
648
649 handle->timeout_task = NULL;
650 do_error (handle);
651}
652
653/**
654 * Return attributes for claim
655 *
656 * @param cls the request handle
657 */
658static void
659return_userinfo_response (void *cls)
660{
661 char* result_str;
662 struct RequestHandle *handle = cls;
663 struct MHD_Response *resp;
664
665 result_str = json_dumps (handle->oidc->response, 0);
666
667 resp = GNUNET_REST_create_response (result_str);
668 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
669 GNUNET_free (result_str);
670 cleanup_handle (handle);
671}
672
673/**
674 * Returns base64 encoded string without padding
675 *
676 * @param string the string to encode
677 * @return base64 encoded string
678 */
679static char*
680base_64_encode(const char *s)
681{
682 char *enc;
683 char *tmp;
684
685 GNUNET_STRINGS_base64_encode(s, strlen(s), &enc);
686 tmp = strrchr (enc, '=');
687 *tmp = '\0';
688 return enc;
689}
690
691/**
692 * Respond to OPTIONS request
693 *
694 * @param con_handle the connection handle
695 * @param url the url
696 * @param cls the RequestHandle
697 */
698static void
699options_cont (struct GNUNET_REST_RequestHandle *con_handle,
700 const char* url,
701 void *cls)
702{
703 struct MHD_Response *resp;
704 struct RequestHandle *handle = cls;
705
706 //For now, independent of path return all options
707 resp = GNUNET_REST_create_response (NULL);
708 MHD_add_response_header (resp,
709 "Access-Control-Allow-Methods",
710 allow_methods);
711 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
712 cleanup_handle (handle);
713 return;
714}
715
716/**
717 * Interprets cookie header and pass its identity keystring to handle
718 */
719static void
720cookie_identity_interpretation (struct RequestHandle *handle)
721{
722 struct GNUNET_HashCode cache_key;
723 char *cookies;
724 struct GNUNET_TIME_Absolute current_time, *relog_time;
725 char delimiter[] = "; ";
726
727 //gets identity of login try with cookie
728 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
729 &cache_key);
730 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
731 &cache_key) )
732 {
733 //splits cookies and find 'Identity' cookie
734 cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
735 handle->oidc->login_identity = strtok(cookies, delimiter);
736
737 while ( NULL != handle->oidc->login_identity )
738 {
739 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
740 {
741 break;
742 }
743 handle->oidc->login_identity = strtok (NULL, delimiter);
744 }
745 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
746 &cache_key);
747 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
748 {
749 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
750 &cache_key);
751 current_time = GNUNET_TIME_absolute_get ();
752 // 30 min after old login -> redirect to login
753 if ( current_time.abs_value_us <= relog_time->abs_value_us )
754 {
755 handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
756 handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
757 } else {
758 handle->oidc->login_identity = NULL;
759 }
760 }
761 else
762 {
763 handle->oidc->login_identity = NULL;
764 }
765 }
766}
767
768/**
769 * Redirects to login page stored in configuration file
770 */
771static void
772login_redirection(void *cls)
773{
774 char *login_base_url;
775 char *new_redirect;
776 struct MHD_Response *resp;
777 struct RequestHandle *handle = cls;
778
779 if ( GNUNET_OK
780 == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
781 "address", &login_base_url) )
782 {
783 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
784 login_base_url,
785 OIDC_RESPONSE_TYPE_KEY,
786 handle->oidc->response_type,
787 OIDC_CLIENT_ID_KEY,
788 handle->oidc->client_id,
789 OIDC_REDIRECT_URI_KEY,
790 handle->oidc->redirect_uri,
791 OIDC_SCOPE_KEY,
792 handle->oidc->scope,
793 OIDC_STATE_KEY,
794 (NULL != handle->oidc->state) ? handle->oidc->state : "",
795 OIDC_NONCE_KEY,
796 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
797 resp = GNUNET_REST_create_response ("");
798 MHD_add_response_header (resp, "Location", new_redirect);
799 GNUNET_free(login_base_url);
800 }
801 else
802 {
803 handle->emsg = GNUNET_strdup("server_error");
804 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
805 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
806 GNUNET_SCHEDULER_add_now (&do_error, handle);
807 return;
808 }
809 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
810 GNUNET_free(new_redirect);
811 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
812}
813
814/**
815 * Does internal server error when iteration failed.
816 */
817static void
818oidc_iteration_error (void *cls)
819{
820 struct RequestHandle *handle = cls;
821 handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
822 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
823 GNUNET_SCHEDULER_add_now (&do_error, handle);
824}
825
826static void
827get_client_name_result (void *cls,
828 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
829 const char *label,
830 unsigned int rd_count,
831 const struct GNUNET_GNSRECORD_Data *rd)
832{
833 struct RequestHandle *handle = cls;
834 struct MHD_Response *resp;
835 char *ticket_str;
836 char *redirect_uri;
837 char *code_json_string;
838 char *code_base64_final_string;
839
840 ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
841 sizeof (struct GNUNET_RECLAIM_Ticket));
842 //TODO change if more attributes are needed (see max_age)
843 code_json_string = OIDC_build_authz_code (&handle->priv_key,
844 &handle->ticket,
845 handle->oidc->nonce);
846 code_base64_final_string = base_64_encode(code_json_string);
847 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
848 handle->redirect_prefix,
849 handle->tld,
850 handle->redirect_suffix,
851 handle->oidc->response_type,
852 code_base64_final_string, handle->oidc->state);
853 resp = GNUNET_REST_create_response ("");
854 MHD_add_response_header (resp, "Location", redirect_uri);
855 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
856 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
857 GNUNET_free (redirect_uri);
858 GNUNET_free (ticket_str);
859 GNUNET_free (code_json_string);
860 GNUNET_free (code_base64_final_string);
861 return;
862
863}
864
865
866static void
867get_client_name_error (void *cls)
868{
869 struct RequestHandle *handle = cls;
870
871 handle->emsg = GNUNET_strdup("server_error");
872 handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client.");
873 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
874}
875
876
877static void
878lookup_redirect_uri_result (void *cls,
879 uint32_t rd_count,
880 const struct GNUNET_GNSRECORD_Data *rd)
881{
882 struct RequestHandle *handle = cls;
883 char *tmp;
884 char *tmp_key_str;
885 char *pos;
886 struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
887
888 handle->gns_op = NULL;
889 if (0 == rd_count)
890 {
891 handle->emsg = GNUNET_strdup("server_error");
892 handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found.");
893 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
894 return;
895 }
896 for (int i = 0; i < rd_count; i++)
897 {
898 if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
899 continue;
900 if (0 != strcmp (rd[i].data,
901 handle->oidc->redirect_uri))
902 continue;
903 tmp = GNUNET_strdup (rd[i].data);
904 pos = strrchr (tmp,
905 (unsigned char) '.');
906 *pos = '\0';
907 handle->redirect_prefix = GNUNET_strdup (tmp);
908 tmp_key_str = pos + 1;
909 pos = strchr (tmp_key_str,
910 (unsigned char) '/');
911 *pos = '\0';
912 handle->redirect_suffix = GNUNET_strdup (pos + 1);
913
914 GNUNET_STRINGS_string_to_data (tmp_key_str,
915 strlen (tmp_key_str),
916 &redirect_zone,
917 sizeof (redirect_zone));
918
919 GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle,
920 &handle->priv_key,
921 &redirect_zone,
922 &get_client_name_error,
923 handle,
924 &get_client_name_result,
925 handle);
926 GNUNET_free (tmp);
927 return;
928 }
929 handle->emsg = GNUNET_strdup("server_error");
930 handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found.");
931 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
932}
933
934/**
935 * Issues ticket and redirects to relying party with the authorization code as
936 * parameter. Otherwise redirects with error
937 */
938static void
939oidc_ticket_issue_cb (void* cls,
940 const struct GNUNET_RECLAIM_Ticket *ticket)
941{
942 struct RequestHandle *handle = cls;
943
944 handle->idp_op = NULL;
945 handle->ticket = *ticket;
946 if (NULL == ticket)
947 {
948 handle->emsg = GNUNET_strdup("server_error");
949 handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
950 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
951 return;
952 }
953 handle->gns_op = GNUNET_GNS_lookup (handle->gns_handle,
954 "+",
955 &handle->oidc->client_pkey,
956 GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT,
957 GNUNET_GNS_LO_DEFAULT,
958 &lookup_redirect_uri_result,
959 handle);
960
961}
962
963static void
964oidc_collect_finished_cb (void *cls)
965{
966 struct RequestHandle *handle = cls;
967 handle->attr_it = NULL;
968 handle->ticket_it = NULL;
969 if (NULL == handle->attr_list->list_head)
970 {
971 handle->emsg = GNUNET_strdup("invalid_scope");
972 handle->edesc = GNUNET_strdup("The requested scope is not available.");
973 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
974 return;
975 }
976 handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
977 &handle->priv_key,
978 &handle->oidc->client_pkey,
979 handle->attr_list,
980 &oidc_ticket_issue_cb,
981 handle);
982}
983
984
985/**
986 * Collects all attributes for an ego if in scope parameter
987 */
988static void
989oidc_attr_collect (void *cls,
990 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
991 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
992{
993 struct RequestHandle *handle = cls;
994 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
995 char* scope_variables;
996 char* scope_variable;
997 char delimiter[]=" ";
998
999 if ( (NULL == attr->name) || (NULL == attr->data) )
1000 {
1001 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1002 return;
1003 }
1004
1005 scope_variables = GNUNET_strdup(handle->oidc->scope);
1006 scope_variable = strtok (scope_variables, delimiter);
1007 while (NULL != scope_variable)
1008 {
1009 if ( 0 == strcmp (attr->name, scope_variable) )
1010 {
1011 break;
1012 }
1013 scope_variable = strtok (NULL, delimiter);
1014 }
1015 if ( NULL == scope_variable )
1016 {
1017 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1018 GNUNET_free(scope_variables);
1019 return;
1020 }
1021 GNUNET_free(scope_variables);
1022
1023 le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1024 le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type,
1025 attr->data, attr->data_size);
1026 GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1027 handle->attr_list->list_tail, le);
1028 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1029}
1030
1031
1032/**
1033 * Checks time and cookie and redirects accordingly
1034 */
1035static void
1036login_check (void *cls)
1037{
1038 struct RequestHandle *handle = cls;
1039 struct GNUNET_TIME_Absolute current_time, *relog_time;
1040 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1041 struct GNUNET_HashCode cache_key;
1042 char *identity_cookie;
1043
1044 GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1045 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1046 GNUNET_free(identity_cookie);
1047 //No login time for identity -> redirect to login
1048 if ( GNUNET_YES
1049 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1050 &cache_key) )
1051 {
1052 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1053 &cache_key);
1054 current_time = GNUNET_TIME_absolute_get ();
1055 // 30 min after old login -> redirect to login
1056 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1057 {
1058 if ( GNUNET_OK
1059 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1060 handle->oidc->login_identity,
1061 strlen (handle->oidc->login_identity), &pubkey) )
1062 {
1063 handle->emsg = GNUNET_strdup("invalid_cookie");
1064 handle->edesc = GNUNET_strdup(
1065 "The cookie of a login identity is not valid");
1066 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1067 return;
1068 }
1069 // iterate over egos and compare their public key
1070 for (handle->ego_entry = handle->ego_head;
1071 NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1072 {
1073 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1074 if ( 0
1075 == memcmp (&ego_pkey, &pubkey,
1076 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1077 {
1078 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1079 handle->ego_entry->ego);
1080 handle->resp_object = GNUNET_JSONAPI_document_new ();
1081 handle->idp = GNUNET_RECLAIM_connect (cfg);
1082 handle->attr_list = GNUNET_new(
1083 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1084 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
1085 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1086 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1087 return;
1088 }
1089 }
1090 //handle->emsg = GNUNET_strdup("invalid_cookie");
1091 //handle->edesc = GNUNET_strdup(
1092 // "The cookie of the login identity is not valid");
1093 //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1094 GNUNET_SCHEDULER_add_now (&login_redirection,handle);
1095 return;
1096 }
1097 }
1098}
1099
1100/**
1101 * Iteration over all results finished, build final
1102 * response.
1103 *
1104 * @param cls the `struct RequestHandle`
1105 */
1106static void
1107build_authz_response (void *cls)
1108{
1109 struct RequestHandle *handle = cls;
1110 struct GNUNET_HashCode cache_key;
1111
1112 char *expected_scope;
1113 char delimiter[]=" ";
1114 int number_of_ignored_parameter, iterator;
1115
1116
1117 // REQUIRED value: redirect_uri
1118 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1119 &cache_key);
1120 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1121 &cache_key))
1122 {
1123 handle->emsg=GNUNET_strdup("invalid_request");
1124 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1125 GNUNET_SCHEDULER_add_now (&do_error, handle);
1126 return;
1127 }
1128 handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1129 &cache_key));
1130
1131 // REQUIRED value: response_type
1132 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1133 &cache_key);
1134 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1135 &cache_key))
1136 {
1137 handle->emsg=GNUNET_strdup("invalid_request");
1138 handle->edesc=GNUNET_strdup("missing parameter response_type");
1139 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1140 return;
1141 }
1142 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1143 &cache_key);
1144 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1145
1146 // REQUIRED value: scope
1147 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1148 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1149 &cache_key))
1150 {
1151 handle->emsg=GNUNET_strdup("invalid_request");
1152 handle->edesc=GNUNET_strdup("missing parameter scope");
1153 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1154 return;
1155 }
1156 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1157 &cache_key);
1158 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1159
1160 //OPTIONAL value: nonce
1161 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1162 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1163 &cache_key))
1164 {
1165 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1166 &cache_key);
1167 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1168 }
1169
1170 //TODO check other values if needed
1171 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1172 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1173 {
1174 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1175 strlen(OIDC_ignored_parameter_array[iterator]),
1176 &cache_key);
1177 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1178 &cache_key))
1179 {
1180 handle->emsg=GNUNET_strdup("access_denied");
1181 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1182 OIDC_ignored_parameter_array[iterator]);
1183 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1184 return;
1185 }
1186 }
1187
1188 // Checks if response_type is 'code'
1189 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1190 {
1191 handle->emsg=GNUNET_strdup("unsupported_response_type");
1192 handle->edesc=GNUNET_strdup("The authorization server does not support "
1193 "obtaining this authorization code.");
1194 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1195 return;
1196 }
1197
1198 // Checks if scope contains 'openid'
1199 expected_scope = GNUNET_strdup(handle->oidc->scope);
1200 char* test;
1201 test = strtok (expected_scope, delimiter);
1202 while (NULL != test)
1203 {
1204 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1205 {
1206 break;
1207 }
1208 test = strtok (NULL, delimiter);
1209 }
1210 if (NULL == test)
1211 {
1212 handle->emsg = GNUNET_strdup("invalid_scope");
1213 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1214 "malformed.");
1215 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1216 GNUNET_free(expected_scope);
1217 return;
1218 }
1219
1220 GNUNET_free(expected_scope);
1221
1222 if( NULL != handle->oidc->login_identity )
1223 {
1224 GNUNET_SCHEDULER_add_now(&login_check,handle);
1225 return;
1226 }
1227
1228 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1229}
1230
1231/**
1232 * Responds to authorization GET and url-encoded POST request
1233 *
1234 * @param con_handle the connection handle
1235 * @param url the url
1236 * @param cls the RequestHandle
1237 */
1238static void
1239authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1240 const char* url,
1241 void *cls)
1242{
1243 struct RequestHandle *handle = cls;
1244 struct GNUNET_HashCode cache_key;
1245 struct EgoEntry *tmp_ego;
1246 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1247 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1248
1249 cookie_identity_interpretation(handle);
1250
1251 //RECOMMENDED value: state - REQUIRED for answers
1252 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1253 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1254 &cache_key))
1255 {
1256 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1257 &cache_key);
1258 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1259 }
1260
1261 // REQUIRED value: client_id
1262 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1263 &cache_key);
1264 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1265 &cache_key))
1266 {
1267 handle->emsg=GNUNET_strdup("invalid_request");
1268 handle->edesc=GNUNET_strdup("missing parameter client_id");
1269 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1270 GNUNET_SCHEDULER_add_now (&do_error, handle);
1271 return;
1272 }
1273 handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1274 &cache_key));
1275
1276 if ( GNUNET_OK
1277 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1278 strlen (handle->oidc->client_id),
1279 &handle->oidc->client_pkey) )
1280 {
1281 handle->emsg = GNUNET_strdup("unauthorized_client");
1282 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1283 "authorization code using this method.");
1284 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1285 GNUNET_SCHEDULER_add_now (&do_error, handle);
1286 return;
1287 }
1288
1289
1290 if ( NULL == handle->ego_head )
1291 {
1292 handle->emsg = GNUNET_strdup("server_error");
1293 handle->edesc = GNUNET_strdup ("Egos are missing");
1294 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1295 GNUNET_SCHEDULER_add_now (&do_error, handle);
1296 return;
1297 }
1298
1299 handle->ego_entry = handle->ego_head;
1300 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1301 //If we know this identity, translated the corresponding TLD
1302 //TODO: We might want to have a reverse lookup functionality for TLDs?
1303 for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1304 {
1305 priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1306 GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
1307 &pkey);
1308 if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey,
1309 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1310 {
1311 handle->tld = GNUNET_strdup (tmp_ego->identifier);
1312 handle->ego_entry = handle->ego_tail;
1313 }
1314 }
1315 GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
1316}
1317
1318/**
1319 * Combines an identity with a login time and responds OK to login request
1320 *
1321 * @param con_handle the connection handle
1322 * @param url the url
1323 * @param cls the RequestHandle
1324 */
1325static void
1326login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1327 const char* url,
1328 void *cls)
1329{
1330 struct MHD_Response *resp = GNUNET_REST_create_response ("");
1331 struct RequestHandle *handle = cls;
1332 struct GNUNET_HashCode cache_key;
1333 struct GNUNET_TIME_Absolute *current_time;
1334 struct GNUNET_TIME_Absolute *last_time;
1335 char* cookie;
1336 json_t *root;
1337 json_error_t error;
1338 json_t *identity;
1339 char term_data[handle->rest_handle->data_size+1];
1340 term_data[handle->rest_handle->data_size] = '\0';
1341 GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size);
1342 root = json_loads (term_data, JSON_DECODE_ANY, &error);
1343 identity = json_object_get (root, "identity");
1344 if ( json_is_string(identity) )
1345 {
1346 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1347 MHD_add_response_header (resp, "Set-Cookie", cookie);
1348 MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1349 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1350
1351 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1352 *current_time = GNUNET_TIME_relative_to_absolute (
1353 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
1354 5));
1355 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1356 if (NULL != last_time)
1357 {
1358 GNUNET_free(last_time);
1359 }
1360 GNUNET_CONTAINER_multihashmap_put (
1361 OIDC_identity_login_time, &cache_key, current_time,
1362 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1363
1364 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1365 GNUNET_free(cookie);
1366 }
1367 else
1368 {
1369 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1370 }
1371 json_decref (root);
1372 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1373 return;
1374}
1375
1376static int
1377check_authorization (struct RequestHandle *handle,
1378 struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1379{
1380 struct GNUNET_HashCode cache_key;
1381 char *authorization;
1382 char *credentials;
1383 char *basic_authorization;
1384 char *client_id;
1385 char *pass;
1386 char *expected_pass;
1387 int client_exists = GNUNET_NO;
1388
1389 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1390 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1391 &cache_key);
1392 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1393 &cache_key) )
1394 {
1395 handle->emsg=GNUNET_strdup("invalid_client");
1396 handle->edesc=GNUNET_strdup("missing authorization");
1397 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1398 return GNUNET_SYSERR;
1399 }
1400 authorization = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
1401 &cache_key);
1402
1403 //split header in "Basic" and [content]
1404 credentials = strtok (authorization, " ");
1405 if (0 != strcmp ("Basic", credentials))
1406 {
1407 handle->emsg=GNUNET_strdup("invalid_client");
1408 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1409 return GNUNET_SYSERR;
1410 }
1411 credentials = strtok(NULL, " ");
1412 if (NULL == credentials)
1413 {
1414 handle->emsg=GNUNET_strdup("invalid_client");
1415 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1416 return GNUNET_SYSERR;
1417 }
1418 GNUNET_STRINGS_base64_decode (credentials,
1419 strlen (credentials),
1420 (void**)&basic_authorization);
1421
1422 if ( NULL == basic_authorization )
1423 {
1424 handle->emsg=GNUNET_strdup("invalid_client");
1425 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1426 return GNUNET_SYSERR;
1427 }
1428 client_id = strtok (basic_authorization, ":");
1429 if ( NULL == client_id )
1430 {
1431 GNUNET_free_non_null(basic_authorization);
1432 handle->emsg=GNUNET_strdup("invalid_client");
1433 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1434 return GNUNET_SYSERR;
1435 }
1436 pass = strtok (NULL, ":");
1437 if (NULL == pass)
1438 {
1439 GNUNET_free_non_null(basic_authorization);
1440 handle->emsg=GNUNET_strdup("invalid_client");
1441 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1442 return GNUNET_SYSERR;
1443 }
1444
1445 //check client password
1446 if ( GNUNET_OK
1447 == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
1448 "psw", &expected_pass) )
1449 {
1450 if (0 != strcmp (expected_pass, pass))
1451 {
1452 GNUNET_free_non_null(basic_authorization);
1453 GNUNET_free(expected_pass);
1454 handle->emsg=GNUNET_strdup("invalid_client");
1455 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1456 return GNUNET_SYSERR;
1457 }
1458 GNUNET_free(expected_pass);
1459 }
1460 else
1461 {
1462 GNUNET_free_non_null(basic_authorization);
1463 handle->emsg = GNUNET_strdup("server_error");
1464 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1465 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1466 return GNUNET_SYSERR;
1467 }
1468
1469 //check client_id
1470 for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
1471 {
1472 if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
1473 {
1474 client_exists = GNUNET_YES;
1475 break;
1476 }
1477 handle->ego_entry = handle->ego_entry->next;
1478 }
1479 if (GNUNET_NO == client_exists)
1480 {
1481 GNUNET_free_non_null(basic_authorization);
1482 handle->emsg=GNUNET_strdup("invalid_client");
1483 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1484 return GNUNET_SYSERR;
1485 }
1486 GNUNET_STRINGS_string_to_data (client_id,
1487 strlen(client_id),
1488 cid,
1489 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1490
1491 GNUNET_free (basic_authorization);
1492 return GNUNET_OK;
1493}
1494
1495static int
1496ego_exists (struct RequestHandle *handle,
1497 struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
1498{
1499 struct EgoEntry *ego_entry;
1500 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1501
1502 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1503 {
1504 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1505 if (0 == memcmp (&pub_key,
1506 test_key,
1507 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1508 {
1509 break;
1510 }
1511 }
1512 if (NULL == ego_entry)
1513 return GNUNET_NO;
1514 return GNUNET_YES;
1515}
1516
1517static void
1518store_ticket_reference (const struct RequestHandle *handle,
1519 const char* access_token,
1520 const struct GNUNET_RECLAIM_Ticket *ticket,
1521 const struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
1522{
1523 struct GNUNET_HashCode cache_key;
1524 char *id_ticket_combination;
1525 char *ticket_string;
1526 char *client_id;
1527
1528 GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
1529 client_id = GNUNET_STRINGS_data_to_string_alloc (cid,
1530 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1531 ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket,
1532 sizeof (struct GNUNET_RECLAIM_Ticket));
1533 GNUNET_asprintf(&id_ticket_combination,
1534 "%s;%s",
1535 client_id,
1536 ticket_string);
1537 GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
1538 &cache_key,
1539 id_ticket_combination,
1540 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1541
1542 GNUNET_free (client_id);
1543 GNUNET_free (ticket_string);
1544}
1545
1546/**
1547 * Responds to token url-encoded POST request
1548 *
1549 * @param con_handle the connection handle
1550 * @param url the url
1551 * @param cls the RequestHandle
1552 */
1553static void
1554token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1555 const char* url,
1556 void *cls)
1557{
1558 struct RequestHandle *handle = cls;
1559 struct GNUNET_TIME_Relative expiration_time;
1560 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl;
1561 struct GNUNET_RECLAIM_Ticket *ticket;
1562 struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1563 struct GNUNET_HashCode cache_key;
1564 struct MHD_Response *resp;
1565 char *grant_type;
1566 char *code;
1567 char *json_response;
1568 char *id_token;
1569 char *access_token;
1570 char *jwt_secret;
1571 char *nonce;
1572 int i = 1;
1573
1574 /*
1575 * Check Authorization
1576 */
1577 if (GNUNET_SYSERR == check_authorization (handle,
1578 &cid))
1579 {
1580 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1581 "OIDC authorization for token endpoint failed\n");
1582 GNUNET_SCHEDULER_add_now (&do_error, handle);
1583 return;
1584 }
1585
1586 /*
1587 * Check parameter
1588 */
1589
1590 //TODO Do not allow multiple equal parameter names
1591 //REQUIRED grant_type
1592 GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
1593 if (GNUNET_NO ==
1594 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1595 &cache_key))
1596 {
1597 handle->emsg = GNUNET_strdup("invalid_request");
1598 handle->edesc = GNUNET_strdup("missing parameter grant_type");
1599 handle->response_code = MHD_HTTP_BAD_REQUEST;
1600 GNUNET_SCHEDULER_add_now (&do_error, handle);
1601 return;
1602 }
1603 grant_type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1604 &cache_key);
1605
1606 //REQUIRED code
1607 GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
1608 if (GNUNET_NO ==
1609 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1610 &cache_key))
1611 {
1612 handle->emsg = GNUNET_strdup("invalid_request");
1613 handle->edesc = GNUNET_strdup("missing parameter code");
1614 handle->response_code = MHD_HTTP_BAD_REQUEST;
1615 GNUNET_SCHEDULER_add_now (&do_error, handle);
1616 return;
1617 }
1618 code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1619 &cache_key);
1620
1621 //REQUIRED redirect_uri
1622 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1623 &cache_key);
1624 if (GNUNET_NO ==
1625 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1626 &cache_key) )
1627 {
1628 handle->emsg = GNUNET_strdup("invalid_request");
1629 handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
1630 handle->response_code = MHD_HTTP_BAD_REQUEST;
1631 GNUNET_SCHEDULER_add_now (&do_error, handle);
1632 return;
1633 }
1634
1635 //Check parameter grant_type == "authorization_code"
1636 if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
1637 {
1638 handle->emsg=GNUNET_strdup("unsupported_grant_type");
1639 handle->response_code = MHD_HTTP_BAD_REQUEST;
1640 GNUNET_SCHEDULER_add_now (&do_error, handle);
1641 return;
1642 }
1643 GNUNET_CRYPTO_hash (code, strlen (code), &cache_key);
1644 if (GNUNET_SYSERR ==
1645 GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once,
1646 &cache_key,
1647 &i,
1648 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) )
1649 {
1650 handle->emsg = GNUNET_strdup("invalid_request");
1651 handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
1652 handle->response_code = MHD_HTTP_BAD_REQUEST;
1653 GNUNET_SCHEDULER_add_now (&do_error, handle);
1654 return;
1655 }
1656
1657 //decode code
1658 if(GNUNET_OK != OIDC_parse_authz_code (&cid,
1659 code,
1660 &ticket,
1661 &nonce))
1662 {
1663 handle->emsg = GNUNET_strdup("invalid_request");
1664 handle->edesc = GNUNET_strdup("invalid code");
1665 handle->response_code = MHD_HTTP_BAD_REQUEST;
1666 GNUNET_SCHEDULER_add_now (&do_error, handle);
1667 return;
1668 }
1669
1670 //create jwt
1671 if (GNUNET_OK !=
1672 GNUNET_CONFIGURATION_get_value_time(cfg,
1673 "reclaim-rest-plugin",
1674 "expiration_time",
1675 &expiration_time))
1676 {
1677 handle->emsg = GNUNET_strdup("server_error");
1678 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1679 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1680 GNUNET_SCHEDULER_add_now (&do_error, handle);
1681 GNUNET_free(ticket);
1682 return;
1683 }
1684
1685
1686 //TODO OPTIONAL acr,amr,azp
1687 if (GNUNET_NO == ego_exists (handle,
1688 &ticket->audience))
1689 {
1690 handle->emsg = GNUNET_strdup("invalid_request");
1691 handle->edesc = GNUNET_strdup("invalid code...");
1692 handle->response_code = MHD_HTTP_BAD_REQUEST;
1693 GNUNET_SCHEDULER_add_now (&do_error, handle);
1694 GNUNET_free(ticket);
1695 }
1696 if ( GNUNET_OK
1697 != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
1698 "jwt_secret", &jwt_secret) )
1699 {
1700 handle->emsg = GNUNET_strdup("invalid_request");
1701 handle->edesc = GNUNET_strdup("No signing secret configured!");
1702 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1703 GNUNET_SCHEDULER_add_now (&do_error, handle);
1704 GNUNET_free(ticket);
1705 return;
1706 }
1707 //TODO We should collect the attributes here. cl always empty
1708 cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1709 id_token = OIDC_id_token_new (&ticket->audience,
1710 &ticket->identity,
1711 cl,
1712 &expiration_time,
1713 (NULL != nonce) ? nonce : NULL,
1714 jwt_secret);
1715 access_token = OIDC_access_token_new ();
1716 OIDC_build_token_response (access_token,
1717 id_token,
1718 &expiration_time,
1719 &json_response);
1720
1721 store_ticket_reference (handle,
1722 access_token,
1723 ticket,
1724 &cid);
1725 resp = GNUNET_REST_create_response (json_response);
1726 MHD_add_response_header (resp, "Cache-Control", "no-store");
1727 MHD_add_response_header (resp, "Pragma", "no-cache");
1728 MHD_add_response_header (resp, "Content-Type", "application/json");
1729 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1730 GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl);
1731 GNUNET_free(access_token);
1732 GNUNET_free(json_response);
1733 GNUNET_free(ticket);
1734 GNUNET_free(id_token);
1735 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
1736}
1737
1738/**
1739 * Collects claims and stores them in handle
1740 */
1741static void
1742consume_ticket (void *cls,
1743 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1744 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1745{
1746 struct RequestHandle *handle = cls;
1747 char *tmp_value;
1748 json_t *value;
1749
1750 if (NULL == identity)
1751 {
1752 GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
1753 return;
1754 }
1755
1756 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1757 attr->data,
1758 attr->data_size);
1759
1760 value = json_string (tmp_value);
1761
1762
1763 json_object_set_new (handle->oidc->response,
1764 attr->name,
1765 value);
1766 GNUNET_free (tmp_value);
1767}
1768
1769/**
1770 * Responds to userinfo GET and url-encoded POST request
1771 *
1772 * @param con_handle the connection handle
1773 * @param url the url
1774 * @param cls the RequestHandle
1775 */
1776static void
1777userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1778 const char* url, void *cls)
1779{
1780 //TODO expiration time
1781 struct RequestHandle *handle = cls;
1782 char delimiter[] = " ";
1783 char delimiter_db[] = ";";
1784 struct GNUNET_HashCode cache_key;
1785 char *authorization, *authorization_type, *authorization_access_token;
1786 char *client_ticket, *client, *ticket_str;
1787 struct GNUNET_RECLAIM_Ticket *ticket;
1788
1789 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1790 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1791 &cache_key);
1792 if ( GNUNET_NO
1793 == GNUNET_CONTAINER_multihashmap_contains (
1794 handle->rest_handle->header_param_map, &cache_key) )
1795 {
1796 handle->emsg = GNUNET_strdup("invalid_token");
1797 handle->edesc = GNUNET_strdup("No Access Token");
1798 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1799 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1800 return;
1801 }
1802 authorization = GNUNET_CONTAINER_multihashmap_get (
1803 handle->rest_handle->header_param_map, &cache_key);
1804
1805 //split header in "Bearer" and access_token
1806 authorization = GNUNET_strdup(authorization);
1807 authorization_type = strtok (authorization, delimiter);
1808 if ( 0 != strcmp ("Bearer", authorization_type) )
1809 {
1810 handle->emsg = GNUNET_strdup("invalid_token");
1811 handle->edesc = GNUNET_strdup("No Access Token");
1812 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1813 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1814 GNUNET_free(authorization);
1815 return;
1816 }
1817 authorization_access_token = strtok (NULL, delimiter);
1818 if ( NULL == authorization_access_token )
1819 {
1820 handle->emsg = GNUNET_strdup("invalid_token");
1821 handle->edesc = GNUNET_strdup("No Access Token");
1822 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1823 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1824 GNUNET_free(authorization);
1825 return;
1826 }
1827
1828 GNUNET_CRYPTO_hash (authorization_access_token,
1829 strlen (authorization_access_token),
1830 &cache_key);
1831 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
1832 &cache_key) )
1833 {
1834 handle->emsg = GNUNET_strdup("invalid_token");
1835 handle->edesc = GNUNET_strdup("The Access Token expired");
1836 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1837 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1838 GNUNET_free(authorization);
1839 return;
1840 }
1841
1842 client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
1843 &cache_key);
1844 client_ticket = GNUNET_strdup(client_ticket);
1845 client = strtok(client_ticket,delimiter_db);
1846 if (NULL == client)
1847 {
1848 handle->emsg = GNUNET_strdup("invalid_token");
1849 handle->edesc = GNUNET_strdup("The Access Token expired");
1850 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1851 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1852 GNUNET_free(authorization);
1853 GNUNET_free(client_ticket);
1854 return;
1855 }
1856 handle->ego_entry = handle->ego_head;
1857 for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1858 {
1859 if (0 == strcmp(handle->ego_entry->keystring,client))
1860 {
1861 break;
1862 }
1863 }
1864 if (NULL == handle->ego_entry)
1865 {
1866 handle->emsg = GNUNET_strdup("invalid_token");
1867 handle->edesc = GNUNET_strdup("The Access Token expired");
1868 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1869 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1870 GNUNET_free(authorization);
1871 GNUNET_free(client_ticket);
1872 return;
1873 }
1874 ticket_str = strtok(NULL, delimiter_db);
1875 if (NULL == ticket_str)
1876 {
1877 handle->emsg = GNUNET_strdup("invalid_token");
1878 handle->edesc = GNUNET_strdup("The Access Token expired");
1879 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1880 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1881 GNUNET_free(authorization);
1882 GNUNET_free(client_ticket);
1883 return;
1884 }
1885 ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
1886 if ( GNUNET_OK
1887 != GNUNET_STRINGS_string_to_data (ticket_str,
1888 strlen (ticket_str),
1889 ticket,
1890 sizeof(struct GNUNET_RECLAIM_Ticket)))
1891 {
1892 handle->emsg = GNUNET_strdup("invalid_token");
1893 handle->edesc = GNUNET_strdup("The Access Token expired");
1894 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1895 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1896 GNUNET_free(ticket);
1897 GNUNET_free(authorization);
1898 GNUNET_free(client_ticket);
1899 return;
1900 }
1901
1902 handle->idp = GNUNET_RECLAIM_connect (cfg);
1903 handle->oidc->response = json_object();
1904 json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
1905 handle->idp_op = GNUNET_RECLAIM_ticket_consume (
1906 handle->idp,
1907 GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
1908 ticket,
1909 consume_ticket,
1910 handle);
1911 GNUNET_free(ticket);
1912 GNUNET_free(authorization);
1913 GNUNET_free(client_ticket);
1914
1915}
1916
1917
1918/**
1919 * Handle rest request
1920 *
1921 * @param handle the request handle
1922 */
1923static void
1924init_cont (struct RequestHandle *handle)
1925{
1926 struct GNUNET_REST_RequestHandlerError err;
1927 static const struct GNUNET_REST_RequestHandler handlers[] = {
1928 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
1929 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
1930 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
1931 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
1932 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1933 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1934 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC,
1935 &options_cont},
1936 GNUNET_REST_HANDLER_END
1937 };
1938
1939 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1940 handlers,
1941 &err,
1942 handle))
1943 {
1944 handle->response_code = err.error_code;
1945 GNUNET_SCHEDULER_add_now (&do_error, handle);
1946 }
1947}
1948
1949/**
1950 * If listing is enabled, prints information about the egos.
1951 *
1952 * This function is initially called for all egos and then again
1953 * whenever a ego's identifier changes or if it is deleted. At the
1954 * end of the initial pass over all egos, the function is once called
1955 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1956 * be invoked in the future or that there was an error.
1957 *
1958 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1959 * this function is only called ONCE, and 'NULL' being passed in
1960 * 'ego' does indicate an error (i.e. name is taken or no default
1961 * value is known). If 'ego' is non-NULL and if '*ctx'
1962 * is set in those callbacks, the value WILL be passed to a subsequent
1963 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1964 * that one was not NULL).
1965 *
1966 * When an identity is renamed, this function is called with the
1967 * (known) ego but the NEW identifier.
1968 *
1969 * When an identity is deleted, this function is called with the
1970 * (known) ego and "NULL" for the 'identifier'. In this case,
1971 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1972 * cleaned up).
1973 *
1974 * @param cls closure
1975 * @param ego ego handle
1976 * @param ctx context for application to store data for this ego
1977 * (during the lifetime of this process, initially NULL)
1978 * @param identifier identifier assigned by the user for this ego,
1979 * NULL if the user just deleted the ego and it
1980 * must thus no longer be used
1981 */
1982static void
1983list_ego (void *cls,
1984 struct GNUNET_IDENTITY_Ego *ego,
1985 void **ctx,
1986 const char *identifier)
1987{
1988 struct RequestHandle *handle = cls;
1989 struct EgoEntry *ego_entry;
1990 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1991
1992 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1993 {
1994 handle->state = ID_REST_STATE_POST_INIT;
1995 init_cont (handle);
1996 return;
1997 }
1998 if (ID_REST_STATE_INIT == handle->state) {
1999 ego_entry = GNUNET_new (struct EgoEntry);
2000 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2001 ego_entry->keystring =
2002 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2003 ego_entry->ego = ego;
2004 ego_entry->identifier = GNUNET_strdup (identifier);
2005 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2006 return;
2007 }
2008 /* Ego renamed or added */
2009 if (identifier != NULL) {
2010 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2011 if (ego_entry->ego == ego) {
2012 /* Rename */
2013 GNUNET_free (ego_entry->identifier);
2014 ego_entry->identifier = GNUNET_strdup (identifier);
2015 break;
2016 }
2017 }
2018 if (NULL == ego_entry) {
2019 /* Add */
2020 ego_entry = GNUNET_new (struct EgoEntry);
2021 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2022 ego_entry->keystring =
2023 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2024 ego_entry->ego = ego;
2025 ego_entry->identifier = GNUNET_strdup (identifier);
2026 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2027 }
2028 } else {
2029 /* Delete */
2030 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2031 if (ego_entry->ego == ego)
2032 break;
2033 }
2034 if (NULL != ego_entry)
2035 GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry);
2036 }
2037
2038}
2039
2040static void
2041rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2042 GNUNET_REST_ResultProcessor proc,
2043 void *proc_cls)
2044{
2045 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2046 handle->oidc = GNUNET_new (struct OIDC_Variables);
2047 if ( NULL == OIDC_identity_login_time )
2048 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2049 if ( NULL == OIDC_identity_grants )
2050 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2051 if ( NULL == OIDC_ticket_once )
2052 OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2053 if ( NULL == OIDC_interpret_access_token )
2054 OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2055 handle->response_code = 0;
2056 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2057 handle->proc_cls = proc_cls;
2058 handle->proc = proc;
2059 handle->state = ID_REST_STATE_INIT;
2060 handle->rest_handle = rest_handle;
2061
2062 handle->url = GNUNET_strdup (rest_handle->url);
2063 if (handle->url[strlen (handle->url)-1] == '/')
2064 handle->url[strlen (handle->url)-1] = '\0';
2065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2066 "Connecting...\n");
2067 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2068 &list_ego,
2069 handle);
2070 handle->gns_handle = GNUNET_GNS_connect (cfg);
2071 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2072 handle->timeout_task =
2073 GNUNET_SCHEDULER_add_delayed (handle->timeout,
2074 &do_timeout,
2075 handle);
2076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2077 "Connected\n");
2078}
2079
2080/**
2081 * Entry point for the plugin.
2082 *
2083 * @param cls Config info
2084 * @return NULL on error, otherwise the plugin context
2085 */
2086void *
2087libgnunet_plugin_rest_openid_connect_init (void *cls)
2088{
2089 static struct Plugin plugin;
2090 struct GNUNET_REST_Plugin *api;
2091
2092 cfg = cls;
2093 if (NULL != plugin.cfg)
2094 return NULL; /* can only initialize once! */
2095 memset (&plugin, 0, sizeof (struct Plugin));
2096 plugin.cfg = cfg;
2097 api = GNUNET_new (struct GNUNET_REST_Plugin);
2098 api->cls = &plugin;
2099 api->name = GNUNET_REST_API_NS_OIDC;
2100 api->process_request = &rest_identity_process_request;
2101 GNUNET_asprintf (&allow_methods,
2102 "%s, %s, %s, %s, %s",
2103 MHD_HTTP_METHOD_GET,
2104 MHD_HTTP_METHOD_POST,
2105 MHD_HTTP_METHOD_PUT,
2106 MHD_HTTP_METHOD_DELETE,
2107 MHD_HTTP_METHOD_OPTIONS);
2108
2109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2110 _("Identity Provider REST API initialized\n"));
2111 return api;
2112}
2113
2114
2115/**
2116 * Exit point from the plugin.
2117 *
2118 * @param cls the plugin context (as returned by "init")
2119 * @return always NULL
2120 */
2121void *
2122libgnunet_plugin_rest_openid_connect_done (void *cls)
2123{
2124 struct GNUNET_REST_Plugin *api = cls;
2125 struct Plugin *plugin = api->cls;
2126 plugin->cfg = NULL;
2127
2128 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2129 void *value = NULL;
2130 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2131 OIDC_identity_login_time);
2132 while (GNUNET_YES ==
2133 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2134 {
2135 if (NULL != value)
2136 GNUNET_free(value);
2137 }
2138 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2139 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2140 while (GNUNET_YES ==
2141 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2142 {
2143 if (NULL != value)
2144 GNUNET_free(value);
2145 }
2146 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2147 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2148 while (GNUNET_YES ==
2149 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2150 {
2151 if (NULL != value)
2152 GNUNET_free(value);
2153 }
2154 GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2155 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2156 while (GNUNET_YES ==
2157 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2158 {
2159 if (NULL != value)
2160 GNUNET_free(value);
2161 }
2162 GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2163 GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2164 GNUNET_free_non_null (allow_methods);
2165 GNUNET_free (api);
2166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2167 "Identity Provider REST plugin is finished\n");
2168 return NULL;
2169}
2170
2171/* end of plugin_rest_identity_provider.c */
diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c
new file mode 100644
index 000000000..38ffc4ddb
--- /dev/null
+++ b/src/reclaim/plugin_rest_reclaim.c
@@ -0,0 +1,1253 @@
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/**
19 * @author Martin Schanzenbach
20 * @author Philippe Buschmann
21 * @file reclaim/plugin_rest_reclaim.c
22 * @brief GNUnet reclaim REST plugin
23 *
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_rest_lib.h"
33#include "gnunet_jsonapi_lib.h"
34#include "gnunet_jsonapi_util.h"
35#include "microhttpd.h"
36#include <jansson.h>
37#include <inttypes.h>
38#include "gnunet_signatures.h"
39#include "gnunet_reclaim_attribute_lib.h"
40#include "gnunet_reclaim_service.h"
41
42/**
43 * REST root namespace
44 */
45#define GNUNET_REST_API_NS_RECLAIM "/reclaim"
46
47/**
48 * Attribute namespace
49 */
50#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
51
52/**
53 * Ticket namespace
54 */
55#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
56
57/**
58 * Revoke namespace
59 */
60#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
61
62/**
63 * Revoke namespace
64 */
65#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
66
67/**
68 * Attribute key
69 */
70#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute"
71
72/**
73 * Ticket key
74 */
75#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
76
77
78/**
79 * Value key
80 */
81#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value"
82
83/**
84 * State while collecting all egos
85 */
86#define ID_REST_STATE_INIT 0
87
88/**
89 * Done collecting egos
90 */
91#define ID_REST_STATE_POST_INIT 1
92
93/**
94 * The configuration handle
95 */
96const struct GNUNET_CONFIGURATION_Handle *cfg;
97
98/**
99 * HTTP methods allows for this plugin
100 */
101static char* allow_methods;
102
103/**
104 * @brief struct returned by the initialization function of the plugin
105 */
106struct Plugin
107{
108 const struct GNUNET_CONFIGURATION_Handle *cfg;
109};
110
111/**
112 * The ego list
113 */
114struct EgoEntry
115{
116 /**
117 * DLL
118 */
119 struct EgoEntry *next;
120
121 /**
122 * DLL
123 */
124 struct EgoEntry *prev;
125
126 /**
127 * Ego Identifier
128 */
129 char *identifier;
130
131 /**
132 * Public key string
133 */
134 char *keystring;
135
136 /**
137 * The Ego
138 */
139 struct GNUNET_IDENTITY_Ego *ego;
140};
141
142
143struct RequestHandle
144{
145 /**
146 * Ego list
147 */
148 struct EgoEntry *ego_head;
149
150 /**
151 * Ego list
152 */
153 struct EgoEntry *ego_tail;
154
155 /**
156 * Selected ego
157 */
158 struct EgoEntry *ego_entry;
159
160 /**
161 * Pointer to ego private key
162 */
163 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
164
165 /**
166 * The processing state
167 */
168 int state;
169
170 /**
171 * Handle to Identity service.
172 */
173 struct GNUNET_IDENTITY_Handle *identity_handle;
174
175 /**
176 * Rest connection
177 */
178 struct GNUNET_REST_RequestHandle *rest_handle;
179
180 /**
181 * Handle to NAMESTORE
182 */
183 struct GNUNET_NAMESTORE_Handle *namestore_handle;
184
185 /**
186 * Iterator for NAMESTORE
187 */
188 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
189
190 /**
191 * Attribute claim list
192 */
193 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
194
195 /**
196 * IDENTITY Operation
197 */
198 struct GNUNET_IDENTITY_Operation *op;
199
200 /**
201 * Identity Provider
202 */
203 struct GNUNET_RECLAIM_Handle *idp;
204
205 /**
206 * Idp Operation
207 */
208 struct GNUNET_RECLAIM_Operation *idp_op;
209
210 /**
211 * Attribute iterator
212 */
213 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
214
215 /**
216 * Ticket iterator
217 */
218 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
219
220 /**
221 * A ticket
222 */
223 struct GNUNET_RECLAIM_Ticket ticket;
224
225 /**
226 * Desired timeout for the lookup (default is no timeout).
227 */
228 struct GNUNET_TIME_Relative timeout;
229
230 /**
231 * ID of a task associated with the resolution process.
232 */
233 struct GNUNET_SCHEDULER_Task *timeout_task;
234
235 /**
236 * The plugin result processor
237 */
238 GNUNET_REST_ResultProcessor proc;
239
240 /**
241 * The closure of the result processor
242 */
243 void *proc_cls;
244
245 /**
246 * The url
247 */
248 char *url;
249
250 /**
251 * Error response message
252 */
253 char *emsg;
254
255 /**
256 * Reponse code
257 */
258 int response_code;
259
260 /**
261 * Response object
262 */
263 struct GNUNET_JSONAPI_Document *resp_object;
264
265};
266
267/**
268 * Cleanup lookup handle
269 * @param handle Handle to clean up
270 */
271static void
272cleanup_handle (struct RequestHandle *handle)
273{
274 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
275 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
276 struct EgoEntry *ego_entry;
277 struct EgoEntry *ego_tmp;
278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
279 "Cleaning up\n");
280 if (NULL != handle->resp_object)
281 GNUNET_JSONAPI_document_delete (handle->resp_object);
282 if (NULL != handle->timeout_task)
283 GNUNET_SCHEDULER_cancel (handle->timeout_task);
284 if (NULL != handle->identity_handle)
285 GNUNET_IDENTITY_disconnect (handle->identity_handle);
286 if (NULL != handle->attr_it)
287 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
288 if (NULL != handle->ticket_it)
289 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
290 if (NULL != handle->idp)
291 GNUNET_RECLAIM_disconnect (handle->idp);
292 if (NULL != handle->url)
293 GNUNET_free (handle->url);
294 if (NULL != handle->emsg)
295 GNUNET_free (handle->emsg);
296 if (NULL != handle->namestore_handle)
297 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
298 if ( NULL != handle->attr_list )
299 {
300 for (claim_entry = handle->attr_list->list_head;
301 NULL != claim_entry;)
302 {
303 claim_tmp = claim_entry;
304 claim_entry = claim_entry->next;
305 GNUNET_free(claim_tmp->claim);
306 GNUNET_free(claim_tmp);
307 }
308 GNUNET_free (handle->attr_list);
309 }
310 for (ego_entry = handle->ego_head;
311 NULL != ego_entry;)
312 {
313 ego_tmp = ego_entry;
314 ego_entry = ego_entry->next;
315 GNUNET_free (ego_tmp->identifier);
316 GNUNET_free (ego_tmp->keystring);
317 GNUNET_free (ego_tmp);
318 }
319 if (NULL != handle->attr_it)
320 {
321 GNUNET_free(handle->attr_it);
322 }
323 GNUNET_free (handle);
324}
325
326static void
327cleanup_handle_delayed (void *cls)
328{
329 cleanup_handle (cls);
330}
331
332
333/**
334 * Task run on error, sends error message. Cleans up everything.
335 *
336 * @param cls the `struct RequestHandle`
337 */
338static void
339do_error (void *cls)
340{
341 struct RequestHandle *handle = cls;
342 struct MHD_Response *resp;
343 char *json_error;
344
345 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
346 handle->emsg);
347 if ( 0 == handle->response_code )
348 {
349 handle->response_code = MHD_HTTP_BAD_REQUEST;
350 }
351 resp = GNUNET_REST_create_response (json_error);
352 MHD_add_response_header (resp, "Content-Type", "application/json");
353 handle->proc (handle->proc_cls, resp, handle->response_code);
354 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
355 GNUNET_free (json_error);
356}
357
358
359/**
360 * Task run on timeout, sends error message. Cleans up everything.
361 *
362 * @param cls the `struct RequestHandle`
363 */
364static void
365do_timeout (void *cls)
366{
367 struct RequestHandle *handle = cls;
368
369 handle->timeout_task = NULL;
370 do_error (handle);
371}
372
373
374static void
375collect_error_cb (void *cls)
376{
377 struct RequestHandle *handle = cls;
378
379 do_error (handle);
380}
381
382static void
383finished_cont (void *cls,
384 int32_t success,
385 const char *emsg)
386{
387 struct RequestHandle *handle = cls;
388 struct MHD_Response *resp;
389
390 resp = GNUNET_REST_create_response (emsg);
391 if (GNUNET_OK != success)
392 {
393 GNUNET_SCHEDULER_add_now (&do_error, handle);
394 return;
395 }
396 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
397 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
398}
399
400
401/**
402 * Return attributes for identity
403 *
404 * @param cls the request handle
405 */
406static void
407return_response (void *cls)
408{
409 char* result_str;
410 struct RequestHandle *handle = cls;
411 struct MHD_Response *resp;
412
413 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
415 resp = GNUNET_REST_create_response (result_str);
416 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
417 GNUNET_free (result_str);
418 cleanup_handle (handle);
419}
420
421static void
422collect_finished_cb (void *cls)
423{
424 struct RequestHandle *handle = cls;
425 //Done
426 handle->attr_it = NULL;
427 handle->ticket_it = NULL;
428 GNUNET_SCHEDULER_add_now (&return_response, handle);
429}
430
431
432/**
433 * Collect all attributes for an ego
434 *
435 */
436static void
437ticket_collect (void *cls,
438 const struct GNUNET_RECLAIM_Ticket *ticket)
439{
440 struct GNUNET_JSONAPI_Resource *json_resource;
441 struct RequestHandle *handle = cls;
442 json_t *value;
443 char* tmp;
444
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
446 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
447 sizeof (uint64_t));
448 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
449 tmp);
450 GNUNET_free (tmp);
451 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
452
453 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
454 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
455 value = json_string (tmp);
456 GNUNET_JSONAPI_resource_add_attr (json_resource,
457 "issuer",
458 value);
459 GNUNET_free (tmp);
460 json_decref (value);
461 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
462 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
463 value = json_string (tmp);
464 GNUNET_JSONAPI_resource_add_attr (json_resource,
465 "audience",
466 value);
467 GNUNET_free (tmp);
468 json_decref (value);
469 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
470 sizeof (uint64_t));
471 value = json_string (tmp);
472 GNUNET_JSONAPI_resource_add_attr (json_resource,
473 "rnd",
474 value);
475 GNUNET_free (tmp);
476 json_decref (value);
477 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
478}
479
480
481
482/**
483 * List tickets for identity request
484 *
485 * @param con_handle the connection handle
486 * @param url the url
487 * @param cls the RequestHandle
488 */
489static void
490list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
491 const char* url,
492 void *cls)
493{
494 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
495 struct RequestHandle *handle = cls;
496 struct EgoEntry *ego_entry;
497 char *identity;
498
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
500 handle->url);
501 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
502 strlen (handle->url))
503 {
504 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
505 GNUNET_SCHEDULER_add_now (&do_error, handle);
506 return;
507 }
508 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
509
510 for (ego_entry = handle->ego_head;
511 NULL != ego_entry;
512 ego_entry = ego_entry->next)
513 if (0 == strcmp (identity, ego_entry->identifier))
514 break;
515 handle->resp_object = GNUNET_JSONAPI_document_new ();
516
517 if (NULL == ego_entry)
518 {
519 //Done
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
521 identity);
522 GNUNET_SCHEDULER_add_now (&return_response, handle);
523 return;
524 }
525 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
526 handle->idp = GNUNET_RECLAIM_connect (cfg);
527 handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
528 priv_key,
529 &collect_error_cb,
530 handle,
531 &ticket_collect,
532 handle,
533 &collect_finished_cb,
534 handle);
535}
536
537
538static void
539add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
540 const char* url,
541 void *cls)
542{
543 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
544 const char* identity;
545 const char* name_str;
546 const char* value_str;
547 const char* exp_str;
548
549 struct RequestHandle *handle = cls;
550 struct EgoEntry *ego_entry;
551 struct MHD_Response *resp;
552 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute;
553 struct GNUNET_JSONAPI_Document *json_obj;
554 struct GNUNET_JSONAPI_Resource *json_res;
555 struct GNUNET_TIME_Relative exp;
556 char term_data[handle->rest_handle->data_size+1];
557 json_t *value_json;
558 json_t *data_json;
559 json_t *exp_json;
560 json_error_t err;
561 struct GNUNET_JSON_Specification docspec[] = {
562 GNUNET_JSON_spec_jsonapi_document (&json_obj),
563 GNUNET_JSON_spec_end()
564 };
565
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
567 handle->url);
568 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
569 strlen (handle->url))
570 {
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
573 return;
574 }
575 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
576
577 for (ego_entry = handle->ego_head;
578 NULL != ego_entry;
579 ego_entry = ego_entry->next)
580 if (0 == strcmp (identity, ego_entry->identifier))
581 break;
582
583 if (NULL == ego_entry)
584 {
585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 "Identity unknown (%s)\n", identity);
587 GNUNET_JSONAPI_document_delete (json_obj);
588 return;
589 }
590 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
591
592 if (0 >= handle->rest_handle->data_size)
593 {
594 GNUNET_SCHEDULER_add_now (&do_error, handle);
595 return;
596 }
597
598 term_data[handle->rest_handle->data_size] = '\0';
599 GNUNET_memcpy (term_data,
600 handle->rest_handle->data,
601 handle->rest_handle->data_size);
602 data_json = json_loads (term_data,
603 JSON_DECODE_ANY,
604 &err);
605 GNUNET_assert (GNUNET_OK ==
606 GNUNET_JSON_parse (data_json, docspec,
607 NULL, NULL));
608 json_decref (data_json);
609 if (NULL == json_obj)
610 {
611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
612 "Unable to parse JSONAPI Object from %s\n",
613 term_data);
614 GNUNET_SCHEDULER_add_now (&do_error, handle);
615 return;
616 }
617 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
618 {
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
620 "Cannot create more than 1 resource! (Got %d)\n",
621 GNUNET_JSONAPI_document_resource_count (json_obj));
622 GNUNET_JSONAPI_document_delete (json_obj);
623 GNUNET_SCHEDULER_add_now (&do_error, handle);
624 return;
625 }
626 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
627 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
628 GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE))
629 {
630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
631 "Unsupported JSON data type\n");
632 GNUNET_JSONAPI_document_delete (json_obj);
633 resp = GNUNET_REST_create_response (NULL);
634 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
635 cleanup_handle (handle);
636 return;
637 }
638 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
639 exp_json = GNUNET_JSONAPI_resource_read_attr (json_res,
640 "exp");
641 exp_str = json_string_value (exp_json);
642 if (NULL == exp_str) {
643 exp = GNUNET_TIME_UNIT_HOURS;
644 } else {
645 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str,
646 &exp)) {
647 exp = GNUNET_TIME_UNIT_HOURS;
648 }
649 }
650
651 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
652 "value");
653 value_str = json_string_value (value_json);
654 attribute = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str,
655 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
656 value_str,
657 strlen (value_str) + 1);
658 handle->idp = GNUNET_RECLAIM_connect (cfg);
659 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
660 identity_priv,
661 attribute,
662 &exp,
663 &finished_cont,
664 handle);
665 GNUNET_free (attribute);
666 GNUNET_JSONAPI_document_delete (json_obj);
667}
668
669
670
671/**
672 * Collect all attributes for an ego
673 *
674 */
675static void
676attr_collect (void *cls,
677 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
678 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
679{
680 struct GNUNET_JSONAPI_Resource *json_resource;
681 struct RequestHandle *handle = cls;
682 json_t *value;
683 char* tmp_value;
684
685 if ((NULL == attr->name) || (NULL == attr->data))
686 {
687 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
688 return;
689 }
690
691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
692 attr->name);
693 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE,
694 attr->name);
695 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
696
697 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
698 attr->data,
699 attr->data_size);
700
701 value = json_string (tmp_value);
702
703 GNUNET_JSONAPI_resource_add_attr (json_resource,
704 "value",
705 value);
706 json_decref (value);
707 GNUNET_free(tmp_value);
708 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
709}
710
711
712
713/**
714 * List attributes for identity request
715 *
716 * @param con_handle the connection handle
717 * @param url the url
718 * @param cls the RequestHandle
719 */
720static void
721list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
722 const char* url,
723 void *cls)
724{
725 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
726 struct RequestHandle *handle = cls;
727 struct EgoEntry *ego_entry;
728 char *identity;
729
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
731 handle->url);
732 if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >=
733 strlen (handle->url))
734 {
735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
736 GNUNET_SCHEDULER_add_now (&do_error, handle);
737 return;
738 }
739 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
740
741 for (ego_entry = handle->ego_head;
742 NULL != ego_entry;
743 ego_entry = ego_entry->next)
744 if (0 == strcmp (identity, ego_entry->identifier))
745 break;
746 handle->resp_object = GNUNET_JSONAPI_document_new ();
747
748
749 if (NULL == ego_entry)
750 {
751 //Done
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
753 identity);
754 GNUNET_SCHEDULER_add_now (&return_response, handle);
755 return;
756 }
757 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
758 handle->idp = GNUNET_RECLAIM_connect (cfg);
759 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
760 priv_key,
761 &collect_error_cb,
762 handle,
763 &attr_collect,
764 handle,
765 &collect_finished_cb,
766 handle);
767}
768
769
770static void
771revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
772 const char* url,
773 void *cls)
774{
775 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
776 const char* identity_str;
777 const char* audience_str;
778 const char* rnd_str;
779
780 struct RequestHandle *handle = cls;
781 struct EgoEntry *ego_entry;
782 struct MHD_Response *resp;
783 struct GNUNET_RECLAIM_Ticket ticket;
784 struct GNUNET_JSONAPI_Document *json_obj;
785 struct GNUNET_JSONAPI_Resource *json_res;
786 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
787 char term_data[handle->rest_handle->data_size+1];
788 json_t *rnd_json;
789 json_t *identity_json;
790 json_t *audience_json;
791 json_t *data_json;
792 json_error_t err;
793 struct GNUNET_JSON_Specification docspec[] = {
794 GNUNET_JSON_spec_jsonapi_document (&json_obj),
795 GNUNET_JSON_spec_end()
796 };
797
798 if (0 >= handle->rest_handle->data_size)
799 {
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803
804 term_data[handle->rest_handle->data_size] = '\0';
805 GNUNET_memcpy (term_data,
806 handle->rest_handle->data,
807 handle->rest_handle->data_size);
808 data_json = json_loads (term_data,
809 JSON_DECODE_ANY,
810 &err);
811 GNUNET_assert (GNUNET_OK ==
812 GNUNET_JSON_parse (data_json, docspec,
813 NULL, NULL));
814 json_decref (data_json);
815 if (NULL == json_obj)
816 {
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
818 "Unable to parse JSONAPI Object from %s\n",
819 term_data);
820 GNUNET_SCHEDULER_add_now (&do_error, handle);
821 return;
822 }
823 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
824 {
825 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826 "Cannot create more than 1 resource! (Got %d)\n",
827 GNUNET_JSONAPI_document_resource_count (json_obj));
828 GNUNET_JSONAPI_document_delete (json_obj);
829 GNUNET_SCHEDULER_add_now (&do_error, handle);
830 return;
831 }
832 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
833 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
834 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
835 {
836 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
837 "Unsupported JSON data type\n");
838 GNUNET_JSONAPI_document_delete (json_obj);
839 resp = GNUNET_REST_create_response (NULL);
840 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
841 cleanup_handle (handle);
842 return;
843 }
844 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
845 "rnd");
846 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
847 "issuer");
848 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
849 "audience");
850 rnd_str = json_string_value (rnd_json);
851 identity_str = json_string_value (identity_json);
852 audience_str = json_string_value (audience_json);
853
854 GNUNET_STRINGS_string_to_data (rnd_str,
855 strlen (rnd_str),
856 &ticket.rnd,
857 sizeof (uint64_t));
858 GNUNET_STRINGS_string_to_data (identity_str,
859 strlen (identity_str),
860 &ticket.identity,
861 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
862 GNUNET_STRINGS_string_to_data (audience_str,
863 strlen (audience_str),
864 &ticket.audience,
865 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
866
867 for (ego_entry = handle->ego_head;
868 NULL != ego_entry;
869 ego_entry = ego_entry->next)
870 {
871 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
872 &tmp_pk);
873 if (0 == memcmp (&ticket.identity,
874 &tmp_pk,
875 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
876 break;
877 }
878 if (NULL == ego_entry)
879 {
880 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881 "Identity unknown (%s)\n", identity_str);
882 GNUNET_JSONAPI_document_delete (json_obj);
883 return;
884 }
885 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
886
887 handle->idp = GNUNET_RECLAIM_connect (cfg);
888 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
889 identity_priv,
890 &ticket,
891 &finished_cont,
892 handle);
893 GNUNET_JSONAPI_document_delete (json_obj);
894}
895
896static void
897consume_cont (void *cls,
898 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
899 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
900{
901 struct RequestHandle *handle = cls;
902 struct GNUNET_JSONAPI_Resource *json_resource;
903 json_t *value;
904
905 if (NULL == identity)
906 {
907 GNUNET_SCHEDULER_add_now (&return_response, handle);
908 return;
909 }
910
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
912 attr->name);
913 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE,
914 attr->name);
915 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
916
917 value = json_string (attr->data);
918 GNUNET_JSONAPI_resource_add_attr (json_resource,
919 "value",
920 value);
921 json_decref (value);
922}
923
924static void
925consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
926 const char* url,
927 void *cls)
928{
929 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
930 const char* identity_str;
931 const char* audience_str;
932 const char* rnd_str;
933
934 struct RequestHandle *handle = cls;
935 struct EgoEntry *ego_entry;
936 struct MHD_Response *resp;
937 struct GNUNET_RECLAIM_Ticket ticket;
938 struct GNUNET_JSONAPI_Document *json_obj;
939 struct GNUNET_JSONAPI_Resource *json_res;
940 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
941 char term_data[handle->rest_handle->data_size+1];
942 json_t *rnd_json;
943 json_t *identity_json;
944 json_t *audience_json;
945 json_t *data_json;
946 json_error_t err;
947 struct GNUNET_JSON_Specification docspec[] = {
948 GNUNET_JSON_spec_jsonapi_document (&json_obj),
949 GNUNET_JSON_spec_end()
950 };
951
952 if (0 >= handle->rest_handle->data_size)
953 {
954 GNUNET_SCHEDULER_add_now (&do_error, handle);
955 return;
956 }
957
958 term_data[handle->rest_handle->data_size] = '\0';
959 GNUNET_memcpy (term_data,
960 handle->rest_handle->data,
961 handle->rest_handle->data_size);
962 data_json = json_loads (term_data,
963 JSON_DECODE_ANY,
964 &err);
965 GNUNET_assert (GNUNET_OK ==
966 GNUNET_JSON_parse (data_json, docspec,
967 NULL, NULL));
968 json_decref (data_json);
969 if (NULL == json_obj)
970 {
971 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972 "Unable to parse JSONAPI Object from %s\n",
973 term_data);
974 GNUNET_SCHEDULER_add_now (&do_error, handle);
975 return;
976 }
977 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
978 {
979 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
980 "Cannot create more than 1 resource! (Got %d)\n",
981 GNUNET_JSONAPI_document_resource_count (json_obj));
982 GNUNET_JSONAPI_document_delete (json_obj);
983 GNUNET_SCHEDULER_add_now (&do_error, handle);
984 return;
985 }
986 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
987 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
988 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
989 {
990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991 "Unsupported JSON data type\n");
992 GNUNET_JSONAPI_document_delete (json_obj);
993 resp = GNUNET_REST_create_response (NULL);
994 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
995 cleanup_handle (handle);
996 return;
997 }
998 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
999 "rnd");
1000 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1001 "identity");
1002 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1003 "audience");
1004 rnd_str = json_string_value (rnd_json);
1005 identity_str = json_string_value (identity_json);
1006 audience_str = json_string_value (audience_json);
1007
1008 GNUNET_STRINGS_string_to_data (rnd_str,
1009 strlen (rnd_str),
1010 &ticket.rnd,
1011 sizeof (uint64_t));
1012 GNUNET_STRINGS_string_to_data (identity_str,
1013 strlen (identity_str),
1014 &ticket.identity,
1015 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1016 GNUNET_STRINGS_string_to_data (audience_str,
1017 strlen (audience_str),
1018 &ticket.audience,
1019 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1020
1021 for (ego_entry = handle->ego_head;
1022 NULL != ego_entry;
1023 ego_entry = ego_entry->next)
1024 {
1025 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1026 &tmp_pk);
1027 if (0 == memcmp (&ticket.audience,
1028 &tmp_pk,
1029 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1030 break;
1031 }
1032 if (NULL == ego_entry)
1033 {
1034 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1035 "Identity unknown (%s)\n", identity_str);
1036 GNUNET_JSONAPI_document_delete (json_obj);
1037 return;
1038 }
1039 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1040 handle->resp_object = GNUNET_JSONAPI_document_new ();
1041 handle->idp = GNUNET_RECLAIM_connect (cfg);
1042 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1043 identity_priv,
1044 &ticket,
1045 &consume_cont,
1046 handle);
1047 GNUNET_JSONAPI_document_delete (json_obj);
1048}
1049
1050
1051
1052/**
1053 * Respond to OPTIONS request
1054 *
1055 * @param con_handle the connection handle
1056 * @param url the url
1057 * @param cls the RequestHandle
1058 */
1059static void
1060options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1061 const char* url,
1062 void *cls)
1063{
1064 struct MHD_Response *resp;
1065 struct RequestHandle *handle = cls;
1066
1067 //For now, independent of path return all options
1068 resp = GNUNET_REST_create_response (NULL);
1069 MHD_add_response_header (resp,
1070 "Access-Control-Allow-Methods",
1071 allow_methods);
1072 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1073 cleanup_handle (handle);
1074 return;
1075}
1076
1077/**
1078 * Handle rest request
1079 *
1080 * @param handle the request handle
1081 */
1082static void
1083init_cont (struct RequestHandle *handle)
1084{
1085 struct GNUNET_REST_RequestHandlerError err;
1086 static const struct GNUNET_REST_RequestHandler handlers[] = {
1087 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont},
1088 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont},
1089 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1090 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1091 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1092 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM,
1093 &options_cont},
1094 GNUNET_REST_HANDLER_END
1095 };
1096
1097 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1098 handlers,
1099 &err,
1100 handle))
1101 {
1102 handle->response_code = err.error_code;
1103 GNUNET_SCHEDULER_add_now (&do_error, handle);
1104 }
1105}
1106
1107/**
1108 * If listing is enabled, prints information about the egos.
1109 *
1110 * This function is initially called for all egos and then again
1111 * whenever a ego's identifier changes or if it is deleted. At the
1112 * end of the initial pass over all egos, the function is once called
1113 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1114 * be invoked in the future or that there was an error.
1115 *
1116 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1117 * this function is only called ONCE, and 'NULL' being passed in
1118 * 'ego' does indicate an error (i.e. name is taken or no default
1119 * value is known). If 'ego' is non-NULL and if '*ctx'
1120 * is set in those callbacks, the value WILL be passed to a subsequent
1121 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1122 * that one was not NULL).
1123 *
1124 * When an identity is renamed, this function is called with the
1125 * (known) ego but the NEW identifier.
1126 *
1127 * When an identity is deleted, this function is called with the
1128 * (known) ego and "NULL" for the 'identifier'. In this case,
1129 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1130 * cleaned up).
1131 *
1132 * @param cls closure
1133 * @param ego ego handle
1134 * @param ctx context for application to store data for this ego
1135 * (during the lifetime of this process, initially NULL)
1136 * @param identifier identifier assigned by the user for this ego,
1137 * NULL if the user just deleted the ego and it
1138 * must thus no longer be used
1139 */
1140static void
1141list_ego (void *cls,
1142 struct GNUNET_IDENTITY_Ego *ego,
1143 void **ctx,
1144 const char *identifier)
1145{
1146 struct RequestHandle *handle = cls;
1147 struct EgoEntry *ego_entry;
1148 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1149
1150 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1151 {
1152 handle->state = ID_REST_STATE_POST_INIT;
1153 init_cont (handle);
1154 return;
1155 }
1156 if (ID_REST_STATE_INIT == handle->state) {
1157 ego_entry = GNUNET_new (struct EgoEntry);
1158 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1159 ego_entry->keystring =
1160 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1161 ego_entry->ego = ego;
1162 ego_entry->identifier = GNUNET_strdup (identifier);
1163 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1164 }
1165
1166}
1167
1168static void
1169rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1170 GNUNET_REST_ResultProcessor proc,
1171 void *proc_cls)
1172{
1173 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1174 handle->response_code = 0;
1175 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1176 handle->proc_cls = proc_cls;
1177 handle->proc = proc;
1178 handle->state = ID_REST_STATE_INIT;
1179 handle->rest_handle = rest_handle;
1180
1181 handle->url = GNUNET_strdup (rest_handle->url);
1182 if (handle->url[strlen (handle->url)-1] == '/')
1183 handle->url[strlen (handle->url)-1] = '\0';
1184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185 "Connecting...\n");
1186 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1187 &list_ego,
1188 handle);
1189 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1190 handle->timeout_task =
1191 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1192 &do_timeout,
1193 handle);
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195 "Connected\n");
1196}
1197
1198/**
1199 * Entry point for the plugin.
1200 *
1201 * @param cls Config info
1202 * @return NULL on error, otherwise the plugin context
1203 */
1204void *
1205libgnunet_plugin_rest_reclaim_init (void *cls)
1206{
1207 static struct Plugin plugin;
1208 struct GNUNET_REST_Plugin *api;
1209
1210 cfg = cls;
1211 if (NULL != plugin.cfg)
1212 return NULL; /* can only initialize once! */
1213 memset (&plugin, 0, sizeof (struct Plugin));
1214 plugin.cfg = cfg;
1215 api = GNUNET_new (struct GNUNET_REST_Plugin);
1216 api->cls = &plugin;
1217 api->name = GNUNET_REST_API_NS_RECLAIM;
1218 api->process_request = &rest_identity_process_request;
1219 GNUNET_asprintf (&allow_methods,
1220 "%s, %s, %s, %s, %s",
1221 MHD_HTTP_METHOD_GET,
1222 MHD_HTTP_METHOD_POST,
1223 MHD_HTTP_METHOD_PUT,
1224 MHD_HTTP_METHOD_DELETE,
1225 MHD_HTTP_METHOD_OPTIONS);
1226
1227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1228 _("Identity Provider REST API initialized\n"));
1229 return api;
1230}
1231
1232
1233/**
1234 * Exit point from the plugin.
1235 *
1236 * @param cls the plugin context (as returned by "init")
1237 * @return always NULL
1238 */
1239void *
1240libgnunet_plugin_rest_reclaim_done (void *cls)
1241{
1242 struct GNUNET_REST_Plugin *api = cls;
1243 struct Plugin *plugin = api->cls;
1244 plugin->cfg = NULL;
1245
1246 GNUNET_free_non_null (allow_methods);
1247 GNUNET_free (api);
1248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1249 "Identity Provider REST plugin is finished\n");
1250 return NULL;
1251}
1252
1253/* end of plugin_rest_reclaim.c */
diff --git a/src/reclaim/reclaim.conf b/src/reclaim/reclaim.conf
new file mode 100644
index 000000000..cf0a0dc5e
--- /dev/null
+++ b/src/reclaim/reclaim.conf
@@ -0,0 +1,23 @@
1[reclaim]
2START_ON_DEMAND = NO
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
12TOKEN_EXPIRATION_INTERVAL = 30 m
13DATABASE = sqlite
14
15[reclaim-rest-plugin]
16#ADDRESS = https://identity.gnu:8000#/login
17ADDRESS = https://reclaim.ui/#/login
18PSW = secret
19JWT_SECRET = secret
20EXPIRATION_TIME = 1d
21
22[reclaim-sqlite]
23FILENAME = $GNUNET_DATA_HOME/reclaim/sqlite.db
diff --git a/src/reclaim/reclaim.h b/src/reclaim/reclaim.h
new file mode 100644
index 000000000..d2c84686d
--- /dev/null
+++ b/src/reclaim/reclaim.h
@@ -0,0 +1,410 @@
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
19/**
20 * @author Martin Schanzenbach
21 * @file reclaim/reclaim.h
22 *
23 * @brief Common type definitions for the identity provider
24 * service and API.
25 */
26#ifndef RECLAIM_H
27#define RECLAIM_H
28
29#include "gnunet_common.h"
30
31
32GNUNET_NETWORK_STRUCT_BEGIN
33
34/**
35 * Use to store an identity attribute
36 */
37struct AttributeStoreMessage
38{
39 /**
40 * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT
41 */
42 struct GNUNET_MessageHeader header;
43
44 /**
45 * Unique identifier for this request (for key collisions).
46 */
47 uint32_t id GNUNET_PACKED;
48
49 /**
50 * The length of the attribute
51 */
52 uint32_t attr_len GNUNET_PACKED;
53
54 /**
55 * The expiration interval of the attribute
56 */
57 uint64_t exp GNUNET_PACKED;
58
59 /**
60 * Identity
61 */
62 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
63
64 /* followed by the serialized attribute */
65
66};
67
68/**
69 * Attribute store response message
70 */
71struct AttributeStoreResultMessage
72{
73 /**
74 * Message header
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * Unique identifier for this request (for key collisions).
80 */
81 uint32_t id GNUNET_PACKED;
82
83 /**
84 * #GNUNET_SYSERR on failure, #GNUNET_OK on success
85 */
86 int32_t op_result GNUNET_PACKED;
87
88};
89
90/**
91 * Attribute is returned from the idp.
92 */
93struct AttributeResultMessage
94{
95 /**
96 * Message header
97 */
98 struct GNUNET_MessageHeader header;
99
100 /**
101 * Unique identifier for this request (for key collisions).
102 */
103 uint32_t id GNUNET_PACKED;
104
105 /**
106 * Length of serialized attribute data
107 */
108 uint16_t attr_len GNUNET_PACKED;
109
110 /**
111 * always zero (for alignment)
112 */
113 uint16_t reserved GNUNET_PACKED;
114
115 /**
116 * The public key of the identity.
117 */
118 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
119
120 /* followed by:
121 * serialized attribute data
122 */
123};
124
125
126/**
127 * Start a attribute iteration for the given identity
128 */
129struct AttributeIterationStartMessage
130{
131 /**
132 * Message
133 */
134 struct GNUNET_MessageHeader header;
135
136 /**
137 * Unique identifier for this request (for key collisions).
138 */
139 uint32_t id GNUNET_PACKED;
140
141 /**
142 * Identity.
143 */
144 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
145
146};
147
148
149/**
150 * Ask for next result of attribute iteration for the given operation
151 */
152struct AttributeIterationNextMessage
153{
154 /**
155 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT
156 */
157 struct GNUNET_MessageHeader header;
158
159 /**
160 * Unique identifier for this request (for key collisions).
161 */
162 uint32_t id GNUNET_PACKED;
163
164};
165
166
167/**
168 * Stop attribute iteration for the given operation
169 */
170struct AttributeIterationStopMessage
171{
172 /**
173 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP
174 */
175 struct GNUNET_MessageHeader header;
176
177 /**
178 * Unique identifier for this request (for key collisions).
179 */
180 uint32_t id GNUNET_PACKED;
181
182};
183
184/**
185 * Start a ticket iteration for the given identity
186 */
187struct TicketIterationStartMessage
188{
189 /**
190 * Message
191 */
192 struct GNUNET_MessageHeader header;
193
194 /**
195 * Unique identifier for this request (for key collisions).
196 */
197 uint32_t id GNUNET_PACKED;
198
199 /**
200 * Identity.
201 */
202 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
203
204 /**
205 * Identity is audience or issuer
206 */
207 uint32_t is_audience GNUNET_PACKED;
208};
209
210
211/**
212 * Ask for next result of ticket iteration for the given operation
213 */
214struct TicketIterationNextMessage
215{
216 /**
217 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT
218 */
219 struct GNUNET_MessageHeader header;
220
221 /**
222 * Unique identifier for this request (for key collisions).
223 */
224 uint32_t id GNUNET_PACKED;
225
226};
227
228
229/**
230 * Stop ticket iteration for the given operation
231 */
232struct TicketIterationStopMessage
233{
234 /**
235 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP
236 */
237 struct GNUNET_MessageHeader header;
238
239 /**
240 * Unique identifier for this request (for key collisions).
241 */
242 uint32_t id GNUNET_PACKED;
243
244};
245
246
247
248/**
249 * Ticket issue message
250 */
251struct IssueTicketMessage
252{
253 /**
254 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET
255 */
256 struct GNUNET_MessageHeader header;
257
258 /**
259 * Unique identifier for this request (for key collisions).
260 */
261 uint32_t id GNUNET_PACKED;
262
263 /**
264 * Identity.
265 */
266 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
267
268 /**
269 * Requesting party.
270 */
271 struct GNUNET_CRYPTO_EcdsaPublicKey rp;
272
273 /**
274 * length of serialized attribute list
275 */
276 uint32_t attr_len GNUNET_PACKED;
277
278 //Followed by a serialized attribute list
279};
280
281/**
282 * Ticket revoke message
283 */
284struct RevokeTicketMessage
285{
286 /**
287 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET
288 */
289 struct GNUNET_MessageHeader header;
290
291 /**
292 * Unique identifier for this request (for key collisions).
293 */
294 uint32_t id GNUNET_PACKED;
295
296 /**
297 * Identity.
298 */
299 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
300
301 /**
302 * length of serialized attribute list
303 */
304 uint32_t attrs_len GNUNET_PACKED;
305
306 //Followed by a ticket and serialized attribute list
307};
308
309/**
310 * Ticket revoke message
311 */
312struct RevokeTicketResultMessage
313{
314 /**
315 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
316 */
317 struct GNUNET_MessageHeader header;
318
319 /**
320 * Unique identifier for this request (for key collisions).
321 */
322 uint32_t id GNUNET_PACKED;
323
324 /**
325 * Revocation result
326 */
327 uint32_t success GNUNET_PACKED;
328};
329
330
331/**
332 * Ticket result message
333 */
334struct TicketResultMessage
335{
336 /**
337 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
338 */
339 struct GNUNET_MessageHeader header;
340
341 /**
342 * Unique identifier for this request (for key collisions).
343 */
344 uint32_t id GNUNET_PACKED;
345
346};
347
348/**
349 * Ticket consume message
350 */
351struct ConsumeTicketMessage
352{
353 /**
354 * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET
355 */
356 struct GNUNET_MessageHeader header;
357
358 /**
359 * Unique identifier for this request (for key collisions).
360 */
361 uint32_t id GNUNET_PACKED;
362
363 /**
364 * Identity.
365 */
366 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
367
368 //Followed by a serialized ticket
369};
370
371/**
372 * Attribute list is returned from the idp.
373 */
374struct ConsumeTicketResultMessage
375{
376 /**
377 * Message header
378 */
379 struct GNUNET_MessageHeader header;
380
381 /**
382 * Unique identifier for this request (for key collisions).
383 */
384 uint32_t id GNUNET_PACKED;
385
386 /**
387 * Length of serialized attribute data
388 */
389 uint16_t attrs_len GNUNET_PACKED;
390
391 /**
392 * always zero (for alignment)
393 */
394 uint16_t reserved GNUNET_PACKED;
395
396 /**
397 * The public key of the identity.
398 */
399 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
400
401 /* followed by:
402 * serialized attributes data
403 */
404};
405
406
407
408GNUNET_NETWORK_STRUCT_END
409
410#endif
diff --git a/src/reclaim/reclaim_api.c b/src/reclaim/reclaim_api.c
new file mode 100644
index 000000000..3f1584ccd
--- /dev/null
+++ b/src/reclaim/reclaim_api.c
@@ -0,0 +1,1383 @@
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
19/**
20 * @file reclaim/reclaim_api.c
21 * @brief api to interact with the reclaim service
22 * @author Martin Schanzenbach
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_constants.h"
27#include "gnunet_protocols.h"
28#include "gnunet_mq_lib.h"
29#include "gnunet_reclaim_service.h"
30#include "gnunet_reclaim_attribute_lib.h"
31#include "reclaim.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "reclaim-api",__VA_ARGS__)
34
35
36/**
37 * Handle for an operation with the service.
38 */
39struct GNUNET_RECLAIM_Operation
40{
41
42 /**
43 * Main handle.
44 */
45 struct GNUNET_RECLAIM_Handle *h;
46
47 /**
48 * We keep operations in a DLL.
49 */
50 struct GNUNET_RECLAIM_Operation *next;
51
52 /**
53 * We keep operations in a DLL.
54 */
55 struct GNUNET_RECLAIM_Operation *prev;
56
57 /**
58 * Message to send to the service.
59 * Allocated at the end of this struct.
60 */
61 const struct GNUNET_MessageHeader *msg;
62
63 /**
64 * Continuation to invoke after attribute store call
65 */
66 GNUNET_RECLAIM_ContinuationWithStatus as_cb;
67
68 /**
69 * Attribute result callback
70 */
71 GNUNET_RECLAIM_AttributeResult ar_cb;
72
73 /**
74 * Revocation result callback
75 */
76 GNUNET_RECLAIM_ContinuationWithStatus rvk_cb;
77
78 /**
79 * Ticket result callback
80 */
81 GNUNET_RECLAIM_TicketCallback tr_cb;
82
83 /**
84 * Envelope with the message for this queue entry.
85 */
86 struct GNUNET_MQ_Envelope *env;
87
88 /**
89 * request id
90 */
91 uint32_t r_id;
92
93 /**
94 * Closure for @e cont or @e cb.
95 */
96 void *cls;
97
98};
99
100/**
101 * Handle for a ticket iterator operation
102 */
103struct GNUNET_RECLAIM_TicketIterator
104{
105
106 /**
107 * Kept in a DLL.
108 */
109 struct GNUNET_RECLAIM_TicketIterator *next;
110
111 /**
112 * Kept in a DLL.
113 */
114 struct GNUNET_RECLAIM_TicketIterator *prev;
115
116 /**
117 * Main handle to access the idp.
118 */
119 struct GNUNET_RECLAIM_Handle *h;
120
121 /**
122 * Function to call on completion.
123 */
124 GNUNET_SCHEDULER_TaskCallback finish_cb;
125
126 /**
127 * Closure for @e error_cb.
128 */
129 void *finish_cb_cls;
130
131 /**
132 * The continuation to call with the results
133 */
134 GNUNET_RECLAIM_TicketCallback tr_cb;
135
136 /**
137 * Closure for @e tr_cb.
138 */
139 void *cls;
140
141 /**
142 * Function to call on errors.
143 */
144 GNUNET_SCHEDULER_TaskCallback error_cb;
145
146 /**
147 * Closure for @e error_cb.
148 */
149 void *error_cb_cls;
150
151 /**
152 * Envelope of the message to send to the service, if not yet
153 * sent.
154 */
155 struct GNUNET_MQ_Envelope *env;
156
157 /**
158 * The operation id this zone iteration operation has
159 */
160 uint32_t r_id;
161
162};
163
164
165/**
166 * Handle for a attribute iterator operation
167 */
168struct GNUNET_RECLAIM_AttributeIterator
169{
170
171 /**
172 * Kept in a DLL.
173 */
174 struct GNUNET_RECLAIM_AttributeIterator *next;
175
176 /**
177 * Kept in a DLL.
178 */
179 struct GNUNET_RECLAIM_AttributeIterator *prev;
180
181 /**
182 * Main handle to access the idp.
183 */
184 struct GNUNET_RECLAIM_Handle *h;
185
186 /**
187 * Function to call on completion.
188 */
189 GNUNET_SCHEDULER_TaskCallback finish_cb;
190
191 /**
192 * Closure for @e error_cb.
193 */
194 void *finish_cb_cls;
195
196 /**
197 * The continuation to call with the results
198 */
199 GNUNET_RECLAIM_AttributeResult proc;
200
201 /**
202 * Closure for @e proc.
203 */
204 void *proc_cls;
205
206 /**
207 * Function to call on errors.
208 */
209 GNUNET_SCHEDULER_TaskCallback error_cb;
210
211 /**
212 * Closure for @e error_cb.
213 */
214 void *error_cb_cls;
215
216 /**
217 * Envelope of the message to send to the service, if not yet
218 * sent.
219 */
220 struct GNUNET_MQ_Envelope *env;
221
222 /**
223 * Private key of the zone.
224 */
225 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
226
227 /**
228 * The operation id this zone iteration operation has
229 */
230 uint32_t r_id;
231
232};
233
234
235/**
236 * Handle for the service.
237 */
238struct GNUNET_RECLAIM_Handle
239{
240 /**
241 * Configuration to use.
242 */
243 const struct GNUNET_CONFIGURATION_Handle *cfg;
244
245 /**
246 * Socket (if available).
247 */
248 struct GNUNET_CLIENT_Connection *client;
249
250 /**
251 * Closure for 'cb'.
252 */
253 void *cb_cls;
254
255 /**
256 * Head of active operations.
257 */
258 struct GNUNET_RECLAIM_Operation *op_head;
259
260 /**
261 * Tail of active operations.
262 */
263 struct GNUNET_RECLAIM_Operation *op_tail;
264
265 /**
266 * Head of active iterations
267 */
268 struct GNUNET_RECLAIM_AttributeIterator *it_head;
269
270 /**
271 * Tail of active iterations
272 */
273 struct GNUNET_RECLAIM_AttributeIterator *it_tail;
274
275 /**
276 * Head of active iterations
277 */
278 struct GNUNET_RECLAIM_TicketIterator *ticket_it_head;
279
280 /**
281 * Tail of active iterations
282 */
283 struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail;
284
285
286 /**
287 * Currently pending transmission request, or NULL for none.
288 */
289 struct GNUNET_CLIENT_TransmitHandle *th;
290
291 /**
292 * Task doing exponential back-off trying to reconnect.
293 */
294 struct GNUNET_SCHEDULER_Task * reconnect_task;
295
296 /**
297 * Time for next connect retry.
298 */
299 struct GNUNET_TIME_Relative reconnect_backoff;
300
301 /**
302 * Connection to service (if available).
303 */
304 struct GNUNET_MQ_Handle *mq;
305
306 /**
307 * Request Id generator. Incremented by one for each request.
308 */
309 uint32_t r_id_gen;
310
311 /**
312 * Are we polling for incoming messages right now?
313 */
314 int in_receive;
315
316};
317
318/**
319 * Try again to connect to the service.
320 *
321 * @param h handle to the reclaim service.
322 */
323static void
324reconnect (struct GNUNET_RECLAIM_Handle *h);
325
326/**
327 * Reconnect
328 *
329 * @param cls the handle
330 */
331static void
332reconnect_task (void *cls)
333{
334 struct GNUNET_RECLAIM_Handle *handle = cls;
335
336 handle->reconnect_task = NULL;
337 reconnect (handle);
338}
339
340
341/**
342 * Disconnect from service and then reconnect.
343 *
344 * @param handle our service
345 */
346static void
347force_reconnect (struct GNUNET_RECLAIM_Handle *handle)
348{
349 GNUNET_MQ_destroy (handle->mq);
350 handle->mq = NULL;
351 handle->reconnect_backoff
352 = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
353 handle->reconnect_task
354 = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
355 &reconnect_task,
356 handle);
357}
358
359/**
360 * Free @a it.
361 *
362 * @param it entry to free
363 */
364static void
365free_it (struct GNUNET_RECLAIM_AttributeIterator *it)
366{
367 struct GNUNET_RECLAIM_Handle *h = it->h;
368
369 GNUNET_CONTAINER_DLL_remove (h->it_head,
370 h->it_tail,
371 it);
372 if (NULL != it->env)
373 GNUNET_MQ_discard (it->env);
374 GNUNET_free (it);
375}
376
377static void
378free_op (struct GNUNET_RECLAIM_Operation* op)
379{
380 if (NULL == op)
381 return;
382 if (NULL != op->env)
383 GNUNET_MQ_discard (op->env);
384 GNUNET_free(op);
385}
386
387
388/**
389 * Generic error handler, called with the appropriate error code and
390 * the same closure specified at the creation of the message queue.
391 * Not every message queue implementation supports an error handler.
392 *
393 * @param cls closure with the `struct GNUNET_GNS_Handle *`
394 * @param error error code
395 */
396static void
397mq_error_handler (void *cls,
398 enum GNUNET_MQ_Error error)
399{
400 struct GNUNET_RECLAIM_Handle *handle = cls;
401 force_reconnect (handle);
402}
403
404/**
405 * Handle an incoming message of type
406 * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
407 *
408 * @param cls
409 * @param msg the message we received
410 */
411static void
412handle_attribute_store_response (void *cls,
413 const struct AttributeStoreResultMessage *msg)
414{
415 struct GNUNET_RECLAIM_Handle *h = cls;
416 struct GNUNET_RECLAIM_Operation *op;
417 uint32_t r_id = ntohl (msg->id);
418 int res;
419 const char *emsg;
420
421 for (op = h->op_head; NULL != op; op = op->next)
422 if (op->r_id == r_id)
423 break;
424 if (NULL == op)
425 return;
426
427 res = ntohl (msg->op_result);
428 LOG (GNUNET_ERROR_TYPE_DEBUG,
429 "Received ATTRIBUTE_STORE_RESPONSE with result %d\n",
430 res);
431
432 /* TODO: add actual error message to response... */
433 if (GNUNET_SYSERR == res)
434 emsg = _("failed to store record\n");
435 else
436 emsg = NULL;
437 if (NULL != op->as_cb)
438 op->as_cb (op->cls,
439 res,
440 emsg);
441 GNUNET_CONTAINER_DLL_remove (h->op_head,
442 h->op_tail,
443 op);
444 free_op (op);
445
446}
447
448
449/**
450 * Handle an incoming message of type
451 * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
452 *
453 * @param cls
454 * @param msg the message we received
455 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
456 */
457static int
458check_consume_ticket_result (void *cls,
459 const struct ConsumeTicketResultMessage *msg)
460{
461 size_t msg_len;
462 size_t attrs_len;
463
464 msg_len = ntohs (msg->header.size);
465 attrs_len = ntohs (msg->attrs_len);
466 if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len)
467 {
468 GNUNET_break (0);
469 return GNUNET_SYSERR;
470 }
471 return GNUNET_OK;
472}
473
474
475/**
476 * Handle an incoming message of type
477 * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
478 *
479 * @param cls
480 * @param msg the message we received
481 */
482static void
483handle_consume_ticket_result (void *cls,
484 const struct ConsumeTicketResultMessage *msg)
485{
486 struct GNUNET_RECLAIM_Handle *h = cls;
487 struct GNUNET_RECLAIM_Operation *op;
488 size_t attrs_len;
489 uint32_t r_id = ntohl (msg->id);
490
491 attrs_len = ntohs (msg->attrs_len);
492 LOG (GNUNET_ERROR_TYPE_DEBUG,
493 "Processing attribute result.\n");
494
495
496 for (op = h->op_head; NULL != op; op = op->next)
497 if (op->r_id == r_id)
498 break;
499 if (NULL == op)
500 return;
501
502 {
503 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
504 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
505 attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&msg[1],
506 attrs_len);
507 if (NULL != op->ar_cb)
508 {
509 if (NULL == attrs)
510 {
511 op->ar_cb (op->cls,
512 &msg->identity,
513 NULL);
514 }
515 else
516 {
517 for (le = attrs->list_head; NULL != le; le = le->next)
518 op->ar_cb (op->cls,
519 &msg->identity,
520 le->claim);
521 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
522 }
523 }
524 if (NULL != op)
525 {
526 op->ar_cb (op->cls,
527 NULL,
528 NULL);
529 GNUNET_CONTAINER_DLL_remove (h->op_head,
530 h->op_tail,
531 op);
532 free_op (op);
533 }
534 return;
535 }
536 GNUNET_assert (0);
537}
538
539
540/**
541 * Handle an incoming message of type
542 * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
543 *
544 * @param cls
545 * @param msg the message we received
546 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
547 */
548static int
549check_attribute_result (void *cls,
550 const struct AttributeResultMessage *msg)
551{
552 size_t msg_len;
553 size_t attr_len;
554
555 msg_len = ntohs (msg->header.size);
556 attr_len = ntohs (msg->attr_len);
557 if (msg_len != sizeof (struct AttributeResultMessage) + attr_len)
558 {
559 GNUNET_break (0);
560 return GNUNET_SYSERR;
561 }
562 return GNUNET_OK;
563}
564
565
566/**
567 * Handle an incoming message of type
568 * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
569 *
570 * @param cls
571 * @param msg the message we received
572 */
573static void
574handle_attribute_result (void *cls,
575 const struct AttributeResultMessage *msg)
576{
577 static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
578 struct GNUNET_RECLAIM_Handle *h = cls;
579 struct GNUNET_RECLAIM_AttributeIterator *it;
580 struct GNUNET_RECLAIM_Operation *op;
581 size_t attr_len;
582 uint32_t r_id = ntohl (msg->id);
583
584 attr_len = ntohs (msg->attr_len);
585 LOG (GNUNET_ERROR_TYPE_DEBUG,
586 "Processing attribute result.\n");
587
588
589 for (it = h->it_head; NULL != it; it = it->next)
590 if (it->r_id == r_id)
591 break;
592 for (op = h->op_head; NULL != op; op = op->next)
593 if (op->r_id == r_id)
594 break;
595 if ((NULL == it) && (NULL == op))
596 return;
597
598 if ( (0 == (memcmp (&msg->identity,
599 &identity_dummy,
600 sizeof (identity_dummy)))) )
601 {
602 if ((NULL == it) && (NULL == op))
603 {
604 GNUNET_break (0);
605 force_reconnect (h);
606 return;
607 }
608 if (NULL != it)
609 {
610 if (NULL != it->finish_cb)
611 it->finish_cb (it->finish_cb_cls);
612 free_it (it);
613 }
614 if (NULL != op)
615 {
616 if (NULL != op->ar_cb)
617 op->ar_cb (op->cls,
618 NULL,
619 NULL);
620 GNUNET_CONTAINER_DLL_remove (h->op_head,
621 h->op_tail,
622 op);
623 free_op (op);
624
625 }
626 return;
627 }
628
629 {
630 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
631 attr = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&msg[1],
632 attr_len);
633 if (NULL != it)
634 {
635 if (NULL != it->proc)
636 it->proc (it->proc_cls,
637 &msg->identity,
638 attr);
639 } else if (NULL != op)
640 {
641 if (NULL != op->ar_cb)
642 op->ar_cb (op->cls,
643 &msg->identity,
644 attr);
645
646 }
647 GNUNET_free (attr);
648 return;
649 }
650 GNUNET_assert (0);
651}
652
653/**
654 * Handle an incoming message of type
655 * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
656 *
657 * @param cls
658 * @param msg the message we received
659 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
660 */
661static int
662check_ticket_result (void *cls,
663 const struct TicketResultMessage *msg)
664{
665 size_t msg_len;
666
667 msg_len = ntohs (msg->header.size);
668 if (msg_len < sizeof (struct TicketResultMessage))
669 {
670 GNUNET_break (0);
671 return GNUNET_SYSERR;
672 }
673 return GNUNET_OK;
674}
675
676
677
678/**
679 * Handle an incoming message of type
680 * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
681 *
682 * @param cls
683 * @param msg the message we received
684 */
685static void
686handle_ticket_result (void *cls,
687 const struct TicketResultMessage *msg)
688{
689 struct GNUNET_RECLAIM_Handle *handle = cls;
690 struct GNUNET_RECLAIM_Operation *op;
691 struct GNUNET_RECLAIM_TicketIterator *it;
692 const struct GNUNET_RECLAIM_Ticket *ticket;
693 uint32_t r_id = ntohl (msg->id);
694 size_t msg_len;
695
696 for (op = handle->op_head; NULL != op; op = op->next)
697 if (op->r_id == r_id)
698 break;
699 for (it = handle->ticket_it_head; NULL != it; it = it->next)
700 if (it->r_id == r_id)
701 break;
702 if ((NULL == op) && (NULL == it))
703 return;
704 msg_len = ntohs (msg->header.size);
705 if (NULL != op)
706 {
707 GNUNET_CONTAINER_DLL_remove (handle->op_head,
708 handle->op_tail,
709 op);
710 if (msg_len == sizeof (struct TicketResultMessage))
711 {
712 if (NULL != op->tr_cb)
713 op->tr_cb (op->cls, NULL);
714 } else {
715 ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1];
716 if (NULL != op->tr_cb)
717 op->tr_cb (op->cls, ticket);
718 }
719 free_op (op);
720 return;
721 } else if (NULL != it) {
722 if (msg_len == sizeof (struct TicketResultMessage))
723 {
724 if (NULL != it->tr_cb)
725 GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
726 handle->ticket_it_tail,
727 it);
728 it->finish_cb (it->finish_cb_cls);
729 GNUNET_free (it);
730 } else {
731 ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1];
732 if (NULL != it->tr_cb)
733 it->tr_cb (it->cls, ticket);
734 }
735 return;
736 }
737 GNUNET_break (0);
738}
739
740
741/**
742 * Handle an incoming message of type
743 * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
744 *
745 * @param cls
746 * @param msg the message we received
747 */
748static void
749handle_revoke_ticket_result (void *cls,
750 const struct RevokeTicketResultMessage *msg)
751{
752 struct GNUNET_RECLAIM_Handle *h = cls;
753 struct GNUNET_RECLAIM_Operation *op;
754 uint32_t r_id = ntohl (msg->id);
755 int32_t success;
756
757 LOG (GNUNET_ERROR_TYPE_DEBUG,
758 "Processing revocation result.\n");
759
760
761 for (op = h->op_head; NULL != op; op = op->next)
762 if (op->r_id == r_id)
763 break;
764 if (NULL == op)
765 return;
766 success = ntohl (msg->success);
767 {
768 if (NULL != op->rvk_cb)
769 {
770 op->rvk_cb (op->cls,
771 success,
772 NULL);
773 }
774 GNUNET_CONTAINER_DLL_remove (h->op_head,
775 h->op_tail,
776 op);
777 free_op (op);
778 return;
779 }
780 GNUNET_assert (0);
781}
782
783
784
785/**
786 * Try again to connect to the service.
787 *
788 * @param h handle to the reclaim service.
789 */
790static void
791reconnect (struct GNUNET_RECLAIM_Handle *h)
792{
793 struct GNUNET_MQ_MessageHandler handlers[] = {
794 GNUNET_MQ_hd_fixed_size (attribute_store_response,
795 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE,
796 struct AttributeStoreResultMessage,
797 h),
798 GNUNET_MQ_hd_var_size (attribute_result,
799 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
800 struct AttributeResultMessage,
801 h),
802 GNUNET_MQ_hd_var_size (ticket_result,
803 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
804 struct TicketResultMessage,
805 h),
806 GNUNET_MQ_hd_var_size (consume_ticket_result,
807 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
808 struct ConsumeTicketResultMessage,
809 h),
810 GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
811 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
812 struct RevokeTicketResultMessage,
813 h),
814 GNUNET_MQ_handler_end ()
815 };
816 struct GNUNET_RECLAIM_Operation *op;
817
818 GNUNET_assert (NULL == h->mq);
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
820 "Connecting to reclaim service.\n");
821
822 h->mq = GNUNET_CLIENT_connect (h->cfg,
823 "reclaim",
824 handlers,
825 &mq_error_handler,
826 h);
827 if (NULL == h->mq)
828 return;
829 for (op = h->op_head; NULL != op; op = op->next)
830 GNUNET_MQ_send_copy (h->mq,
831 op->env);
832}
833
834
835/**
836 * Connect to the reclaim service.
837 *
838 * @param cfg the configuration to use
839 * @return handle to use
840 */
841struct GNUNET_RECLAIM_Handle *
842GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
843{
844 struct GNUNET_RECLAIM_Handle *h;
845
846 h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
847 h->cfg = cfg;
848 reconnect (h);
849 if (NULL == h->mq)
850 {
851 GNUNET_free (h);
852 return NULL;
853 }
854 return h;
855}
856
857
858/**
859 * Cancel an operation. Note that the operation MAY still
860 * be executed; this merely cancels the continuation; if the request
861 * was already transmitted, the service may still choose to complete
862 * the operation.
863 *
864 * @param op operation to cancel
865 */
866void
867GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
868{
869 struct GNUNET_RECLAIM_Handle *h = op->h;
870
871 GNUNET_CONTAINER_DLL_remove (h->op_head,
872 h->op_tail,
873 op);
874 free_op (op);
875}
876
877
878/**
879 * Disconnect from service
880 *
881 * @param h handle to destroy
882 */
883void
884GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
885{
886 GNUNET_assert (NULL != h);
887 if (NULL != h->mq)
888 {
889 GNUNET_MQ_destroy (h->mq);
890 h->mq = NULL;
891 }
892 if (NULL != h->reconnect_task)
893 {
894 GNUNET_SCHEDULER_cancel (h->reconnect_task);
895 h->reconnect_task = NULL;
896 }
897 GNUNET_assert (NULL == h->op_head);
898 GNUNET_free (h);
899}
900
901/**
902 * Store an attribute. If the attribute is already present,
903 * it is replaced with the new attribute.
904 *
905 * @param h handle to the reclaim
906 * @param pkey private key of the identity
907 * @param attr the attribute value
908 * @param exp_interval the relative expiration interval for the attribute
909 * @param cont continuation to call when done
910 * @param cont_cls closure for @a cont
911 * @return handle to abort the request
912 */
913struct GNUNET_RECLAIM_Operation *
914GNUNET_RECLAIM_attribute_store (struct GNUNET_RECLAIM_Handle *h,
915 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
916 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
917 const struct GNUNET_TIME_Relative *exp_interval,
918 GNUNET_RECLAIM_ContinuationWithStatus cont,
919 void *cont_cls)
920{
921 struct GNUNET_RECLAIM_Operation *op;
922 struct AttributeStoreMessage *sam;
923 size_t attr_len;
924
925 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
926 op->h = h;
927 op->as_cb = cont;
928 op->cls = cont_cls;
929 op->r_id = h->r_id_gen++;
930 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
931 h->op_tail,
932 op);
933 attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
934 op->env = GNUNET_MQ_msg_extra (sam,
935 attr_len,
936 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
937 sam->identity = *pkey;
938 sam->id = htonl (op->r_id);
939 sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
940
941 GNUNET_RECLAIM_ATTRIBUTE_serialize (attr,
942 (char*)&sam[1]);
943
944 sam->attr_len = htons (attr_len);
945 if (NULL != h->mq)
946 GNUNET_MQ_send_copy (h->mq,
947 op->env);
948 return op;
949
950}
951
952
953/**
954 * List all attributes for a local identity.
955 * This MUST lock the `struct GNUNET_RECLAIM_Handle`
956 * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
957 * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
958 * immediately, and then again after
959 * #GNUNET_RECLAIM_get_attributes_next() is invoked.
960 *
961 * On error (disconnect), @a error_cb will be invoked.
962 * On normal completion, @a finish_cb proc will be
963 * invoked.
964 *
965 * @param h handle to the idp
966 * @param identity identity to access
967 * @param error_cb function to call on error (i.e. disconnect),
968 * the handle is afterwards invalid
969 * @param error_cb_cls closure for @a error_cb
970 * @param proc function to call on each attribute; it
971 * will be called repeatedly with a value (if available)
972 * @param proc_cls closure for @a proc
973 * @param finish_cb function to call on completion
974 * the handle is afterwards invalid
975 * @param finish_cb_cls closure for @a finish_cb
976 * @return an iterator handle to use for iteration
977 */
978struct GNUNET_RECLAIM_AttributeIterator *
979GNUNET_RECLAIM_get_attributes_start (struct GNUNET_RECLAIM_Handle *h,
980 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
981 GNUNET_SCHEDULER_TaskCallback error_cb,
982 void *error_cb_cls,
983 GNUNET_RECLAIM_AttributeResult proc,
984 void *proc_cls,
985 GNUNET_SCHEDULER_TaskCallback finish_cb,
986 void *finish_cb_cls)
987{
988 struct GNUNET_RECLAIM_AttributeIterator *it;
989 struct GNUNET_MQ_Envelope *env;
990 struct AttributeIterationStartMessage *msg;
991 uint32_t rid;
992
993 rid = h->r_id_gen++;
994 it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
995 it->h = h;
996 it->error_cb = error_cb;
997 it->error_cb_cls = error_cb_cls;
998 it->finish_cb = finish_cb;
999 it->finish_cb_cls = finish_cb_cls;
1000 it->proc = proc;
1001 it->proc_cls = proc_cls;
1002 it->r_id = rid;
1003 it->identity = *identity;
1004 GNUNET_CONTAINER_DLL_insert_tail (h->it_head,
1005 h->it_tail,
1006 it);
1007 env = GNUNET_MQ_msg (msg,
1008 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
1009 msg->id = htonl (rid);
1010 msg->identity = *identity;
1011 if (NULL == h->mq)
1012 it->env = env;
1013 else
1014 GNUNET_MQ_send (h->mq,
1015 env);
1016 return it;
1017}
1018
1019
1020/**
1021 * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
1022 * for the next record.
1023 *
1024 * @param it the iterator
1025 */
1026void
1027GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
1028{
1029 struct GNUNET_RECLAIM_Handle *h = it->h;
1030 struct AttributeIterationNextMessage *msg;
1031 struct GNUNET_MQ_Envelope *env;
1032
1033 env = GNUNET_MQ_msg (msg,
1034 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
1035 msg->id = htonl (it->r_id);
1036 GNUNET_MQ_send (h->mq,
1037 env);
1038}
1039
1040
1041/**
1042 * Stops iteration and releases the idp handle for further calls. Must
1043 * be called on any iteration that has not yet completed prior to calling
1044 * #GNUNET_RECLAIM_disconnect.
1045 *
1046 * @param it the iterator
1047 */
1048void
1049GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1050{
1051 struct GNUNET_RECLAIM_Handle *h = it->h;
1052 struct GNUNET_MQ_Envelope *env;
1053 struct AttributeIterationStopMessage *msg;
1054
1055 if (NULL != h->mq)
1056 {
1057 env = GNUNET_MQ_msg (msg,
1058 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1059 msg->id = htonl (it->r_id);
1060 GNUNET_MQ_send (h->mq,
1061 env);
1062 }
1063 free_it (it);
1064}
1065
1066
1067/** TODO
1068 * Issues a ticket to another identity. The identity may use
1069 * @GNUNET_RECLAIM_authorization_ticket_consume to consume the ticket
1070 * and retrieve the attributes specified in the AttributeList.
1071 *
1072 * @param h the reclaim to use
1073 * @param iss the issuing identity
1074 * @param rp the subject of the ticket (the relying party)
1075 * @param attrs the attributes that the relying party is given access to
1076 * @param cb the callback
1077 * @param cb_cls the callback closure
1078 * @return handle to abort the operation
1079 */
1080struct GNUNET_RECLAIM_Operation *
1081GNUNET_RECLAIM_ticket_issue (struct GNUNET_RECLAIM_Handle *h,
1082 const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1083 const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1084 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1085 GNUNET_RECLAIM_TicketCallback cb,
1086 void *cb_cls)
1087{
1088 struct GNUNET_RECLAIM_Operation *op;
1089 struct IssueTicketMessage *tim;
1090 size_t attr_len;
1091
1092 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1093 op->h = h;
1094 op->tr_cb = cb;
1095 op->cls = cb_cls;
1096 op->r_id = h->r_id_gen++;
1097 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1098 h->op_tail,
1099 op);
1100 attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1101 op->env = GNUNET_MQ_msg_extra (tim,
1102 attr_len,
1103 GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1104 tim->identity = *iss;
1105 tim->rp = *rp;
1106 tim->id = htonl (op->r_id);
1107
1108 GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs,
1109 (char*)&tim[1]);
1110
1111 tim->attr_len = htons (attr_len);
1112 if (NULL != h->mq)
1113 GNUNET_MQ_send_copy (h->mq,
1114 op->env);
1115 return op;
1116}
1117
1118/**
1119 * Consumes an issued ticket. The ticket is persisted
1120 * and used to retrieve identity information from the issuer
1121 *
1122 * @param h the reclaim to use
1123 * @param identity the identity that is the subject of the issued ticket (the relying party)
1124 * @param ticket the issued ticket to consume
1125 * @param cb the callback to call
1126 * @param cb_cls the callback closure
1127 * @return handle to abort the operation
1128 */
1129struct GNUNET_RECLAIM_Operation *
1130GNUNET_RECLAIM_ticket_consume (struct GNUNET_RECLAIM_Handle *h,
1131 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1132 const struct GNUNET_RECLAIM_Ticket *ticket,
1133 GNUNET_RECLAIM_AttributeResult cb,
1134 void *cb_cls)
1135{
1136 struct GNUNET_RECLAIM_Operation *op;
1137 struct ConsumeTicketMessage *ctm;
1138
1139 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1140 op->h = h;
1141 op->ar_cb = cb;
1142 op->cls = cb_cls;
1143 op->r_id = h->r_id_gen++;
1144 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1145 h->op_tail,
1146 op);
1147 op->env = GNUNET_MQ_msg_extra (ctm,
1148 sizeof (const struct GNUNET_RECLAIM_Ticket),
1149 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1150 ctm->identity = *identity;
1151 ctm->id = htonl (op->r_id);
1152
1153 GNUNET_memcpy ((char*)&ctm[1],
1154 ticket,
1155 sizeof (const struct GNUNET_RECLAIM_Ticket));
1156
1157 if (NULL != h->mq)
1158 GNUNET_MQ_send_copy (h->mq,
1159 op->env);
1160 return op;
1161
1162}
1163
1164
1165/**
1166 * Lists all tickets that have been issued to remote
1167 * identites (relying parties)
1168 *
1169 * @param h the reclaim to use
1170 * @param identity the issuing identity
1171 * @param error_cb function to call on error (i.e. disconnect),
1172 * the handle is afterwards invalid
1173 * @param error_cb_cls closure for @a error_cb
1174 * @param proc function to call on each ticket; it
1175 * will be called repeatedly with a value (if available)
1176 * @param proc_cls closure for @a proc
1177 * @param finish_cb function to call on completion
1178 * the handle is afterwards invalid
1179 * @param finish_cb_cls closure for @a finish_cb
1180 * @return an iterator handle to use for iteration
1181 */
1182struct GNUNET_RECLAIM_TicketIterator *
1183GNUNET_RECLAIM_ticket_iteration_start (struct GNUNET_RECLAIM_Handle *h,
1184 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1185 GNUNET_SCHEDULER_TaskCallback error_cb,
1186 void *error_cb_cls,
1187 GNUNET_RECLAIM_TicketCallback proc,
1188 void *proc_cls,
1189 GNUNET_SCHEDULER_TaskCallback finish_cb,
1190 void *finish_cb_cls)
1191{
1192 struct GNUNET_RECLAIM_TicketIterator *it;
1193 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
1194 struct GNUNET_MQ_Envelope *env;
1195 struct TicketIterationStartMessage *msg;
1196 uint32_t rid;
1197
1198 GNUNET_CRYPTO_ecdsa_key_get_public (identity,
1199 &identity_pub);
1200 rid = h->r_id_gen++;
1201 it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1202 it->h = h;
1203 it->error_cb = error_cb;
1204 it->error_cb_cls = error_cb_cls;
1205 it->finish_cb = finish_cb;
1206 it->finish_cb_cls = finish_cb_cls;
1207 it->tr_cb = proc;
1208 it->cls = proc_cls;
1209 it->r_id = rid;
1210 GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1211 h->ticket_it_tail,
1212 it);
1213 env = GNUNET_MQ_msg (msg,
1214 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1215 msg->id = htonl (rid);
1216 msg->identity = identity_pub;
1217 msg->is_audience = htonl (GNUNET_NO);
1218 if (NULL == h->mq)
1219 it->env = env;
1220 else
1221 GNUNET_MQ_send (h->mq,
1222 env);
1223 return it;
1224
1225}
1226
1227
1228/**
1229 * Lists all tickets that have been issued to remote
1230 * identites (relying parties)
1231 *
1232 * @param h the reclaim to use
1233 * @param identity the issuing identity
1234 * @param error_cb function to call on error (i.e. disconnect),
1235 * the handle is afterwards invalid
1236 * @param error_cb_cls closure for @a error_cb
1237 * @param proc function to call on each ticket; it
1238 * will be called repeatedly with a value (if available)
1239 * @param proc_cls closure for @a proc
1240 * @param finish_cb function to call on completion
1241 * the handle is afterwards invalid
1242 * @param finish_cb_cls closure for @a finish_cb
1243 * @return an iterator handle to use for iteration
1244 */
1245struct GNUNET_RECLAIM_TicketIterator *
1246GNUNET_RECLAIM_ticket_iteration_start_rp (struct GNUNET_RECLAIM_Handle *h,
1247 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1248 GNUNET_SCHEDULER_TaskCallback error_cb,
1249 void *error_cb_cls,
1250 GNUNET_RECLAIM_TicketCallback proc,
1251 void *proc_cls,
1252 GNUNET_SCHEDULER_TaskCallback finish_cb,
1253 void *finish_cb_cls)
1254{
1255 struct GNUNET_RECLAIM_TicketIterator *it;
1256 struct GNUNET_MQ_Envelope *env;
1257 struct TicketIterationStartMessage *msg;
1258 uint32_t rid;
1259
1260 rid = h->r_id_gen++;
1261 it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1262 it->h = h;
1263 it->error_cb = error_cb;
1264 it->error_cb_cls = error_cb_cls;
1265 it->finish_cb = finish_cb;
1266 it->finish_cb_cls = finish_cb_cls;
1267 it->tr_cb = proc;
1268 it->cls = proc_cls;
1269 it->r_id = rid;
1270 GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head,
1271 h->ticket_it_tail,
1272 it);
1273 env = GNUNET_MQ_msg (msg,
1274 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1275 msg->id = htonl (rid);
1276 msg->identity = *identity;
1277 msg->is_audience = htonl (GNUNET_YES);
1278 if (NULL == h->mq)
1279 it->env = env;
1280 else
1281 GNUNET_MQ_send (h->mq,
1282 env);
1283 return it;
1284
1285
1286}
1287
1288/**
1289 * Calls the record processor specified in #GNUNET_RECLAIM_ticket_iteration_start
1290 * for the next record.
1291 *
1292 * @param it the iterator
1293 */
1294void
1295GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1296{
1297 struct GNUNET_RECLAIM_Handle *h = it->h;
1298 struct TicketIterationNextMessage *msg;
1299 struct GNUNET_MQ_Envelope *env;
1300
1301 env = GNUNET_MQ_msg (msg,
1302 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1303 msg->id = htonl (it->r_id);
1304 GNUNET_MQ_send (h->mq,
1305 env);
1306}
1307
1308
1309/**
1310 * Stops iteration and releases the idp handle for further calls. Must
1311 * be called on any iteration that has not yet completed prior to calling
1312 * #GNUNET_RECLAIM_disconnect.
1313 *
1314 * @param it the iterator
1315 */
1316void
1317GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1318{
1319 struct GNUNET_RECLAIM_Handle *h = it->h;
1320 struct GNUNET_MQ_Envelope *env;
1321 struct TicketIterationStopMessage *msg;
1322
1323 if (NULL != h->mq)
1324 {
1325 env = GNUNET_MQ_msg (msg,
1326 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1327 msg->id = htonl (it->r_id);
1328 GNUNET_MQ_send (h->mq,
1329 env);
1330 }
1331 GNUNET_free (it);
1332}
1333
1334/**
1335 * Revoked an issued ticket. The relying party will be unable to retrieve
1336 * updated attributes.
1337 *
1338 * @param h the reclaim to use
1339 * @param identity the issuing identity
1340 * @param ticket the ticket to revoke
1341 * @param cb the callback
1342 * @param cb_cls the callback closure
1343 * @return handle to abort the operation
1344 */
1345struct GNUNET_RECLAIM_Operation *
1346GNUNET_RECLAIM_ticket_revoke (struct GNUNET_RECLAIM_Handle *h,
1347 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1348 const struct GNUNET_RECLAIM_Ticket *ticket,
1349 GNUNET_RECLAIM_ContinuationWithStatus cb,
1350 void *cb_cls)
1351{
1352 struct GNUNET_RECLAIM_Operation *op;
1353 struct RevokeTicketMessage *msg;
1354 uint32_t rid;
1355
1356 rid = h->r_id_gen++;
1357 op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1358 op->h = h;
1359 op->rvk_cb = cb;
1360 op->cls = cb_cls;
1361 op->r_id = rid;
1362 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1363 h->op_tail,
1364 op);
1365 op->env = GNUNET_MQ_msg_extra (msg,
1366 sizeof (struct GNUNET_RECLAIM_Ticket),
1367 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1368 msg->id = htonl (rid);
1369 msg->identity = *identity;
1370 GNUNET_memcpy (&msg[1],
1371 ticket,
1372 sizeof (struct GNUNET_RECLAIM_Ticket));
1373 if (NULL != h->mq) {
1374 GNUNET_MQ_send (h->mq,
1375 op->env);
1376 op->env = NULL;
1377 }
1378 return op;
1379}
1380
1381
1382
1383/* end of reclaim_api.c */
diff --git a/src/reclaim/test_reclaim.sh b/src/reclaim/test_reclaim.sh
new file mode 100755
index 000000000..311f5382a
--- /dev/null
+++ b/src/reclaim/test_reclaim.sh
@@ -0,0 +1,31 @@
1#!/bin/bash
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 && 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.sh b/src/reclaim/test_reclaim_attribute.sh
new file mode 100755
index 000000000..39bd715b7
--- /dev/null
+++ b/src/reclaim/test_reclaim_attribute.sh
@@ -0,0 +1,40 @@
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 -c test_reclaim.conf | grep testego | awk '{print $3}')
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
new file mode 100755
index 000000000..36c8052d0
--- /dev/null
+++ b/src/reclaim/test_reclaim_consume.sh
@@ -0,0 +1,43 @@
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
30SUBJECT_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep rpego | awk '{print $3}')
31TEST_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep testego | awk '{print $3}')
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
new file mode 100644
index 000000000..a9a197dea
--- /dev/null
+++ b/src/reclaim/test_reclaim_defaults.conf
@@ -0,0 +1,24 @@
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
new file mode 100755
index 000000000..6a71470e1
--- /dev/null
+++ b/src/reclaim/test_reclaim_issue.sh
@@ -0,0 +1,42 @@
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
30SUBJECT_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep rpego | awk '{print $3}')
31TEST_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep testego | awk '{print $3}')
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
new file mode 100755
index 000000000..595752fd8
--- /dev/null
+++ b/src/reclaim/test_reclaim_revoke.sh
@@ -0,0 +1,65 @@
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 2&>1 > /dev/null
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 -c test_reclaim.conf | grep alice | awk '{print $3}')
31BOB_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep bob | awk '{print $3}')
32EVE_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep eve | awk '{print $3}')
33
34gnunet-reclaim -e alice -E 15s -a email -V john@doe.gnu -c test_reclaim.conf
35gnunet-reclaim -e alice -E 15s -a name -V John -c test_reclaim.conf
36TICKET_BOB=$(gnunet-reclaim -e alice -i "email,name" -r $BOB_KEY -c test_reclaim.conf | awk '{print $1}')
37#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf
38TICKET_EVE=$(gnunet-reclaim -e alice -i "email" -r $EVE_KEY -c test_reclaim.conf | awk '{print $1}')
39
40#echo "Consuming $TICKET"
41#gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf
42gnunet-reclaim -e alice -R $TICKET_EVE -c test_reclaim.conf
43
44#sleep 6
45
46gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf 2&>1 >/dev/null
47if test $? == 0
48then
49 echo "Eve can still resolve attributes..."
50 gnunet-arm -e -c test_reclaim.conf
51 exit 1
52fi
53
54gnunet-arm -e -c test_reclaim.conf
55gnunet-arm -s -c test_reclaim.conf 2&>1 > /dev/null
56
57gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf 2&>1 >/dev/null
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