aboutsummaryrefslogtreecommitdiff
path: root/src/reclaim
diff options
context:
space:
mode:
authorSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-07-19 23:28:53 +0200
committerSchanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de>2018-07-19 23:28:53 +0200
commit4fd677cec39e5621d16bc2c63926b803b31582e3 (patch)
treeb1ed7c7544c1a8a721308d67c908e0f3cd758486 /src/reclaim
parent0f75e5c54c6e6c9087cf565539266514abd67e98 (diff)
downloadgnunet-4fd677cec39e5621d16bc2c63926b803b31582e3.tar.gz
gnunet-4fd677cec39e5621d16bc2c63926b803b31582e3.zip
renamed identity-provider subsystem to reclaim
Diffstat (limited to 'src/reclaim')
-rw-r--r--src/reclaim/.gitignore2
-rw-r--r--src/reclaim/Makefile.am140
-rw-r--r--src/reclaim/gnunet-reclaim.c517
-rw-r--r--src/reclaim/gnunet-service-reclaim.c2786
-rw-r--r--src/reclaim/jwt.c160
-rw-r--r--src/reclaim/jwt.h10
-rw-r--r--src/reclaim/plugin_gnsrecord_reclaim.c265
-rw-r--r--src/reclaim/plugin_reclaim_sqlite.c734
-rw-r--r--src/reclaim/plugin_rest_openid_connect.c2227
-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
19 files changed, 10155 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..c13c68763
--- /dev/null
+++ b/src/reclaim/Makefile.am
@@ -0,0 +1,140 @@
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 libgnunetidentityprovider.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 libgnunetidentityprovider.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 libgnunetidentityprovider.la \
78 $(top_builddir)/src/gns/libgnunetgns.la \
79 $(GN_LIBINTL)
80
81libgnunetidentityprovider_la_SOURCES = \
82 reclaim_api.c \
83 reclaim.h
84libgnunetidentityprovider_la_LIBADD = \
85 $(top_builddir)/src/util/libgnunetutil.la \
86 $(GN_LIBINTL) $(XLIB)
87libgnunetidentityprovider_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 \
93 jwt.c
94libgnunet_plugin_rest_reclaim_la_LIBADD = \
95 $(top_builddir)/src/identity/libgnunetidentity.la \
96 libgnunetidentityprovider.la \
97 $(top_builddir)/src/rest/libgnunetrest.la \
98 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
99 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
100 $(top_builddir)/src/namestore/libgnunetnamestore.la \
101 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
102 $(LTLIBINTL) -ljansson -lmicrohttpd
103libgnunet_plugin_rest_reclaim_la_LDFLAGS = \
104 $(GN_PLUGIN_LDFLAGS)
105
106libgnunet_plugin_rest_openid_connect_la_SOURCES = \
107 plugin_rest_openid_connect.c \
108 jwt.c
109libgnunet_plugin_rest_openid_connect_la_LIBADD = \
110 $(top_builddir)/src/identity/libgnunetidentity.la \
111 libgnunetidentityprovider.la \
112 $(top_builddir)/src/rest/libgnunetrest.la \
113 $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
114 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
115 $(top_builddir)/src/namestore/libgnunetnamestore.la \
116 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
117 $(LTLIBINTL) -ljansson -lmicrohttpd
118libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \
119 $(GN_PLUGIN_LDFLAGS)
120
121gnunet_reclaim_SOURCES = \
122 gnunet-reclaim.c
123gnunet_reclaim_LDADD = \
124 $(top_builddir)/src/util/libgnunetutil.la \
125 $(top_builddir)/src/namestore/libgnunetnamestore.la \
126 libgnunetidentityprovider.la \
127 $(top_builddir)/src/identity/libgnunetidentity.la \
128 $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \
129 $(GN_LIBINTL)
130
131check_SCRIPTS = \
132 test_reclaim_attribute.sh \
133 test_reclaim_issue.sh \
134 test_reclaim_consume.sh \
135 test_reclaim_revoke.sh
136
137if ENABLE_TEST_RUN
138 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
139 TESTS = $(check_SCRIPTS)
140endif
diff --git a/src/reclaim/gnunet-reclaim.c b/src/reclaim/gnunet-reclaim.c
new file mode 100644
index 000000000..9947eac6d
--- /dev/null
+++ b/src/reclaim/gnunet-reclaim.c
@@ -0,0 +1,517 @@
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
137static void
138do_cleanup(void *cls)
139{
140 if (NULL != timeout)
141 GNUNET_SCHEDULER_cancel (timeout);
142 if (NULL != reclaim_op)
143 GNUNET_RECLAIM_cancel (reclaim_op);
144 if (NULL != attr_iterator)
145 GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
146 if (NULL != reclaim_handle)
147 GNUNET_RECLAIM_disconnect (reclaim_handle);
148 if (NULL != identity_handle)
149 GNUNET_IDENTITY_disconnect (identity_handle);
150 if (NULL != abe_key)
151 GNUNET_free (abe_key);
152 if (NULL != attr_list)
153 GNUNET_free (attr_list);
154}
155
156static void
157ticket_issue_cb (void* cls,
158 const struct GNUNET_RECLAIM_Ticket *ticket)
159{
160 char* ticket_str;
161 reclaim_op = NULL;
162 if (NULL != ticket) {
163 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
164 sizeof (struct GNUNET_RECLAIM_Ticket));
165 printf("%s\n",
166 ticket_str);
167 GNUNET_free (ticket_str);
168 }
169 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
170}
171
172static void
173store_attr_cont (void *cls,
174 int32_t success,
175 const char*emsg)
176{
177 reclaim_op = NULL;
178 if (GNUNET_SYSERR == success) {
179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
180 "%s\n", emsg);
181 }
182 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
183}
184
185static void
186process_attrs (void *cls,
187 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
188 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
189{
190 char *value_str;
191 if (NULL == identity)
192 {
193 reclaim_op = NULL;
194 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
195 return;
196 }
197 if (NULL == attr)
198 {
199 ret = 1;
200 return;
201 }
202 value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
203 attr->data,
204 attr->data_size);
205 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
206 "%s: %s\n", attr->name, value_str);
207}
208
209
210static void
211iter_error (void *cls)
212{
213 attr_iterator = NULL;
214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 "Failed to iterate over attributes\n");
216 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
217}
218
219static void
220timeout_task (void *cls)
221{
222 timeout = NULL;
223 ret = 1;
224 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
225 "Timeout\n");
226 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
227}
228
229static void
230process_rvk (void *cls, int success, const char* msg)
231{
232 reclaim_op = NULL;
233 if (GNUNET_OK != success)
234 {
235 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
236 "Revocation failed.\n");
237 ret = 1;
238 }
239 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
240}
241
242static void
243iter_finished (void *cls)
244{
245 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
246 char *data;
247 size_t data_size;
248 int type;
249
250 attr_iterator = NULL;
251 if (list)
252 {
253 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
254 return;
255 }
256
257 if (issue_attrs)
258 {
259 reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
260 pkey,
261 &rp_key,
262 attr_list,
263 &ticket_issue_cb,
264 NULL);
265 return;
266 }
267 if (consume_ticket)
268 {
269 reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
270 pkey,
271 &ticket,
272 &process_attrs,
273 NULL);
274 timeout = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10),
275 &timeout_task,
276 NULL);
277 return;
278 }
279 if (revoke_ticket)
280 {
281 reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
282 pkey,
283 &ticket,
284 &process_rvk,
285 NULL);
286 return;
287 }
288 if (attr_name)
289 {
290 if (NULL == type_str)
291 type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
292 else
293 type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
294
295 GNUNET_assert (GNUNET_SYSERR != GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
296 attr_value,
297 (void**)&data,
298 &data_size));
299 claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name,
300 type,
301 data,
302 data_size);
303 reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
304 pkey,
305 claim,
306 &exp_interval,
307 &store_attr_cont,
308 NULL);
309 return;
310 }
311 GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
312}
313
314static void
315iter_cb (void *cls,
316 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
317 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
318{
319 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
320 char *attrs_tmp;
321 char *attr_str;
322
323 if (issue_attrs)
324 {
325 attrs_tmp = GNUNET_strdup (issue_attrs);
326 attr_str = strtok (attrs_tmp, ",");
327 while (NULL != attr_str) {
328 if (0 != strcmp (attr_str, attr->name)) {
329 attr_str = strtok (NULL, ",");
330 continue;
331 }
332 le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
333 le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
334 attr->type,
335 attr->data,
336 attr->data_size);
337 GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
338 attr_list->list_tail,
339 le);
340 break;
341 }
342 GNUNET_free (attrs_tmp);
343 } else if (list) {
344 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
345 "%s: %s\n", attr->name, (char*)attr->data);
346 }
347 GNUNET_RECLAIM_get_attributes_next (attr_iterator);
348}
349
350static void
351ego_iter_finished (void *cls)
352{
353 if (NULL == pkey)
354 {
355 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
356 "Ego %s not found\n", ego_name);
357 return;
358 }
359
360 if (NULL != rp)
361 GNUNET_CRYPTO_ecdsa_public_key_from_string (rp,
362 strlen (rp),
363 &rp_key);
364 if (NULL != consume_ticket)
365 GNUNET_STRINGS_string_to_data (consume_ticket,
366 strlen (consume_ticket),
367 &ticket,
368 sizeof (struct GNUNET_RECLAIM_Ticket));
369 if (NULL != revoke_ticket)
370 GNUNET_STRINGS_string_to_data (revoke_ticket,
371 strlen (revoke_ticket),
372 &ticket,
373 sizeof (struct GNUNET_RECLAIM_Ticket));
374
375
376 attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
377
378 attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
379 pkey,
380 &iter_error,
381 NULL,
382 &iter_cb,
383 NULL,
384 &iter_finished,
385 NULL);
386
387
388}
389
390static int init = GNUNET_YES;
391
392static void
393ego_cb (void *cls,
394 struct GNUNET_IDENTITY_Ego *ego,
395 void **ctx,
396 const char *name)
397{
398 if (NULL == name) {
399 if (GNUNET_YES == init) {
400 init = GNUNET_NO;
401 GNUNET_SCHEDULER_add_now (&ego_iter_finished, NULL);
402 }
403 return;
404 }
405 if (0 != strcmp (name, ego_name))
406 return;
407 pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
408}
409
410
411static void
412run (void *cls,
413 char *const *args,
414 const char *cfgfile,
415 const struct GNUNET_CONFIGURATION_Handle *c)
416{
417 ret = 0;
418 if (NULL == ego_name)
419 {
420 ret = 1;
421 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
422 _("Ego is required\n"));
423 return;
424 }
425
426 if ( (NULL == attr_value) && (NULL != attr_name) )
427 {
428 ret = 1;
429 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
430 _("Attribute value missing!\n"));
431 return;
432 }
433
434 if ( (NULL == rp) && (NULL != issue_attrs) )
435 {
436 ret = 1;
437 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
438 _("Requesting party key is required!\n"));
439 return;
440 }
441
442 reclaim_handle = GNUNET_RECLAIM_connect (c);
443 //Get Ego
444 identity_handle = GNUNET_IDENTITY_connect (c,
445 &ego_cb,
446 NULL);
447
448
449}
450
451
452int
453main(int argc, char *const argv[])
454{
455 exp_interval = GNUNET_TIME_UNIT_HOURS;
456 struct GNUNET_GETOPT_CommandLineOption options[] = {
457
458 GNUNET_GETOPT_option_string ('a',
459 "add",
460 NULL,
461 gettext_noop ("Add attribute"),
462 &attr_name),
463
464 GNUNET_GETOPT_option_string ('V',
465 "value",
466 NULL,
467 gettext_noop ("Attribute value"),
468 &attr_value),
469 GNUNET_GETOPT_option_string ('e',
470 "ego",
471 NULL,
472 gettext_noop ("Ego"),
473 &ego_name),
474 GNUNET_GETOPT_option_string ('r',
475 "rp",
476 NULL,
477 gettext_noop ("Audience (relying party)"),
478 &rp),
479 GNUNET_GETOPT_option_flag ('D',
480 "dump",
481 gettext_noop ("List attributes for Ego"),
482 &list),
483 GNUNET_GETOPT_option_string ('i',
484 "issue",
485 NULL,
486 gettext_noop ("Issue a ticket"),
487 &issue_attrs),
488 GNUNET_GETOPT_option_string ('C',
489 "consume",
490 NULL,
491 gettext_noop ("Consume a ticket"),
492 &consume_ticket),
493 GNUNET_GETOPT_option_string ('R',
494 "revoke",
495 NULL,
496 gettext_noop ("Revoke a ticket"),
497 &revoke_ticket),
498 GNUNET_GETOPT_option_string ('t',
499 "type",
500 NULL,
501 gettext_noop ("Type of attribute"),
502 &type_str),
503 GNUNET_GETOPT_option_relative_time ('E',
504 "expiration",
505 NULL,
506 gettext_noop ("Expiration interval of the attribute"),
507 &exp_interval),
508
509 GNUNET_GETOPT_OPTION_END
510 };
511 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "ct",
512 "ct", options,
513 &run, NULL))
514 return 1;
515 else
516 return ret;
517}
diff --git a/src/reclaim/gnunet-service-reclaim.c b/src/reclaim/gnunet-service-reclaim.c
new file mode 100644
index 000000000..bf8780a92
--- /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 GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim,
1443 buf);
1444 rh->attrs->list_head->claim->version++;
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..45b5d73f6
--- /dev/null
+++ b/src/reclaim/jwt.c
@@ -0,0 +1,160 @@
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/jwt.c
21 * @brief helper library for JSON-Web-Tokens
22 * @author Martin Schanzenbach
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_signatures.h"
27#include "gnunet_reclaim_attribute_lib.h"
28#include <jansson.h>
29
30
31#define JWT_ALG "alg"
32
33/* Use 512bit HMAC */
34#define JWT_ALG_VALUE "HS512"
35
36#define JWT_TYP "typ"
37
38#define JWT_TYP_VALUE "jwt"
39
40#define SERVER_ADDRESS "https://reclaim.id/api/openid/userinfo"
41
42static char*
43create_jwt_header(void)
44{
45 json_t *root;
46 char *json_str;
47
48 root = json_object ();
49 json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
50 json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
51
52 json_str = json_dumps (root, JSON_INDENT(1));
53 json_decref (root);
54 return json_str;
55}
56
57/**
58 * Create a JWT from attributes
59 *
60 * @param aud_key the public of the subject
61 * @param attrs the attribute list
62 * @param priv_key the key used to sign the JWT
63 * @return a new base64-encoded JWT string.
64 */
65char*
66jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
67 const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
68 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
69 const struct GNUNET_CRYPTO_AuthKey *priv_key)
70{
71 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
72 struct GNUNET_HashCode signature;
73 char* audience;
74 char* subject;
75 char* header;
76 char* padding;
77 char* body_str;
78 char* result;
79 char* header_base64;
80 char* body_base64;
81 char* signature_target;
82 char* signature_base64;
83 char* attr_val_str;
84 json_t* body;
85
86 //exp REQUIRED time expired from config
87 //iat REQUIRED time now
88 //auth_time only if max_age
89 //nonce only if nonce
90 // OPTIONAL acr,amr,azp
91 subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key,
92 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
93 audience = GNUNET_STRINGS_data_to_string_alloc (aud_key,
94 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
95 header = create_jwt_header ();
96 body = json_object ();
97
98 //iss REQUIRED case sensitive server uri with https
99 //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid)
100 json_object_set_new (body,
101 "iss", json_string (SERVER_ADDRESS));
102 //sub REQUIRED public key identity, not exceed 255 ASCII length
103 json_object_set_new (body,
104 "sub", json_string (subject));
105 //aud REQUIRED public key client_id must be there
106 json_object_set_new (body,
107 "aud", json_string (audience));
108 for (le = attrs->list_head; NULL != le; le = le->next)
109 {
110 attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type,
111 le->claim->data,
112 le->claim->data_size);
113 json_object_set_new (body,
114 le->claim->name,
115 json_string (attr_val_str));
116 GNUNET_free (attr_val_str);
117 }
118 body_str = json_dumps (body, JSON_INDENT(0));
119 json_decref (body);
120
121 GNUNET_STRINGS_base64_encode (header,
122 strlen (header),
123 &header_base64);
124 //Remove GNUNET padding of base64
125 padding = strtok(header_base64, "=");
126 while (NULL != padding)
127 padding = strtok(NULL, "=");
128
129 GNUNET_STRINGS_base64_encode (body_str,
130 strlen (body_str),
131 &body_base64);
132
133 //Remove GNUNET padding of base64
134 padding = strtok(body_base64, "=");
135 while (NULL != padding)
136 padding = strtok(NULL, "=");
137
138 GNUNET_free (subject);
139 GNUNET_free (audience);
140
141 /**
142 * Creating the JWT signature. This might not be
143 * standards compliant, check.
144 */
145 GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64);
146 GNUNET_CRYPTO_hmac (priv_key, signature_target, strlen (signature_target), &signature);
147 GNUNET_STRINGS_base64_encode ((const char*)&signature,
148 sizeof (struct GNUNET_HashCode),
149 &signature_base64);
150 GNUNET_asprintf (&result, "%s.%s.%s",
151 header_base64, body_base64, signature_base64);
152
153 GNUNET_free (signature_target);
154 GNUNET_free (header);
155 GNUNET_free (body_str);
156 GNUNET_free (signature_base64);
157 GNUNET_free (body_base64);
158 GNUNET_free (header_base64);
159 return result;
160}
diff --git a/src/reclaim/jwt.h b/src/reclaim/jwt.h
new file mode 100644
index 000000000..4b0b01be3
--- /dev/null
+++ b/src/reclaim/jwt.h
@@ -0,0 +1,10 @@
1#ifndef JWT_H
2#define JWT_H
3
4char*
5jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
6 const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
7 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
8 const struct GNUNET_CRYPTO_AuthKey *priv_key);
9
10#endif
diff --git a/src/reclaim/plugin_gnsrecord_reclaim.c b/src/reclaim/plugin_gnsrecord_reclaim.c
new file mode 100644
index 000000000..0322df752
--- /dev/null
+++ b/src/reclaim/plugin_gnsrecord_reclaim.c
@@ -0,0 +1,265 @@
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 return GNUNET_strndup (data, data_size);
58 case GNUNET_GNSRECORD_TYPE_ABE_KEY:
59 case GNUNET_GNSRECORD_TYPE_ABE_MASTER:
60 return GNUNET_STRINGS_data_to_string_alloc (data, data_size);
61 case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: //DEPRECATED
62 ecdhe_privkey = data;
63 audience_pubkey = data+sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
64 scopes = (char*) audience_pubkey+(sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
65 ecdhe_str = GNUNET_STRINGS_data_to_string_alloc (ecdhe_privkey,
66 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
67 aud_str = GNUNET_STRINGS_data_to_string_alloc (audience_pubkey,
68 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
69 GNUNET_asprintf (&result,
70 "%s;%s;%s",
71 ecdhe_str, aud_str, scopes);
72 GNUNET_free (aud_str);
73 GNUNET_free (ecdhe_str);
74 return result;
75
76 default:
77 return NULL;
78 }
79}
80
81
82/**
83 * Convert human-readable version of a 'value' of a record to the binary
84 * representation.
85 *
86 * @param cls closure, unused
87 * @param type type of the record
88 * @param s human-readable string
89 * @param data set to value in binary encoding (will be allocated)
90 * @param data_size set to number of bytes in @a data
91 * @return #GNUNET_OK on success
92 */
93static int
94string_to_value (void *cls,
95 uint32_t type,
96 const char *s,
97 void **data,
98 size_t *data_size)
99{
100 char* ecdhe_str;
101 char* aud_keystr;
102 char* write_ptr;
103 char* tmp_tok;
104 char* str;
105
106 if (NULL == s)
107 return GNUNET_SYSERR;
108 switch (type)
109 {
110 case GNUNET_GNSRECORD_TYPE_ID_ATTR:
111 return GNUNET_STRINGS_string_to_data (s,
112 strlen (s),
113 *data,
114 *data_size);
115 case GNUNET_GNSRECORD_TYPE_ID_TOKEN:
116 *data = GNUNET_strdup (s);
117 *data_size = strlen (s);
118 return GNUNET_OK;
119 case GNUNET_GNSRECORD_TYPE_ABE_KEY:
120 case GNUNET_GNSRECORD_TYPE_ABE_MASTER:
121 return GNUNET_STRINGS_string_to_data (s,
122 strlen (s),
123 *data,
124 *data_size);
125 case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA:
126 tmp_tok = GNUNET_strdup (s);
127 ecdhe_str = strtok (tmp_tok, ";");
128 if (NULL == ecdhe_str)
129 {
130 GNUNET_free (tmp_tok);
131 return GNUNET_SYSERR;
132 }
133 aud_keystr = strtok (NULL, ";");
134 if (NULL == aud_keystr)
135 {
136 GNUNET_free (tmp_tok);
137 return GNUNET_SYSERR;
138 }
139 str = strtok (NULL, ";");
140 if (NULL == str)
141 {
142 GNUNET_free (tmp_tok);
143 return GNUNET_SYSERR;
144 }
145 *data_size = strlen (str) + 1
146 +sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
147 +sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
148 *data = GNUNET_malloc (*data_size);
149
150 write_ptr = *data;
151 GNUNET_STRINGS_string_to_data (ecdhe_str,
152 strlen (ecdhe_str),
153 write_ptr,
154 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
155 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
156 GNUNET_STRINGS_string_to_data (aud_keystr,
157 strlen (aud_keystr),
158 write_ptr,
159 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
160 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
161 GNUNET_memcpy (write_ptr, str, strlen (str) + 1); //with 0-Terminator
162 GNUNET_free (tmp_tok);
163 return GNUNET_OK;
164
165 default:
166 return GNUNET_SYSERR;
167 }
168}
169
170
171/**
172 * Mapping of record type numbers to human-readable
173 * record type names.
174 */
175static struct {
176 const char *name;
177 uint32_t number;
178} name_map[] = {
179 { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR },
180 { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN },
181 { "ABE_KEY", GNUNET_GNSRECORD_TYPE_ABE_KEY },
182 { "ABE_MASTER", GNUNET_GNSRECORD_TYPE_ABE_MASTER },
183 { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA },
184 { NULL, UINT32_MAX }
185};
186
187
188/**
189 * Convert a type name (i.e. "AAAA") to the corresponding number.
190 *
191 * @param cls closure, unused
192 * @param dns_typename name to convert
193 * @return corresponding number, UINT32_MAX on error
194 */
195static uint32_t
196typename_to_number (void *cls,
197 const char *dns_typename)
198{
199 unsigned int i;
200
201 i=0;
202 while ( (NULL != name_map[i].name) &&
203 (0 != strcasecmp (dns_typename, name_map[i].name)) )
204 i++;
205 return name_map[i].number;
206}
207
208
209/**
210 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
211 *
212 * @param cls closure, unused
213 * @param type number of a type to convert
214 * @return corresponding typestring, NULL on error
215 */
216static const char *
217number_to_typename (void *cls,
218 uint32_t type)
219{
220 unsigned int i;
221
222 i=0;
223 while ( (NULL != name_map[i].name) &&
224 (type != name_map[i].number) )
225 i++;
226 return name_map[i].name;
227}
228
229
230/**
231 * Entry point for the plugin.
232 *
233 * @param cls NULL
234 * @return the exported block API
235 */
236void *
237libgnunet_plugin_gnsrecord_reclaim_init (void *cls)
238{
239 struct GNUNET_GNSRECORD_PluginFunctions *api;
240
241 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
242 api->value_to_string = &value_to_string;
243 api->string_to_value = &string_to_value;
244 api->typename_to_number = &typename_to_number;
245 api->number_to_typename = &number_to_typename;
246 return api;
247}
248
249
250/**
251 * Exit point from the plugin.
252 *
253 * @param cls the return value from #libgnunet_plugin_block_test_init
254 * @return NULL
255 */
256void *
257libgnunet_plugin_gnsrecord_reclaim_done (void *cls)
258{
259 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
260
261 GNUNET_free (api);
262 return NULL;
263}
264
265/* 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..abb3f59f5
--- /dev/null
+++ b/src/reclaim/plugin_rest_openid_connect.c
@@ -0,0 +1,2227 @@
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 "jwt.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 "max_age",
172 "ui_locales",
173 "response_mode",
174 "id_token_hint",
175 "login_hint",
176 "acr_values"
177};
178
179/**
180 * OIDC authorized identities and times hashmap
181 */
182struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
183
184/**
185 * OIDC authorized identities and times hashmap
186 */
187struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
188
189/**
190 * OIDC ticket/code use only once
191 */
192struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
193
194/**
195 * OIDC access_token to ticket and ego
196 */
197struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
198
199/**
200 * The configuration handle
201 */
202const struct GNUNET_CONFIGURATION_Handle *cfg;
203
204/**
205 * HTTP methods allows for this plugin
206 */
207static char* allow_methods;
208
209/**
210 * @brief struct returned by the initialization function of the plugin
211 */
212struct Plugin
213{
214 const struct GNUNET_CONFIGURATION_Handle *cfg;
215};
216
217/**
218 * OIDC needed variables
219 */
220struct OIDC_Variables
221{
222 /**
223 * The RP client public key
224 */
225 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
226
227 /**
228 * The OIDC client id of the RP
229 */
230 char *client_id;
231
232 /**
233 * GNUNET_YES if there is a delegation to
234 * this RP or if it is a local identity
235 */
236 int is_client_trusted;
237
238 /**
239 * The OIDC redirect uri
240 */
241 char *redirect_uri;
242
243 /**
244 * The list of oidc scopes
245 */
246 char *scope;
247
248 /**
249 * The OIDC state
250 */
251 char *state;
252
253 /**
254 * The OIDC nonce
255 */
256 char *nonce;
257
258 /**
259 * The OIDC response type
260 */
261 char *response_type;
262
263 /**
264 * The identity chosen by the user to login
265 */
266 char *login_identity;
267
268 /**
269 * The response JSON
270 */
271 json_t *response;
272
273};
274
275/**
276 * The ego list
277 */
278struct EgoEntry
279{
280 /**
281 * DLL
282 */
283 struct EgoEntry *next;
284
285 /**
286 * DLL
287 */
288 struct EgoEntry *prev;
289
290 /**
291 * Ego Identifier
292 */
293 char *identifier;
294
295 /**
296 * Public key string
297 */
298 char *keystring;
299
300 /**
301 * The Ego
302 */
303 struct GNUNET_IDENTITY_Ego *ego;
304};
305
306
307struct RequestHandle
308{
309 /**
310 * Ego list
311 */
312 struct EgoEntry *ego_head;
313
314 /**
315 * Ego list
316 */
317 struct EgoEntry *ego_tail;
318
319 /**
320 * Selected ego
321 */
322 struct EgoEntry *ego_entry;
323
324 /**
325 * Pointer to ego private key
326 */
327 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
328
329 /**
330 * OIDC variables
331 */
332 struct OIDC_Variables *oidc;
333
334 /**
335 * The processing state
336 */
337 int state;
338
339 /**
340 * Handle to Identity service.
341 */
342 struct GNUNET_IDENTITY_Handle *identity_handle;
343
344 /**
345 * Rest connection
346 */
347 struct GNUNET_REST_RequestHandle *rest_handle;
348
349 /**
350 * Handle to NAMESTORE
351 */
352 struct GNUNET_NAMESTORE_Handle *namestore_handle;
353
354 /**
355 * Iterator for NAMESTORE
356 */
357 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
358
359 /**
360 * Attribute claim list
361 */
362 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
363
364 /**
365 * IDENTITY Operation
366 */
367 struct GNUNET_IDENTITY_Operation *op;
368
369 /**
370 * Identity Provider
371 */
372 struct GNUNET_RECLAIM_Handle *idp;
373
374 /**
375 * Idp Operation
376 */
377 struct GNUNET_RECLAIM_Operation *idp_op;
378
379 /**
380 * Attribute iterator
381 */
382 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
383
384 /**
385 * Ticket iterator
386 */
387 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
388
389 /**
390 * A ticket
391 */
392 struct GNUNET_RECLAIM_Ticket ticket;
393
394 /**
395 * Desired timeout for the lookup (default is no timeout).
396 */
397 struct GNUNET_TIME_Relative timeout;
398
399 /**
400 * ID of a task associated with the resolution process.
401 */
402 struct GNUNET_SCHEDULER_Task *timeout_task;
403
404 /**
405 * The plugin result processor
406 */
407 GNUNET_REST_ResultProcessor proc;
408
409 /**
410 * The closure of the result processor
411 */
412 void *proc_cls;
413
414 /**
415 * The url
416 */
417 char *url;
418
419 /**
420 * The tld for redirect
421 */
422 char *tld;
423
424 /**
425 * Error response message
426 */
427 char *emsg;
428
429 /**
430 * Error response description
431 */
432 char *edesc;
433
434 /**
435 * Reponse code
436 */
437 int response_code;
438
439 /**
440 * Response object
441 */
442 struct GNUNET_JSONAPI_Document *resp_object;
443
444};
445
446/**
447 * Cleanup lookup handle
448 * @param handle Handle to clean up
449 */
450static void
451cleanup_handle (struct RequestHandle *handle)
452{
453 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
454 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
455 struct EgoEntry *ego_entry;
456 struct EgoEntry *ego_tmp;
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Cleaning up\n");
459 if (NULL != handle->resp_object)
460 GNUNET_JSONAPI_document_delete (handle->resp_object);
461 if (NULL != handle->timeout_task)
462 GNUNET_SCHEDULER_cancel (handle->timeout_task);
463 if (NULL != handle->identity_handle)
464 GNUNET_IDENTITY_disconnect (handle->identity_handle);
465 if (NULL != handle->attr_it)
466 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
467 if (NULL != handle->ticket_it)
468 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
469 if (NULL != handle->idp)
470 GNUNET_RECLAIM_disconnect (handle->idp);
471 if (NULL != handle->url)
472 GNUNET_free (handle->url);
473 if (NULL != handle->tld)
474 GNUNET_free (handle->tld);
475 if (NULL != handle->emsg)
476 GNUNET_free (handle->emsg);
477 if (NULL != handle->edesc)
478 GNUNET_free (handle->edesc);
479 if (NULL != handle->namestore_handle)
480 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
481 if (NULL != handle->oidc)
482 {
483 if (NULL != handle->oidc->client_id)
484 GNUNET_free(handle->oidc->client_id);
485 if (NULL != handle->oidc->login_identity)
486 GNUNET_free(handle->oidc->login_identity);
487 if (NULL != handle->oidc->nonce)
488 GNUNET_free(handle->oidc->nonce);
489 if (NULL != handle->oidc->redirect_uri)
490 GNUNET_free(handle->oidc->redirect_uri);
491 if (NULL != handle->oidc->response_type)
492 GNUNET_free(handle->oidc->response_type);
493 if (NULL != handle->oidc->scope)
494 GNUNET_free(handle->oidc->scope);
495 if (NULL != handle->oidc->state)
496 GNUNET_free(handle->oidc->state);
497 if (NULL != handle->oidc->response)
498 json_decref(handle->oidc->response);
499 GNUNET_free(handle->oidc);
500 }
501 if ( NULL != handle->attr_list )
502 {
503 for (claim_entry = handle->attr_list->list_head;
504 NULL != claim_entry;)
505 {
506 claim_tmp = claim_entry;
507 claim_entry = claim_entry->next;
508 GNUNET_free(claim_tmp->claim);
509 GNUNET_free(claim_tmp);
510 }
511 GNUNET_free (handle->attr_list);
512 }
513 for (ego_entry = handle->ego_head;
514 NULL != ego_entry;)
515 {
516 ego_tmp = ego_entry;
517 ego_entry = ego_entry->next;
518 GNUNET_free (ego_tmp->identifier);
519 GNUNET_free (ego_tmp->keystring);
520 GNUNET_free (ego_tmp);
521 }
522 if (NULL != handle->attr_it)
523 {
524 GNUNET_free(handle->attr_it);
525 }
526 GNUNET_free (handle);
527}
528
529static void
530cleanup_handle_delayed (void *cls)
531{
532 cleanup_handle (cls);
533}
534
535
536/**
537 * Task run on error, sends error message. Cleans up everything.
538 *
539 * @param cls the `struct RequestHandle`
540 */
541static void
542do_error (void *cls)
543{
544 struct RequestHandle *handle = cls;
545 struct MHD_Response *resp;
546 char *json_error;
547
548 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
549 handle->emsg,
550 (NULL != handle->edesc) ? handle->edesc : "",
551 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
552 (NULL != handle->oidc->state) ? handle->oidc->state : "",
553 (NULL != handle->oidc->state) ? "\"" : "");
554 if ( 0 == handle->response_code )
555 {
556 handle->response_code = MHD_HTTP_BAD_REQUEST;
557 }
558 resp = GNUNET_REST_create_response (json_error);
559 if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
560 {
561 MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
562 }
563 MHD_add_response_header (resp, "Content-Type", "application/json");
564 handle->proc (handle->proc_cls, resp, handle->response_code);
565 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
566 GNUNET_free (json_error);
567}
568
569
570/**
571 * Task run on error in userinfo endpoint, sends error header. Cleans up
572 * everything
573 *
574 * @param cls the `struct RequestHandle`
575 */
576static void
577do_userinfo_error (void *cls)
578{
579 struct RequestHandle *handle = cls;
580 struct MHD_Response *resp;
581 char *error;
582
583 GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
584 handle->emsg,
585 (NULL != handle->edesc) ? handle->edesc : "");
586 resp = GNUNET_REST_create_response ("");
587 MHD_add_response_header(resp, "WWW-Authenticate", error);
588 handle->proc (handle->proc_cls, resp, handle->response_code);
589 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
590 GNUNET_free (error);
591}
592
593
594/**
595 * Task run on error, sends error message and redirects. Cleans up everything.
596 *
597 * @param cls the `struct RequestHandle`
598 */
599static void
600do_redirect_error (void *cls)
601{
602 struct RequestHandle *handle = cls;
603 struct MHD_Response *resp;
604 char* redirect;
605 GNUNET_asprintf (&redirect,
606 "%s?error=%s&error_description=%s%s%s",
607 handle->oidc->redirect_uri, handle->emsg, handle->edesc,
608 (NULL != handle->oidc->state) ? "&state=" : "",
609 (NULL != handle->oidc->state) ? handle->oidc->state : "");
610 resp = GNUNET_REST_create_response ("");
611 MHD_add_response_header (resp, "Location", redirect);
612 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
613 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
614 GNUNET_free (redirect);
615}
616
617/**
618 * Task run on timeout, sends error message. Cleans up everything.
619 *
620 * @param cls the `struct RequestHandle`
621 */
622static void
623do_timeout (void *cls)
624{
625 struct RequestHandle *handle = cls;
626
627 handle->timeout_task = NULL;
628 do_error (handle);
629}
630
631/**
632 * Return attributes for claim
633 *
634 * @param cls the request handle
635 */
636static void
637return_userinfo_response (void *cls)
638{
639 char* result_str;
640 struct RequestHandle *handle = cls;
641 struct MHD_Response *resp;
642
643 result_str = json_dumps (handle->oidc->response, 0);
644
645 resp = GNUNET_REST_create_response (result_str);
646 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
647 GNUNET_free (result_str);
648 cleanup_handle (handle);
649}
650
651/**
652 * Returns base64 encoded string without padding
653 *
654 * @param string the string to encode
655 * @return base64 encoded string
656 */
657static char*
658base_64_encode(const char *s)
659{
660 char *enc;
661 char *tmp;
662
663 GNUNET_STRINGS_base64_encode(s, strlen(s), &enc);
664 tmp = strrchr (enc, '=');
665 *tmp = '\0';
666 return enc;
667}
668
669/**
670 * Respond to OPTIONS request
671 *
672 * @param con_handle the connection handle
673 * @param url the url
674 * @param cls the RequestHandle
675 */
676static void
677options_cont (struct GNUNET_REST_RequestHandle *con_handle,
678 const char* url,
679 void *cls)
680{
681 struct MHD_Response *resp;
682 struct RequestHandle *handle = cls;
683
684 //For now, independent of path return all options
685 resp = GNUNET_REST_create_response (NULL);
686 MHD_add_response_header (resp,
687 "Access-Control-Allow-Methods",
688 allow_methods);
689 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
690 cleanup_handle (handle);
691 return;
692}
693
694/**
695 * Interprets cookie header and pass its identity keystring to handle
696 */
697static void
698cookie_identity_interpretation (struct RequestHandle *handle)
699{
700 struct GNUNET_HashCode cache_key;
701 char *cookies;
702 struct GNUNET_TIME_Absolute current_time, *relog_time;
703 char delimiter[] = "; ";
704
705 //gets identity of login try with cookie
706 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
707 &cache_key);
708 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
709 &cache_key) )
710 {
711 //splits cookies and find 'Identity' cookie
712 cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
713 handle->oidc->login_identity = strtok(cookies, delimiter);
714
715 while ( NULL != handle->oidc->login_identity )
716 {
717 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
718 {
719 break;
720 }
721 handle->oidc->login_identity = strtok (NULL, delimiter);
722 }
723 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
724 &cache_key);
725 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
726 {
727 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
728 &cache_key);
729 current_time = GNUNET_TIME_absolute_get ();
730 // 30 min after old login -> redirect to login
731 if ( current_time.abs_value_us <= relog_time->abs_value_us )
732 {
733 handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
734 handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
735 } else {
736 handle->oidc->login_identity = NULL;
737 }
738 }
739 else
740 {
741 handle->oidc->login_identity = NULL;
742 }
743 }
744}
745
746/**
747 * Redirects to login page stored in configuration file
748 */
749static void
750login_redirection(void *cls)
751{
752 char *login_base_url;
753 char *new_redirect;
754 struct MHD_Response *resp;
755 struct RequestHandle *handle = cls;
756
757 if ( GNUNET_OK
758 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
759 "address", &login_base_url) )
760 {
761 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
762 login_base_url,
763 OIDC_RESPONSE_TYPE_KEY,
764 handle->oidc->response_type,
765 OIDC_CLIENT_ID_KEY,
766 handle->oidc->client_id,
767 OIDC_REDIRECT_URI_KEY,
768 handle->oidc->redirect_uri,
769 OIDC_SCOPE_KEY,
770 handle->oidc->scope,
771 OIDC_STATE_KEY,
772 (NULL != handle->oidc->state) ? handle->oidc->state : "",
773 OIDC_NONCE_KEY,
774 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
775 resp = GNUNET_REST_create_response ("");
776 MHD_add_response_header (resp, "Location", new_redirect);
777 GNUNET_free(login_base_url);
778 }
779 else
780 {
781 handle->emsg = GNUNET_strdup("server_error");
782 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
783 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
784 GNUNET_SCHEDULER_add_now (&do_error, handle);
785 return;
786 }
787 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
788 GNUNET_free(new_redirect);
789 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
790}
791
792/**
793 * Does internal server error when iteration failed.
794 */
795static void
796oidc_iteration_error (void *cls)
797{
798 struct RequestHandle *handle = cls;
799 handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
800 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
801 GNUNET_SCHEDULER_add_now (&do_error, handle);
802}
803
804static void get_client_name_result (void *cls,
805 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
806 const char *label,
807 unsigned int rd_count,
808 const struct GNUNET_GNSRECORD_Data *rd)
809{
810 struct RequestHandle *handle = cls;
811 struct MHD_Response *resp;
812 char *ticket_str;
813 char *redirect_uri;
814 char *code_json_string;
815 char *code_base64_final_string;
816 char *redirect_path;
817 char *tmp;
818 char *tmp_prefix;
819 char *prefix;
820 ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
821 sizeof (struct GNUNET_RECLAIM_Ticket));
822 //TODO change if more attributes are needed (see max_age)
823 GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
824 ticket_str,
825 (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
826 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
827 (NULL != handle->oidc->nonce) ? "\"" : "");
828 code_base64_final_string = base_64_encode(code_json_string);
829 tmp = GNUNET_strdup (handle->oidc->redirect_uri);
830 redirect_path = strtok (tmp, "/");
831 redirect_path = strtok (NULL, "/");
832 redirect_path = strtok (NULL, "/");
833 tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri);
834 prefix = strrchr (tmp_prefix,
835 (unsigned char) '.');
836 *prefix = '\0';
837 GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
838 tmp_prefix,
839 handle->tld,
840 redirect_path,
841 handle->oidc->response_type,
842 code_base64_final_string, handle->oidc->state);
843 resp = GNUNET_REST_create_response ("");
844 MHD_add_response_header (resp, "Location", redirect_uri);
845 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
846 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
847 GNUNET_free (tmp);
848 GNUNET_free (tmp_prefix);
849 GNUNET_free (redirect_uri);
850 GNUNET_free (ticket_str);
851 GNUNET_free (code_json_string);
852 GNUNET_free (code_base64_final_string);
853 return;
854}
855
856static void
857get_client_name_error (void *cls)
858{
859 struct RequestHandle *handle = cls;
860
861 handle->emsg = GNUNET_strdup("server_error");
862 handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client.");
863 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
864}
865
866/**
867 * Issues ticket and redirects to relying party with the authorization code as
868 * parameter. Otherwise redirects with error
869 */
870static void
871oidc_ticket_issue_cb (void* cls,
872 const struct GNUNET_RECLAIM_Ticket *ticket)
873{
874 struct RequestHandle *handle = cls;
875 handle->idp_op = NULL;
876 handle->ticket = *ticket;
877 if (NULL != ticket) {
878 GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle,
879 &handle->priv_key,
880 &handle->oidc->client_pkey,
881 &get_client_name_error,
882 handle,
883 &get_client_name_result,
884 handle);
885 return;
886 }
887 handle->emsg = GNUNET_strdup("server_error");
888 handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
889 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
890}
891
892static void
893oidc_collect_finished_cb (void *cls)
894{
895 struct RequestHandle *handle = cls;
896 handle->attr_it = NULL;
897 handle->ticket_it = NULL;
898 if (NULL == handle->attr_list->list_head)
899 {
900 handle->emsg = GNUNET_strdup("invalid_scope");
901 handle->edesc = GNUNET_strdup("The requested scope is not available.");
902 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
903 return;
904 }
905 handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
906 &handle->priv_key,
907 &handle->oidc->client_pkey,
908 handle->attr_list,
909 &oidc_ticket_issue_cb,
910 handle);
911}
912
913
914/**
915 * Collects all attributes for an ego if in scope parameter
916 */
917static void
918oidc_attr_collect (void *cls,
919 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
920 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
921{
922 struct RequestHandle *handle = cls;
923 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
924 char* scope_variables;
925 char* scope_variable;
926 char delimiter[]=" ";
927
928 if ( (NULL == attr->name) || (NULL == attr->data) )
929 {
930 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
931 return;
932 }
933
934 scope_variables = GNUNET_strdup(handle->oidc->scope);
935 scope_variable = strtok (scope_variables, delimiter);
936 while (NULL != scope_variable)
937 {
938 if ( 0 == strcmp (attr->name, scope_variable) )
939 {
940 break;
941 }
942 scope_variable = strtok (NULL, delimiter);
943 }
944 if ( NULL == scope_variable )
945 {
946 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
947 GNUNET_free(scope_variables);
948 return;
949 }
950 GNUNET_free(scope_variables);
951
952 le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
953 le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type,
954 attr->data, attr->data_size);
955 GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
956 handle->attr_list->list_tail, le);
957 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
958}
959
960
961/**
962 * Checks time and cookie and redirects accordingly
963 */
964static void
965login_check (void *cls)
966{
967 struct RequestHandle *handle = cls;
968 struct GNUNET_TIME_Absolute current_time, *relog_time;
969 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
970 struct GNUNET_HashCode cache_key;
971 char *identity_cookie;
972
973 GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
974 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
975 GNUNET_free(identity_cookie);
976 //No login time for identity -> redirect to login
977 if ( GNUNET_YES
978 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
979 &cache_key) )
980 {
981 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
982 &cache_key);
983 current_time = GNUNET_TIME_absolute_get ();
984 // 30 min after old login -> redirect to login
985 if ( current_time.abs_value_us <= relog_time->abs_value_us )
986 {
987 if ( GNUNET_OK
988 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
989 handle->oidc->login_identity,
990 strlen (handle->oidc->login_identity), &pubkey) )
991 {
992 handle->emsg = GNUNET_strdup("invalid_cookie");
993 handle->edesc = GNUNET_strdup(
994 "The cookie of a login identity is not valid");
995 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
996 return;
997 }
998 // iterate over egos and compare their public key
999 for (handle->ego_entry = handle->ego_head;
1000 NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1001 {
1002 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1003 if ( 0
1004 == memcmp (&ego_pkey, &pubkey,
1005 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1006 {
1007 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1008 handle->ego_entry->ego);
1009 handle->resp_object = GNUNET_JSONAPI_document_new ();
1010 handle->idp = GNUNET_RECLAIM_connect (cfg);
1011 handle->attr_list = GNUNET_new(
1012 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1013 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
1014 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1015 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1016 return;
1017 }
1018 }
1019 //handle->emsg = GNUNET_strdup("invalid_cookie");
1020 //handle->edesc = GNUNET_strdup(
1021 // "The cookie of the login identity is not valid");
1022 //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1023 GNUNET_SCHEDULER_add_now (&login_redirection,handle);
1024 return;
1025 }
1026 }
1027}
1028
1029/**
1030 * Searches for client_id in namestore. If found trust status stored in handle
1031 * Else continues to search
1032 *
1033 * @param handle the RequestHandle
1034 */
1035static void
1036namestore_iteration_callback (
1037 void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1038 const char *rname, unsigned int rd_len,
1039 const struct GNUNET_GNSRECORD_Data *rd)
1040{
1041 struct RequestHandle *handle = cls;
1042 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1043 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1044 int i;
1045
1046 for (i = 0; i < rd_len; i++)
1047 {
1048 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1049 continue;
1050
1051 if ( NULL != handle->oidc->login_identity )
1052 {
1053 GNUNET_CRYPTO_ecdsa_public_key_from_string (
1054 handle->oidc->login_identity,
1055 strlen (handle->oidc->login_identity),
1056 &login_identity_pkey);
1057 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1058 &current_zone_pkey);
1059
1060 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1061 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1062 {
1063 if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
1064 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1065 {
1066 handle->oidc->is_client_trusted = GNUNET_YES;
1067 }
1068 }
1069 }
1070 else
1071 {
1072 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1073 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1074 {
1075 handle->oidc->is_client_trusted = GNUNET_YES;
1076 }
1077 }
1078 }
1079
1080 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it,
1081 1);
1082}
1083
1084
1085/**
1086 * Iteration over all results finished, build final
1087 * response.
1088 *
1089 * @param cls the `struct RequestHandle`
1090 */
1091static void
1092namestore_iteration_finished (void *cls)
1093{
1094 struct RequestHandle *handle = cls;
1095 struct GNUNET_HashCode cache_key;
1096
1097 char *expected_scope;
1098 char delimiter[]=" ";
1099 int number_of_ignored_parameter, iterator;
1100
1101
1102 handle->ego_entry = handle->ego_entry->next;
1103
1104 if(NULL != handle->ego_entry)
1105 {
1106 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1107 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1108 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1109 &namestore_iteration_finished, handle);
1110 return;
1111 }
1112 if (GNUNET_NO == handle->oidc->is_client_trusted)
1113 {
1114 handle->emsg = GNUNET_strdup("unauthorized_client");
1115 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1116 "authorization code using this method.");
1117 GNUNET_SCHEDULER_add_now (&do_error, handle);
1118 return;
1119 }
1120
1121 // REQUIRED value: redirect_uri
1122 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1123 &cache_key);
1124 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1125 &cache_key))
1126 {
1127 handle->emsg=GNUNET_strdup("invalid_request");
1128 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1129 GNUNET_SCHEDULER_add_now (&do_error, handle);
1130 return;
1131 }
1132 handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1133 &cache_key));
1134
1135 // REQUIRED value: response_type
1136 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1137 &cache_key);
1138 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1139 &cache_key))
1140 {
1141 handle->emsg=GNUNET_strdup("invalid_request");
1142 handle->edesc=GNUNET_strdup("missing parameter response_type");
1143 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1144 return;
1145 }
1146 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1147 &cache_key);
1148 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1149
1150 // REQUIRED value: scope
1151 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1152 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1153 &cache_key))
1154 {
1155 handle->emsg=GNUNET_strdup("invalid_request");
1156 handle->edesc=GNUNET_strdup("missing parameter scope");
1157 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1158 return;
1159 }
1160 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1161 &cache_key);
1162 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1163
1164 //OPTIONAL value: nonce
1165 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1166 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1167 &cache_key))
1168 {
1169 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1170 &cache_key);
1171 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1172 }
1173
1174 //TODO check other values if needed
1175 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1176 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1177 {
1178 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1179 strlen(OIDC_ignored_parameter_array[iterator]),
1180 &cache_key);
1181 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1182 &cache_key))
1183 {
1184 handle->emsg=GNUNET_strdup("access_denied");
1185 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1186 OIDC_ignored_parameter_array[iterator]);
1187 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1188 return;
1189 }
1190 }
1191
1192 // Checks if response_type is 'code'
1193 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1194 {
1195 handle->emsg=GNUNET_strdup("unsupported_response_type");
1196 handle->edesc=GNUNET_strdup("The authorization server does not support "
1197 "obtaining this authorization code.");
1198 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1199 return;
1200 }
1201
1202 // Checks if scope contains 'openid'
1203 expected_scope = GNUNET_strdup(handle->oidc->scope);
1204 char* test;
1205 test = strtok (expected_scope, delimiter);
1206 while (NULL != test)
1207 {
1208 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1209 {
1210 break;
1211 }
1212 test = strtok (NULL, delimiter);
1213 }
1214 if (NULL == test)
1215 {
1216 handle->emsg = GNUNET_strdup("invalid_scope");
1217 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1218 "malformed.");
1219 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1220 GNUNET_free(expected_scope);
1221 return;
1222 }
1223
1224 GNUNET_free(expected_scope);
1225
1226 if( NULL != handle->oidc->login_identity )
1227 {
1228 GNUNET_SCHEDULER_add_now(&login_check,handle);
1229 return;
1230 }
1231
1232 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1233}
1234
1235/**
1236 * Responds to authorization GET and url-encoded POST request
1237 *
1238 * @param con_handle the connection handle
1239 * @param url the url
1240 * @param cls the RequestHandle
1241 */
1242static void
1243authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1244 const char* url,
1245 void *cls)
1246{
1247 struct RequestHandle *handle = cls;
1248 struct GNUNET_HashCode cache_key;
1249 struct EgoEntry *tmp_ego;
1250 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1251 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1252
1253 cookie_identity_interpretation(handle);
1254
1255 //RECOMMENDED value: state - REQUIRED for answers
1256 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1257 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1258 &cache_key))
1259 {
1260 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1261 &cache_key);
1262 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1263 }
1264
1265 // REQUIRED value: client_id
1266 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1267 &cache_key);
1268 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1269 &cache_key))
1270 {
1271 handle->emsg=GNUNET_strdup("invalid_request");
1272 handle->edesc=GNUNET_strdup("missing parameter client_id");
1273 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1274 GNUNET_SCHEDULER_add_now (&do_error, handle);
1275 return;
1276 }
1277 handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1278 &cache_key));
1279
1280 if ( GNUNET_OK
1281 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1282 strlen (handle->oidc->client_id),
1283 &handle->oidc->client_pkey) )
1284 {
1285 handle->emsg = GNUNET_strdup("unauthorized_client");
1286 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1287 "authorization code using this method.");
1288 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1289 GNUNET_SCHEDULER_add_now (&do_error, handle);
1290 return;
1291 }
1292
1293
1294 if ( NULL == handle->ego_head )
1295 {
1296 handle->emsg = GNUNET_strdup("server_error");
1297 handle->edesc = GNUNET_strdup ("Egos are missing");
1298 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1299 GNUNET_SCHEDULER_add_now (&do_error, handle);
1300 return;
1301 }
1302
1303 handle->ego_entry = handle->ego_head;
1304 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1305 handle->oidc->is_client_trusted = GNUNET_NO;
1306
1307 //First check if client_id is one of our egos; TODO: handle other TLD cases: Delegation, from config
1308 for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1309 {
1310 priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1311 GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
1312 &pkey);
1313 if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey,
1314 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1315 {
1316 handle->tld = GNUNET_strdup (tmp_ego->identifier);
1317 handle->oidc->is_client_trusted = GNUNET_YES;
1318 handle->ego_entry = handle->ego_tail;
1319 }
1320 }
1321
1322
1323 // Checks if client_id is valid:
1324 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1325 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1326 handle, &namestore_iteration_callback, handle,
1327 &namestore_iteration_finished, handle);
1328}
1329
1330/**
1331 * Combines an identity with a login time and responds OK to login request
1332 *
1333 * @param con_handle the connection handle
1334 * @param url the url
1335 * @param cls the RequestHandle
1336 */
1337static void
1338login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1339 const char* url,
1340 void *cls)
1341{
1342 struct MHD_Response *resp = GNUNET_REST_create_response ("");
1343 struct RequestHandle *handle = cls;
1344 struct GNUNET_HashCode cache_key;
1345 struct GNUNET_TIME_Absolute *current_time;
1346 struct GNUNET_TIME_Absolute *last_time;
1347 char* cookie;
1348 json_t *root;
1349 json_error_t error;
1350 json_t *identity;
1351 char term_data[handle->rest_handle->data_size+1];
1352 term_data[handle->rest_handle->data_size] = '\0';
1353 GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size);
1354 root = json_loads (term_data, JSON_DECODE_ANY, &error);
1355 identity = json_object_get (root, "identity");
1356 if ( json_is_string(identity) )
1357 {
1358 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1359 MHD_add_response_header (resp, "Set-Cookie", cookie);
1360 MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1361 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1362
1363 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1364 *current_time = GNUNET_TIME_relative_to_absolute (
1365 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
1366 5));
1367 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1368 if (NULL != last_time)
1369 {
1370 GNUNET_free(last_time);
1371 }
1372 GNUNET_CONTAINER_multihashmap_put (
1373 OIDC_identity_login_time, &cache_key, current_time,
1374 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1375
1376 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1377 GNUNET_free(cookie);
1378 }
1379 else
1380 {
1381 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1382 }
1383 json_decref (root);
1384 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1385 return;
1386}
1387
1388/**
1389 * Responds to token url-encoded POST request
1390 *
1391 * @param con_handle the connection handle
1392 * @param url the url
1393 * @param cls the RequestHandle
1394 */
1395static void
1396token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1397 const char* url,
1398 void *cls)
1399{
1400 //TODO static strings
1401 struct RequestHandle *handle = cls;
1402 struct GNUNET_HashCode cache_key;
1403 char *authorization, *credentials;
1404 char delimiter[]=" ";
1405 char delimiter_user_psw[]=":";
1406 char *grant_type, *code;
1407 char *user_psw = NULL, *client_id, *psw;
1408 char *expected_psw;
1409 int client_exists = GNUNET_NO;
1410 struct MHD_Response *resp;
1411 char* code_output;
1412 json_t *root, *ticket_string, *nonce, *max_age;
1413 json_error_t error;
1414 char *json_response;
1415 char *jwt_secret;
1416
1417 /*
1418 * Check Authorization
1419 */
1420 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1421 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1422 &cache_key);
1423 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1424 &cache_key) )
1425 {
1426 handle->emsg=GNUNET_strdup("invalid_client");
1427 handle->edesc=GNUNET_strdup("missing authorization");
1428 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1429 GNUNET_SCHEDULER_add_now (&do_error, handle);
1430 return;
1431 }
1432 authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1433
1434 //split header in "Basic" and [content]
1435 credentials = strtok (authorization, delimiter);
1436 if (0 != strcmp ("Basic",credentials))
1437 {
1438 handle->emsg=GNUNET_strdup("invalid_client");
1439 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1440 GNUNET_SCHEDULER_add_now (&do_error, handle);
1441 return;
1442 }
1443 credentials = strtok(NULL, delimiter);
1444 if (NULL == credentials)
1445 {
1446 handle->emsg=GNUNET_strdup("invalid_client");
1447 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1448 GNUNET_SCHEDULER_add_now (&do_error, handle);
1449 return;
1450 }
1451 GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw);
1452
1453 if ( NULL == user_psw )
1454 {
1455 handle->emsg=GNUNET_strdup("invalid_client");
1456 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1457 GNUNET_SCHEDULER_add_now (&do_error, handle);
1458 return;
1459 }
1460 client_id = strtok (user_psw, delimiter_user_psw);
1461 if ( NULL == client_id )
1462 {
1463 GNUNET_free_non_null(user_psw);
1464 handle->emsg=GNUNET_strdup("invalid_client");
1465 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1466 GNUNET_SCHEDULER_add_now (&do_error, handle);
1467 return;
1468 }
1469 psw = strtok (NULL, delimiter_user_psw);
1470 if (NULL == psw)
1471 {
1472 GNUNET_free_non_null(user_psw);
1473 handle->emsg=GNUNET_strdup("invalid_client");
1474 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1475 GNUNET_SCHEDULER_add_now (&do_error, handle);
1476 return;
1477 }
1478
1479 //check client password
1480 if ( GNUNET_OK
1481 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1482 "psw", &expected_psw) )
1483 {
1484 if (0 != strcmp (expected_psw, psw))
1485 {
1486 GNUNET_free_non_null(user_psw);
1487 GNUNET_free(expected_psw);
1488 handle->emsg=GNUNET_strdup("invalid_client");
1489 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1490 GNUNET_SCHEDULER_add_now (&do_error, handle);
1491 return;
1492 }
1493 GNUNET_free(expected_psw);
1494 }
1495 else
1496 {
1497 GNUNET_free_non_null(user_psw);
1498 handle->emsg = GNUNET_strdup("server_error");
1499 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1500 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1501 GNUNET_SCHEDULER_add_now (&do_error, handle);
1502 return;
1503 }
1504
1505 //check client_id
1506 for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
1507 {
1508 if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
1509 {
1510 client_exists = GNUNET_YES;
1511 break;
1512 }
1513 handle->ego_entry = handle->ego_entry->next;
1514 }
1515 if (GNUNET_NO == client_exists)
1516 {
1517 GNUNET_free_non_null(user_psw);
1518 handle->emsg=GNUNET_strdup("invalid_client");
1519 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1520 GNUNET_SCHEDULER_add_now (&do_error, handle);
1521 return;
1522 }
1523
1524 /*
1525 * Check parameter
1526 */
1527
1528 //TODO Do not allow multiple equal parameter names
1529 //REQUIRED grant_type
1530 GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
1531 if ( GNUNET_NO
1532 == GNUNET_CONTAINER_multihashmap_contains (
1533 handle->rest_handle->url_param_map, &cache_key) )
1534 {
1535 GNUNET_free_non_null(user_psw);
1536 handle->emsg = GNUNET_strdup("invalid_request");
1537 handle->edesc = GNUNET_strdup("missing parameter grant_type");
1538 handle->response_code = MHD_HTTP_BAD_REQUEST;
1539 GNUNET_SCHEDULER_add_now (&do_error, handle);
1540 return;
1541 }
1542 grant_type = GNUNET_CONTAINER_multihashmap_get (
1543 handle->rest_handle->url_param_map, &cache_key);
1544
1545 //REQUIRED code
1546 GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
1547 if ( GNUNET_NO
1548 == GNUNET_CONTAINER_multihashmap_contains (
1549 handle->rest_handle->url_param_map, &cache_key) )
1550 {
1551 GNUNET_free_non_null(user_psw);
1552 handle->emsg = GNUNET_strdup("invalid_request");
1553 handle->edesc = GNUNET_strdup("missing parameter code");
1554 handle->response_code = MHD_HTTP_BAD_REQUEST;
1555 GNUNET_SCHEDULER_add_now (&do_error, handle);
1556 return;
1557 }
1558 code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1559 &cache_key);
1560
1561 //REQUIRED redirect_uri
1562 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1563 &cache_key);
1564 if ( GNUNET_NO
1565 == GNUNET_CONTAINER_multihashmap_contains (
1566 handle->rest_handle->url_param_map, &cache_key) )
1567 {
1568 GNUNET_free_non_null(user_psw);
1569 handle->emsg = GNUNET_strdup("invalid_request");
1570 handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
1571 handle->response_code = MHD_HTTP_BAD_REQUEST;
1572 GNUNET_SCHEDULER_add_now (&do_error, handle);
1573 return;
1574 }
1575
1576 //Check parameter grant_type == "authorization_code"
1577 if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
1578 {
1579 GNUNET_free_non_null(user_psw);
1580 handle->emsg=GNUNET_strdup("unsupported_grant_type");
1581 handle->response_code = MHD_HTTP_BAD_REQUEST;
1582 GNUNET_SCHEDULER_add_now (&do_error, handle);
1583 return;
1584 }
1585 GNUNET_CRYPTO_hash (code, strlen (code), &cache_key);
1586 int i = 1;
1587 if ( GNUNET_SYSERR
1588 == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once,
1589 &cache_key,
1590 &i,
1591 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) )
1592 {
1593 GNUNET_free_non_null(user_psw);
1594 handle->emsg = GNUNET_strdup("invalid_request");
1595 handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
1596 handle->response_code = MHD_HTTP_BAD_REQUEST;
1597 GNUNET_SCHEDULER_add_now (&do_error, handle);
1598 return;
1599 }
1600
1601 //decode code
1602 GNUNET_STRINGS_base64_decode(code,strlen(code), (void**)&code_output);
1603 root = json_loads (code_output, 0, &error);
1604 GNUNET_free(code_output);
1605 ticket_string = json_object_get (root, "ticket");
1606 nonce = json_object_get (root, "nonce");
1607 max_age = json_object_get (root, "max_age");
1608
1609 if(ticket_string == NULL && !json_is_string(ticket_string))
1610 {
1611 GNUNET_free_non_null(user_psw);
1612 handle->emsg = GNUNET_strdup("invalid_request");
1613 handle->edesc = GNUNET_strdup("invalid code");
1614 handle->response_code = MHD_HTTP_BAD_REQUEST;
1615 GNUNET_SCHEDULER_add_now (&do_error, handle);
1616 return;
1617 }
1618
1619 struct GNUNET_RECLAIM_Ticket *ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
1620 if ( GNUNET_OK
1621 != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
1622 strlen (json_string_value(ticket_string)),
1623 ticket,
1624 sizeof(struct GNUNET_RECLAIM_Ticket)))
1625 {
1626 GNUNET_free_non_null(user_psw);
1627 handle->emsg = GNUNET_strdup("invalid_request");
1628 handle->edesc = GNUNET_strdup("invalid code");
1629 handle->response_code = MHD_HTTP_BAD_REQUEST;
1630 GNUNET_SCHEDULER_add_now (&do_error, handle);
1631 GNUNET_free(ticket);
1632 return;
1633 }
1634 // this is the current client (relying party)
1635 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1636 GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
1637 if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1638 {
1639 GNUNET_free_non_null(user_psw);
1640 handle->emsg = GNUNET_strdup("invalid_request");
1641 handle->edesc = GNUNET_strdup("invalid code");
1642 handle->response_code = MHD_HTTP_BAD_REQUEST;
1643 GNUNET_SCHEDULER_add_now (&do_error, handle);
1644 GNUNET_free(ticket);
1645 return;
1646 }
1647
1648 //create jwt
1649 unsigned long long int expiration_time;
1650 if ( GNUNET_OK
1651 != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin",
1652 "expiration_time", &expiration_time) )
1653 {
1654 GNUNET_free_non_null(user_psw);
1655 handle->emsg = GNUNET_strdup("server_error");
1656 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1657 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1658 GNUNET_SCHEDULER_add_now (&do_error, handle);
1659 GNUNET_free(ticket);
1660 return;
1661 }
1662
1663 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1664 //aud REQUIRED public key client_id must be there
1665 GNUNET_RECLAIM_ATTRIBUTE_list_add(cl,
1666 "aud",
1667 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
1668 client_id,
1669 strlen(client_id));
1670 //exp REQUIRED time expired from config
1671 struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute (
1672 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
1673 expiration_time));
1674 const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time);
1675 GNUNET_RECLAIM_ATTRIBUTE_list_add (cl,
1676 "exp",
1677 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
1678 exp_time_string,
1679 strlen(exp_time_string));
1680 //iat REQUIRED time now
1681 struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get();
1682 const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now);
1683 GNUNET_RECLAIM_ATTRIBUTE_list_add (cl,
1684 "iat",
1685 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
1686 time_now_string,
1687 strlen(time_now_string));
1688 //nonce only if nonce is provided
1689 if ( NULL != nonce && json_is_string(nonce) )
1690 {
1691 GNUNET_RECLAIM_ATTRIBUTE_list_add (cl,
1692 "nonce",
1693 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
1694 json_string_value(nonce),
1695 strlen(json_string_value(nonce)));
1696 }
1697 //auth_time only if max_age is provided
1698 if ( NULL != max_age && json_is_string(max_age) )
1699 {
1700 GNUNET_RECLAIM_ATTRIBUTE_list_add (cl,
1701 "auth_time",
1702 GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING,
1703 json_string_value(max_age),
1704 strlen(json_string_value(max_age)));
1705 }
1706 //TODO OPTIONAL acr,amr,azp
1707
1708 struct EgoEntry *ego_entry;
1709 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1710 {
1711 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1712 if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1713 {
1714 break;
1715 }
1716 }
1717 if ( NULL == ego_entry )
1718 {
1719 GNUNET_free_non_null(user_psw);
1720 handle->emsg = GNUNET_strdup("invalid_request");
1721 handle->edesc = GNUNET_strdup("invalid code...");
1722 handle->response_code = MHD_HTTP_BAD_REQUEST;
1723 GNUNET_SCHEDULER_add_now (&do_error, handle);
1724 GNUNET_free(ticket);
1725 return;
1726 }
1727 if ( GNUNET_OK
1728 != GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1729 "jwt_secret", &jwt_secret) )
1730 {
1731 GNUNET_free_non_null(user_psw);
1732 handle->emsg = GNUNET_strdup("invalid_request");
1733 handle->edesc = GNUNET_strdup("No signing secret configured!");
1734 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1735 GNUNET_SCHEDULER_add_now (&do_error, handle);
1736 GNUNET_free(ticket);
1737 return;
1738 }
1739 struct GNUNET_CRYPTO_AuthKey jwt_sign_key;
1740 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1741 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pk);
1742 GNUNET_CRYPTO_hash (jwt_secret, strlen (jwt_secret), (struct GNUNET_HashCode*)jwt_sign_key.key);
1743 char *id_token = jwt_create_from_list(&ticket->audience,
1744 &pk,
1745 cl,
1746 &jwt_sign_key);
1747
1748 //Create random access_token
1749 char* access_token_number;
1750 char* access_token;
1751 uint64_t random_number;
1752 random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
1753 GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
1754 GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
1755
1756
1757
1758 //TODO OPTIONAL add refresh_token and scope
1759 GNUNET_asprintf (&json_response,
1760 "{ \"access_token\" : \"%s\", "
1761 "\"token_type\" : \"Bearer\", "
1762 "\"expires_in\" : %d, "
1763 "\"id_token\" : \"%s\"}",
1764 access_token,
1765 expiration_time,
1766 id_token);
1767 GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
1768 char *id_ticket_combination;
1769 GNUNET_asprintf(&id_ticket_combination,
1770 "%s;%s",
1771 client_id,
1772 json_string_value(ticket_string));
1773 GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
1774 &cache_key,
1775 id_ticket_combination,
1776 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1777
1778 resp = GNUNET_REST_create_response (json_response);
1779 MHD_add_response_header (resp, "Cache-Control", "no-store");
1780 MHD_add_response_header (resp, "Pragma", "no-cache");
1781 MHD_add_response_header (resp, "Content-Type", "application/json");
1782 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1783
1784 GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl);
1785 GNUNET_free(access_token_number);
1786 GNUNET_free(access_token);
1787 GNUNET_free(user_psw);
1788 GNUNET_free(json_response);
1789 GNUNET_free(ticket);
1790 GNUNET_free(id_token);
1791 json_decref (root);
1792 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
1793}
1794
1795/**
1796 * Collects claims and stores them in handle
1797 */
1798static void
1799consume_ticket (void *cls,
1800 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1801 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1802{
1803 struct RequestHandle *handle = cls;
1804 char *tmp_value;
1805 json_t *value;
1806
1807 if (NULL == identity)
1808 {
1809 GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
1810 return;
1811 }
1812
1813 tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1814 attr->data,
1815 attr->data_size);
1816
1817 value = json_string (tmp_value);
1818
1819
1820 json_object_set_new (handle->oidc->response,
1821 attr->name,
1822 value);
1823 GNUNET_free (tmp_value);
1824}
1825
1826/**
1827 * Responds to userinfo GET and url-encoded POST request
1828 *
1829 * @param con_handle the connection handle
1830 * @param url the url
1831 * @param cls the RequestHandle
1832 */
1833static void
1834userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1835 const char* url, void *cls)
1836{
1837 //TODO expiration time
1838 struct RequestHandle *handle = cls;
1839 char delimiter[] = " ";
1840 char delimiter_db[] = ";";
1841 struct GNUNET_HashCode cache_key;
1842 char *authorization, *authorization_type, *authorization_access_token;
1843 char *client_ticket, *client, *ticket_str;
1844 struct GNUNET_RECLAIM_Ticket *ticket;
1845
1846 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1847 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1848 &cache_key);
1849 if ( GNUNET_NO
1850 == GNUNET_CONTAINER_multihashmap_contains (
1851 handle->rest_handle->header_param_map, &cache_key) )
1852 {
1853 handle->emsg = GNUNET_strdup("invalid_token");
1854 handle->edesc = GNUNET_strdup("No Access Token");
1855 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1856 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1857 return;
1858 }
1859 authorization = GNUNET_CONTAINER_multihashmap_get (
1860 handle->rest_handle->header_param_map, &cache_key);
1861
1862 //split header in "Bearer" and access_token
1863 authorization = GNUNET_strdup(authorization);
1864 authorization_type = strtok (authorization, delimiter);
1865 if ( 0 != strcmp ("Bearer", authorization_type) )
1866 {
1867 handle->emsg = GNUNET_strdup("invalid_token");
1868 handle->edesc = GNUNET_strdup("No Access Token");
1869 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1870 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1871 GNUNET_free(authorization);
1872 return;
1873 }
1874 authorization_access_token = strtok (NULL, delimiter);
1875 if ( NULL == authorization_access_token )
1876 {
1877 handle->emsg = GNUNET_strdup("invalid_token");
1878 handle->edesc = GNUNET_strdup("No Access Token");
1879 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1880 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1881 GNUNET_free(authorization);
1882 return;
1883 }
1884
1885 GNUNET_CRYPTO_hash (authorization_access_token,
1886 strlen (authorization_access_token),
1887 &cache_key);
1888 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
1889 &cache_key) )
1890 {
1891 handle->emsg = GNUNET_strdup("invalid_token");
1892 handle->edesc = GNUNET_strdup("The Access Token expired");
1893 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1894 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1895 GNUNET_free(authorization);
1896 return;
1897 }
1898
1899 client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
1900 &cache_key);
1901 client_ticket = GNUNET_strdup(client_ticket);
1902 client = strtok(client_ticket,delimiter_db);
1903 if (NULL == client)
1904 {
1905 handle->emsg = GNUNET_strdup("invalid_token");
1906 handle->edesc = GNUNET_strdup("The Access Token expired");
1907 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1908 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1909 GNUNET_free(authorization);
1910 GNUNET_free(client_ticket);
1911 return;
1912 }
1913 handle->ego_entry = handle->ego_head;
1914 for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1915 {
1916 if (0 == strcmp(handle->ego_entry->keystring,client))
1917 {
1918 break;
1919 }
1920 }
1921 if (NULL == handle->ego_entry)
1922 {
1923 handle->emsg = GNUNET_strdup("invalid_token");
1924 handle->edesc = GNUNET_strdup("The Access Token expired");
1925 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1926 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1927 GNUNET_free(authorization);
1928 GNUNET_free(client_ticket);
1929 return;
1930 }
1931 ticket_str = strtok(NULL, delimiter_db);
1932 if (NULL == ticket_str)
1933 {
1934 handle->emsg = GNUNET_strdup("invalid_token");
1935 handle->edesc = GNUNET_strdup("The Access Token expired");
1936 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1937 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1938 GNUNET_free(authorization);
1939 GNUNET_free(client_ticket);
1940 return;
1941 }
1942 ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
1943 if ( GNUNET_OK
1944 != GNUNET_STRINGS_string_to_data (ticket_str,
1945 strlen (ticket_str),
1946 ticket,
1947 sizeof(struct GNUNET_RECLAIM_Ticket)))
1948 {
1949 handle->emsg = GNUNET_strdup("invalid_token");
1950 handle->edesc = GNUNET_strdup("The Access Token expired");
1951 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1952 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1953 GNUNET_free(ticket);
1954 GNUNET_free(authorization);
1955 GNUNET_free(client_ticket);
1956 return;
1957 }
1958
1959 handle->idp = GNUNET_RECLAIM_connect (cfg);
1960 handle->oidc->response = json_object();
1961 json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
1962 handle->idp_op = GNUNET_RECLAIM_ticket_consume (
1963 handle->idp,
1964 GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
1965 ticket,
1966 consume_ticket,
1967 handle);
1968 GNUNET_free(ticket);
1969 GNUNET_free(authorization);
1970 GNUNET_free(client_ticket);
1971
1972}
1973
1974
1975/**
1976 * Handle rest request
1977 *
1978 * @param handle the request handle
1979 */
1980static void
1981init_cont (struct RequestHandle *handle)
1982{
1983 struct GNUNET_REST_RequestHandlerError err;
1984 static const struct GNUNET_REST_RequestHandler handlers[] = {
1985 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
1986 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
1987 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
1988 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
1989 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1990 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
1991 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC,
1992 &options_cont},
1993 GNUNET_REST_HANDLER_END
1994 };
1995
1996 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1997 handlers,
1998 &err,
1999 handle))
2000 {
2001 handle->response_code = err.error_code;
2002 GNUNET_SCHEDULER_add_now (&do_error, handle);
2003 }
2004}
2005
2006/**
2007 * If listing is enabled, prints information about the egos.
2008 *
2009 * This function is initially called for all egos and then again
2010 * whenever a ego's identifier changes or if it is deleted. At the
2011 * end of the initial pass over all egos, the function is once called
2012 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2013 * be invoked in the future or that there was an error.
2014 *
2015 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2016 * this function is only called ONCE, and 'NULL' being passed in
2017 * 'ego' does indicate an error (i.e. name is taken or no default
2018 * value is known). If 'ego' is non-NULL and if '*ctx'
2019 * is set in those callbacks, the value WILL be passed to a subsequent
2020 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2021 * that one was not NULL).
2022 *
2023 * When an identity is renamed, this function is called with the
2024 * (known) ego but the NEW identifier.
2025 *
2026 * When an identity is deleted, this function is called with the
2027 * (known) ego and "NULL" for the 'identifier'. In this case,
2028 * the 'ego' is henceforth invalid (and the 'ctx' should also be
2029 * cleaned up).
2030 *
2031 * @param cls closure
2032 * @param ego ego handle
2033 * @param ctx context for application to store data for this ego
2034 * (during the lifetime of this process, initially NULL)
2035 * @param identifier identifier assigned by the user for this ego,
2036 * NULL if the user just deleted the ego and it
2037 * must thus no longer be used
2038 */
2039static void
2040list_ego (void *cls,
2041 struct GNUNET_IDENTITY_Ego *ego,
2042 void **ctx,
2043 const char *identifier)
2044{
2045 struct RequestHandle *handle = cls;
2046 struct EgoEntry *ego_entry;
2047 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2048
2049 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2050 {
2051 handle->state = ID_REST_STATE_POST_INIT;
2052 init_cont (handle);
2053 return;
2054 }
2055 if (ID_REST_STATE_INIT == handle->state) {
2056 ego_entry = GNUNET_new (struct EgoEntry);
2057 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2058 ego_entry->keystring =
2059 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2060 ego_entry->ego = ego;
2061 ego_entry->identifier = GNUNET_strdup (identifier);
2062 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2063 return;
2064 }
2065 /* Ego renamed or added */
2066 if (identifier != NULL) {
2067 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2068 if (ego_entry->ego == ego) {
2069 /* Rename */
2070 GNUNET_free (ego_entry->identifier);
2071 ego_entry->identifier = GNUNET_strdup (identifier);
2072 break;
2073 }
2074 }
2075 if (NULL == ego_entry) {
2076 /* Add */
2077 ego_entry = GNUNET_new (struct EgoEntry);
2078 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2079 ego_entry->keystring =
2080 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2081 ego_entry->ego = ego;
2082 ego_entry->identifier = GNUNET_strdup (identifier);
2083 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2084 }
2085 } else {
2086 /* Delete */
2087 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2088 if (ego_entry->ego == ego)
2089 break;
2090 }
2091 if (NULL != ego_entry)
2092 GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry);
2093 }
2094
2095}
2096
2097static void
2098rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2099 GNUNET_REST_ResultProcessor proc,
2100 void *proc_cls)
2101{
2102 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2103 handle->oidc = GNUNET_new (struct OIDC_Variables);
2104 if ( NULL == OIDC_identity_login_time )
2105 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2106 if ( NULL == OIDC_identity_grants )
2107 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2108 if ( NULL == OIDC_ticket_once )
2109 OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2110 if ( NULL == OIDC_interpret_access_token )
2111 OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2112 handle->response_code = 0;
2113 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2114 handle->proc_cls = proc_cls;
2115 handle->proc = proc;
2116 handle->state = ID_REST_STATE_INIT;
2117 handle->rest_handle = rest_handle;
2118
2119 handle->url = GNUNET_strdup (rest_handle->url);
2120 if (handle->url[strlen (handle->url)-1] == '/')
2121 handle->url[strlen (handle->url)-1] = '\0';
2122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2123 "Connecting...\n");
2124 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2125 &list_ego,
2126 handle);
2127 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2128 handle->timeout_task =
2129 GNUNET_SCHEDULER_add_delayed (handle->timeout,
2130 &do_timeout,
2131 handle);
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2133 "Connected\n");
2134}
2135
2136/**
2137 * Entry point for the plugin.
2138 *
2139 * @param cls Config info
2140 * @return NULL on error, otherwise the plugin context
2141 */
2142void *
2143libgnunet_plugin_rest_openid_connect_init (void *cls)
2144{
2145 static struct Plugin plugin;
2146 struct GNUNET_REST_Plugin *api;
2147
2148 cfg = cls;
2149 if (NULL != plugin.cfg)
2150 return NULL; /* can only initialize once! */
2151 memset (&plugin, 0, sizeof (struct Plugin));
2152 plugin.cfg = cfg;
2153 api = GNUNET_new (struct GNUNET_REST_Plugin);
2154 api->cls = &plugin;
2155 api->name = GNUNET_REST_API_NS_OIDC;
2156 api->process_request = &rest_identity_process_request;
2157 GNUNET_asprintf (&allow_methods,
2158 "%s, %s, %s, %s, %s",
2159 MHD_HTTP_METHOD_GET,
2160 MHD_HTTP_METHOD_POST,
2161 MHD_HTTP_METHOD_PUT,
2162 MHD_HTTP_METHOD_DELETE,
2163 MHD_HTTP_METHOD_OPTIONS);
2164
2165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2166 _("Identity Provider REST API initialized\n"));
2167 return api;
2168}
2169
2170
2171/**
2172 * Exit point from the plugin.
2173 *
2174 * @param cls the plugin context (as returned by "init")
2175 * @return always NULL
2176 */
2177void *
2178libgnunet_plugin_rest_openid_connect_done (void *cls)
2179{
2180 struct GNUNET_REST_Plugin *api = cls;
2181 struct Plugin *plugin = api->cls;
2182 plugin->cfg = NULL;
2183
2184 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2185 void *value = NULL;
2186 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2187 OIDC_identity_login_time);
2188 while (GNUNET_YES ==
2189 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2190 {
2191 if (NULL != value)
2192 GNUNET_free(value);
2193 }
2194 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2195 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2196 while (GNUNET_YES ==
2197 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2198 {
2199 if (NULL != value)
2200 GNUNET_free(value);
2201 }
2202 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2203 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2204 while (GNUNET_YES ==
2205 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2206 {
2207 if (NULL != value)
2208 GNUNET_free(value);
2209 }
2210 GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2211 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2212 while (GNUNET_YES ==
2213 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2214 {
2215 if (NULL != value)
2216 GNUNET_free(value);
2217 }
2218 GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2219 GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2220 GNUNET_free_non_null (allow_methods);
2221 GNUNET_free (api);
2222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2223 "Identity Provider REST plugin is finished\n");
2224 return NULL;
2225}
2226
2227/* 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..b54aed5f3
--- /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 "/idp"
46
47/**
48 * Attribute namespace
49 */
50#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/idp/attributes"
51
52/**
53 * Ticket namespace
54 */
55#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
56
57/**
58 * Revoke namespace
59 */
60#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
61
62/**
63 * Revoke namespace
64 */
65#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/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..e93899e05
--- /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 = 3600
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