aboutsummaryrefslogtreecommitdiff
path: root/src/identity-provider
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2016-01-07 21:10:24 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2016-01-07 21:10:24 +0000
commit1b67c9c5424c96ff4e30d12b8d58cec315f000a1 (patch)
tree65a03cf96bd718d3e57bd2d7f0f0a648cb1986f4 /src/identity-provider
parent4c2b05fe49e5ee49c69337e763a3572af59e78d5 (diff)
downloadgnunet-1b67c9c5424c96ff4e30d12b8d58cec315f000a1.tar.gz
gnunet-1b67c9c5424c96ff4e30d12b8d58cec315f000a1.zip
- Finish refactoring
Diffstat (limited to 'src/identity-provider')
-rw-r--r--src/identity-provider/Makefile.am70
-rw-r--r--src/identity-provider/gnunet-identity-token.c114
-rw-r--r--src/identity-provider/gnunet-service-identity-token.c762
-rw-r--r--src/identity-provider/identity-token.c827
-rw-r--r--src/identity-provider/identity-token.conf2
-rw-r--r--src/identity-provider/plugin_rest_identity_token.c1412
6 files changed, 3187 insertions, 0 deletions
diff --git a/src/identity-provider/Makefile.am b/src/identity-provider/Makefile.am
new file mode 100644
index 000000000..a9338ba59
--- /dev/null
+++ b/src/identity-provider/Makefile.am
@@ -0,0 +1,70 @@
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
15pkgcfgdir= $(pkgdatadir)/config.d/
16
17libexecdir= $(pkglibdir)/libexec/
18
19pkgcfg_DATA = \
20 identity-token.conf
21
22plugin_LTLIBRARIES = \
23 libgnunet_plugin_rest_identity_token.la
24lib_LTLIBRARIES = \
25 libgnunetidentityprovider.la
26
27bin_PROGRAMS = \
28 gnunet-identity-token
29
30libexec_PROGRAMS = \
31 gnunet-service-identity-token
32
33gnunet_service_identity_token_SOURCES = \
34 gnunet-service-identity-token.c
35gnunet_service_identity_token_LDADD = \
36 libgnunetidentityprovider.la \
37 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
38 $(top_builddir)/src/util/libgnunetutil.la \
39 $(top_builddir)/src/namestore/libgnunetnamestore.la \
40 $(top_builddir)/src/identity/libgnunetidentity.la \
41 $(GN_LIBINTL) \
42 -ljansson
43
44libgnunetidentityprovider_la_SOURCES = \
45 identity-token.c
46libgnunetidentityprovider_la_LIBADD = \
47 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
48 $(LTLIBINTL) -ljansson
49
50libgnunet_plugin_rest_identity_token_la_SOURCES = \
51 plugin_rest_identity_token.c
52libgnunet_plugin_rest_identity_token_la_LIBADD = \
53 $(top_builddir)/src/identity/libgnunetidentity.la \
54 $(top_builddir)/src/rest/libgnunetrest.la \
55 $(top_builddir)/src/namestore/libgnunetnamestore.la \
56 $(top_builddir)/src/gns/libgnunetgns.la \
57 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
58 $(LTLIBINTL) -ljansson -lmicrohttpd
59libgnunet_plugin_rest_identity_token_la_LDFLAGS = \
60 $(GN_PLUGIN_LDFLAGS)
61
62
63gnunet_identity_token_SOURCES = \
64 gnunet-identity-token.c
65gnunet_identity_token_LDADD = \
66 $(top_builddir)/src/util/libgnunetutil.la \
67 -ljansson -lmicrohttpd \
68 $(GN_LIBINTL)
69
70
diff --git a/src/identity-provider/gnunet-identity-token.c b/src/identity-provider/gnunet-identity-token.c
new file mode 100644
index 000000000..ad4aae78a
--- /dev/null
+++ b/src/identity-provider/gnunet-identity-token.c
@@ -0,0 +1,114 @@
1#include "platform.h"
2#include "gnunet_util_lib.h"
3#include <jansson.h>
4#include "gnunet_signatures.h"
5
6/**
7 * The token
8 */
9static char* token;
10
11/**
12 * Weather to print the token
13 */
14static int print_token;
15
16static void
17run (void *cls,
18 char *const *args,
19 const char *cfgfile,
20 const struct GNUNET_CONFIGURATION_Handle *c)
21{
22 char* payload;
23 char* header;
24 //Get token parts
25 char* header_b64 = strtok (token, ".");
26 char* payload_b64 = strtok(NULL, ".");
27 char* signature_b32 = strtok(NULL, ".");
28 const char* keystring;
29 char* data;
30 json_t *payload_json;
31 json_t *keystring_json;
32 json_error_t error;
33 struct GNUNET_CRYPTO_EcdsaPublicKey key;
34 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
35 struct GNUNET_CRYPTO_EcdsaSignature sig;
36 //Decode payload
37 GNUNET_STRINGS_base64_decode (payload_b64,
38 strlen (payload_b64),
39 &payload);
40 //Decode header
41 GNUNET_STRINGS_base64_decode (header_b64,
42 strlen (header_b64),
43 &header);
44 if (NULL == token)
45 return;
46
47
48 GNUNET_asprintf(&data,
49 "%s,%s",
50 header_b64,
51 payload_b64);
52 char *val = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
53 purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose*)val;
54 purpose->size = htonl(sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
55 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
56 memcpy (&purpose[1], data, strlen(data));
57
58
59 payload_json = json_loads (payload, 0, &error);
60 if ((NULL == payload_json) || !json_is_object (payload_json))
61 {
62 return;
63 }
64 keystring_json = json_object_get (payload_json, "iss");
65 if (!json_is_string (keystring_json))
66 {
67 return;
68 }
69 keystring = json_string_value (keystring_json);
70 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (keystring,
71 strlen (keystring),
72 &key))
73 {
74 return;
75 }
76 GNUNET_STRINGS_string_to_data (signature_b32,
77 strlen (signature_b32),
78 &sig,
79 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
80
81 if (print_token) {
82 printf ("Token:\nHeader:\t\t%s\nPayload:\t%s\nSignature:\t%s\n", header, payload, keystring);
83 }
84
85 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN,
86 purpose,
87 &sig,
88 &key))
89 {
90 printf("Signature not OK!\n");
91 return;
92 }
93 printf("Signature OK!\n");
94 return;
95}
96int
97main(int argc, char *const argv[])
98{
99 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
100 {'t', "token", NULL,
101 gettext_noop ("GNUid token"), 1,
102 &GNUNET_GETOPT_set_string, &token},
103 {'p', "print", NULL,
104 gettext_noop ("Print token contents"), 0,
105 &GNUNET_GETOPT_set_one, &print_token},
106
107 GNUNET_GETOPT_OPTION_END
108 };
109 return GNUNET_PROGRAM_run (argc, argv, "ct",
110 "ct", options,
111 &run, NULL);
112}
113
114
diff --git a/src/identity-provider/gnunet-service-identity-token.c b/src/identity-provider/gnunet-service-identity-token.c
new file mode 100644
index 000000000..039d1c7e0
--- /dev/null
+++ b/src/identity-provider/gnunet-service-identity-token.c
@@ -0,0 +1,762 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file src/rest/gnunet-service-identity-token.c
23 * @brief Identity Token Service
24 *
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_namestore_service.h"
31#include <jansson.h>
32#include "gnunet_signatures.h"
33#include "gnunet_identity_provider_lib.h"
34
35/**
36 * First pass state
37 */
38#define STATE_INIT 0
39
40/**
41 * Normal operation state
42 */
43#define STATE_POST_INIT 1
44
45/**
46 * Minimum interval between updates
47 */
48#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
49
50/**
51 * Service state (to detect initial update pass)
52 */
53static int state;
54
55/**
56 * Head of ego entry DLL
57 */
58static struct EgoEntry *ego_head;
59
60/**
61 * Tail of ego entry DLL
62 */
63static struct EgoEntry *ego_tail;
64
65/**
66 * Identity handle
67 */
68static struct GNUNET_IDENTITY_Handle *identity_handle;
69
70/**
71 * Namestore handle
72 */
73static struct GNUNET_NAMESTORE_Handle *ns_handle;
74
75/**
76 * Namestore qe
77 */
78static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
79
80/**
81 * Namestore iterator
82 */
83static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
84
85/**
86 * Timeout task
87 */
88static struct GNUNET_SCHEDULER_Task * timeout_task;
89
90
91/**
92 * Update task
93 */
94static struct GNUNET_SCHEDULER_Task * update_task;
95
96/**
97 * Timeout for next update pass
98 */
99static struct GNUNET_TIME_Relative min_rel_exp;
100
101
102/**
103 * Currently processed token
104 */
105static struct GNUNET_IDENTITY_PROVIDER_Token *token;
106
107/**
108 * Label for currently processed token
109 */
110static char* label;
111
112/**
113 * Scopes for processed token
114 */
115static char* scopes;
116
117/**
118 * Expiration for processed token
119 */
120static uint64_t rd_exp;
121
122/**
123 * ECDHE Privkey for processed token metadata
124 */
125static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
126
127/**
128 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
129 *
130 */
131struct EgoEntry
132{
133 /**
134 * DLL
135 */
136 struct EgoEntry *next;
137
138 /**
139 * DLL
140 */
141 struct EgoEntry *prev;
142
143 /**
144 * Ego handle
145 */
146 struct GNUNET_IDENTITY_Ego *ego;
147
148 /**
149 * Attribute map. Contains the attributes as json_t
150 */
151 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
152
153 /**
154 * Attributes are old and should be updated if GNUNET_YES
155 */
156 int attributes_dirty;
157};
158
159/**
160 * Our configuration.
161 */
162static const struct GNUNET_CONFIGURATION_Handle *cfg;
163
164
165/**
166 * Continuation for token store call
167 *
168 * @param cls NULL
169 * @param success error code
170 * @param emsg error message
171 */
172static void
173store_token_cont (void *cls,
174 int32_t success,
175 const char *emsg)
176{
177 ns_qe = NULL;
178 if (GNUNET_SYSERR == success)
179 {
180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
181 "Failed to update token: %s\n",
182 emsg);
183 return;
184 }
185 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
186}
187
188
189/**
190 * This function updates the old token with new attributes,
191 * removes deleted attributes and expiration times.
192 *
193 * @param cls the ego entry
194 * @param tc task context
195 */
196static void
197handle_token_update (void *cls,
198 const struct GNUNET_SCHEDULER_TaskContext *tc)
199{
200 char *token_metadata;
201 char *write_ptr;
202 char *enc_token_str;
203 const char *key;
204 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
205 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
206 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
207 struct EgoEntry *ego_entry = cls;
208 struct GNUNET_GNSRECORD_Data token_record[2];
209 struct GNUNET_HashCode key_hash;
210 struct GNUNET_TIME_Relative token_rel_exp;
211 struct GNUNET_TIME_Relative token_ttl;
212 struct GNUNET_TIME_Absolute token_exp;
213 struct GNUNET_TIME_Absolute token_nbf;
214 struct GNUNET_TIME_Absolute new_exp;
215 struct GNUNET_TIME_Absolute new_iat;
216 struct GNUNET_TIME_Absolute new_nbf;
217 struct GNUNET_IDENTITY_PROVIDER_Token *new_token;
218 json_t *payload_json;
219 json_t *value;
220 json_t *cur_value;
221 json_t *token_nbf_json;
222 json_t *token_exp_json;
223 size_t token_metadata_len;
224
225 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
226 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
227 &pub_key);
228
229 //Note: We need the token expiration time here. Not the record expiration
230 //time.
231 //There are two types of tokens: Token that expire on GNS level with
232 //an absolute expiration time. Those are basically tokens that will
233 //be automatically revoked on (record)expiration.
234 //Tokens stored with relative expiration times will expire on the token level (token expiration)
235 //but this service will reissue new tokens that can be retrieved from GNS
236 //automatically.
237
238 payload_json = token->payload;
239
240 token_exp_json = json_object_get (payload_json, "exp");
241 token_nbf_json = json_object_get (payload_json, "nbf");
242 token_exp.abs_value_us = json_integer_value(token_exp_json);
243 token_nbf.abs_value_us = json_integer_value(token_nbf_json);
244 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
245
246 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
247 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
248 {
249 //This token is not yet expired! Save and skip
250 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
251 {
252 min_rel_exp = token_ttl;
253 }
254 json_decref (payload_json);
255 GNUNET_free (token);
256 token = NULL;
257 GNUNET_free (label);
258 label = NULL;
259 GNUNET_free (scopes);
260 scopes = NULL;
261 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
262 return;
263 }
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "Token is expired. Create a new one\n");
266 new_token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
267 &token->aud_key);
268 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
269 new_nbf = GNUNET_TIME_absolute_get ();
270 new_iat = new_nbf;
271
272 json_object_foreach(payload_json, key, value) {
273 if (0 == strcmp (key, "exp"))
274 {
275 GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_exp.abs_value_us));
276 }
277 else if (0 == strcmp (key, "nbf"))
278 {
279 GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_nbf.abs_value_us));
280 }
281 else if (0 == strcmp (key, "iat"))
282 {
283 GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_iat.abs_value_us));
284 }
285 else if ((0 == strcmp (key, "iss"))
286 || (0 == strcmp (key, "aud")))
287 {
288 //Omit
289 }
290 else if ((0 == strcmp (key, "sub"))
291 || (0 == strcmp (key, "rnl")))
292 {
293 GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, value);
294 }
295 else {
296 GNUNET_CRYPTO_hash (key,
297 strlen (key),
298 &key_hash);
299 //Check if attr still exists. omit of not
300 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
301 &key_hash))
302 {
303 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
304 &key_hash);
305 GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, cur_value);
306 }
307 }
308 }
309
310 // reassemble and set
311 GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (new_token,
312 priv_key,
313 &new_ecdhe_privkey,
314 &enc_token_str));
315
316 json_decref (payload_json);
317
318 token_record[0].data = enc_token_str;
319 token_record[0].data_size = strlen (enc_token_str) + 1;
320 token_record[0].expiration_time = rd_exp; //Old expiration time
321 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
322 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
323
324 //Meta
325 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
326 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
327 + strlen (scopes) + 1; //With 0-Terminator
328 token_metadata = GNUNET_malloc (token_metadata_len);
329 write_ptr = token_metadata;
330 memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
331 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
332 memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
333 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
334 memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
335
336 token_record[1].data = token_metadata;
337 token_record[1].data_size = token_metadata_len;
338 token_record[1].expiration_time = rd_exp;
339 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
340 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
341
342 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
343 priv_key,
344 label,
345 2,
346 token_record,
347 &store_token_cont,
348 ego_entry);
349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
350 GNUNET_IDENTITY_PROVIDER_token_destroy (new_token);
351 GNUNET_IDENTITY_PROVIDER_token_destroy (token);
352 GNUNET_free (new_ecdhe_privkey);
353 GNUNET_free (enc_token_str);
354 token = NULL;
355 GNUNET_free (label);
356 label = NULL;
357 GNUNET_free (scopes);
358 scopes = NULL;
359}
360
361static void
362update_identities(void *cls,
363 const struct GNUNET_SCHEDULER_TaskContext *tc);
364
365/**
366 *
367 * Cleanup attr_map
368 *
369 * @param cls NULL
370 * @param key the key
371 * @param value the json_t attribute value
372 * @return GNUNET_YES
373 */
374static int
375clear_ego_attrs (void *cls,
376 const struct GNUNET_HashCode *key,
377 void *value)
378{
379 json_t *attr_value = value;
380
381 json_decref (attr_value);
382
383 return GNUNET_YES;
384}
385
386
387/**
388 *
389 * Update all ID_TOKEN records for an identity and store them
390 *
391 * @param cls the identity entry
392 * @param zone the identity
393 * @param lbl the name of the record
394 * @param rd_count number of records
395 * @param rd record data
396 *
397 */
398static void
399token_collect (void *cls,
400 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
401 const char *lbl,
402 unsigned int rd_count,
403 const struct GNUNET_GNSRECORD_Data *rd)
404{
405 struct EgoEntry *ego_entry = cls;
406 const struct GNUNET_GNSRECORD_Data *token_record;
407 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
408 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
409
410 if (NULL == lbl)
411 {
412 //Done
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 ">>> Updating Ego finished\n");
415 //Clear attribute map for ego
416 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
417 &clear_ego_attrs,
418 ego_entry);
419 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
420 GNUNET_SCHEDULER_add_now (&update_identities, ego_entry->next);
421 return;
422 }
423
424 //There should be only a single record for a token under a label
425 if (2 != rd_count)
426 {
427 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
428 return;
429 }
430
431 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
432 {
433 token_metadata_record = &rd[0];
434 token_record = &rd[1];
435 } else {
436 token_record = &rd[0];
437 token_metadata_record = &rd[1];
438 }
439 GNUNET_assert (token_metadata_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA);
440 GNUNET_assert (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN);
441
442 //Get metadata and decrypt token
443 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
444 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
445 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
446
447 GNUNET_IDENTITY_PROVIDER_token_parse2 (token_record->data,
448 &ecdhe_privkey,
449 aud_key,
450 &token);
451
452 //token = GNUNET_GNSRECORD_value_to_string (rd->record_type,
453 // rd->data,
454 // rd->data_size);
455 label = GNUNET_strdup (lbl);
456 rd_exp = token_record->expiration_time;
457
458 GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
459}
460
461
462/**
463 *
464 * Collect all ID_ATTR records for an identity and store them
465 *
466 * @param cls the identity entry
467 * @param zone the identity
468 * @param lbl the name of the record
469 * @param rd_count number of records
470 * @param rd record data
471 *
472 */
473static void
474attribute_collect (void *cls,
475 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
476 const char *lbl,
477 unsigned int rd_count,
478 const struct GNUNET_GNSRECORD_Data *rd)
479{
480 struct EgoEntry *ego_entry = cls;
481 json_t *attr_value;
482 struct GNUNET_HashCode key;
483 char* attr;
484 int i;
485
486 if (NULL == lbl)
487 {
488 //Done
489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 ">>> Updating Attributes finished\n");
491 ego_entry->attributes_dirty = GNUNET_NO;
492 GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
493 return;
494 }
495
496 if (0 == rd_count)
497 {
498 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
499 return;
500 }
501 GNUNET_CRYPTO_hash (lbl,
502 strlen (lbl),
503 &key);
504 if (1 == rd_count)
505 {
506 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
507 {
508 attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
509 rd->data,
510 rd->data_size);
511 attr_value = json_string (attr);
512 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
513 &key,
514 attr_value,
515 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
516 GNUNET_free (attr);
517 }
518
519 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
520 return;
521 }
522
523 attr_value = json_array();
524 for (i = 0; i < rd_count; i++)
525 {
526 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
527 {
528 attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
529 rd[i].data,
530 rd[i].data_size);
531 json_array_append_new (attr_value, json_string (attr));
532 GNUNET_free (attr);
533 }
534
535 }
536 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
537 &key,
538 attr_value,
539 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
540 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
541 return;
542}
543
544/**
545 *
546 * Update identity information for ego. If attribute map is
547 * dirty, first update the attributes.
548 *
549 * @param cls the ego to update
550 * param tc task context
551 *
552 */
553static void
554update_identities(void *cls,
555 const struct GNUNET_SCHEDULER_TaskContext *tc)
556{
557 struct EgoEntry *next_ego = cls;
558 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
559 if (NULL == next_ego)
560 {
561 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
562 min_rel_exp = MIN_WAIT_TIME;
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 ">>> Finished. Rescheduling in %d\n",
565 min_rel_exp.rel_value_us);
566 ns_it = NULL;
567 //finished -> TODO reschedule
568 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
569 &update_identities,
570 ego_head);
571 min_rel_exp.rel_value_us = 0;
572 return;
573 }
574 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
575 if (GNUNET_YES == next_ego->attributes_dirty)
576 {
577 //Starting over. We must update the Attributes for they might have changed.
578 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
579 priv_key,
580 &attribute_collect,
581 next_ego);
582
583 }
584 else
585 {
586 //Ego will be dirty next time
587 next_ego->attributes_dirty = GNUNET_YES;
588 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
589 priv_key,
590 &token_collect,
591 next_ego);
592 }
593}
594
595
596
597/**
598 * Function called initially to start update task
599 */
600static void
601init_cont ()
602{
603 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
604 //Initially iterate all itenties and refresh all tokens
605 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
606}
607
608/**
609 * Initial ego collection function.
610 *
611 * @param cls NULL
612 * @param ego ego
613 * @param ctx context
614 * @param identifier ego name
615 */
616static void
617list_ego (void *cls,
618 struct GNUNET_IDENTITY_Ego *ego,
619 void **ctx,
620 const char *identifier)
621{
622 struct EgoEntry *new_entry;
623 if ((NULL == ego) && (STATE_INIT == state))
624 {
625 state = STATE_POST_INIT;
626 init_cont ();
627 return;
628 }
629 if (STATE_INIT == state) {
630 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
631 new_entry->ego = ego;
632 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
633 GNUNET_NO);
634 new_entry->attributes_dirty = GNUNET_YES;
635 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
636 }
637}
638
639/**
640 * Cleanup task
641 */
642static void
643cleanup()
644{
645 struct EgoEntry *ego_entry;
646 struct EgoEntry *ego_tmp;
647
648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
649 "Cleaning up\n");
650 if (NULL != timeout_task)
651 GNUNET_SCHEDULER_cancel (timeout_task);
652 if (NULL != update_task)
653 GNUNET_SCHEDULER_cancel (update_task);
654 if (NULL != identity_handle)
655 GNUNET_IDENTITY_disconnect (identity_handle);
656 if (NULL != ns_it)
657 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
658 if (NULL != ns_qe)
659 GNUNET_NAMESTORE_cancel (ns_qe);
660 if (NULL != ns_handle)
661 GNUNET_NAMESTORE_disconnect (ns_handle);
662 if (NULL != token)
663 GNUNET_free (token);
664 if (NULL != label)
665 GNUNET_free (label);
666
667 for (ego_entry = ego_head;
668 NULL != ego_entry;)
669 {
670 ego_tmp = ego_entry;
671 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
672 {
673 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
674 &clear_ego_attrs,
675 ego_tmp);
676
677 }
678 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
679 ego_entry = ego_entry->next;
680 GNUNET_free (ego_tmp);
681 }
682}
683
684/**
685 * Shutdown task
686 *
687 * @param cls NULL
688 * @param tc task context
689 */
690static void
691do_shutdown (void *cls,
692 const struct GNUNET_SCHEDULER_TaskContext *tc)
693{
694 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
695 "Shutting down...\n");
696 cleanup();
697}
698
699/**
700 * Main function that will be run
701 *
702 * @param cls closure
703 * @param args remaining command-line arguments
704 * @param cfgfile name of the configuration file used (for saving, can be NULL)
705 * @param c configuration
706 */
707static void
708run (void *cls,
709 char *const *args,
710 const char *cfgfile,
711 const struct GNUNET_CONFIGURATION_Handle *c)
712{
713 cfg = c;
714
715
716 //Connect to identity and namestore services
717 ns_handle = GNUNET_NAMESTORE_connect (cfg);
718 if (NULL == ns_handle)
719 {
720 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
721 }
722
723 identity_handle = GNUNET_IDENTITY_connect (cfg,
724 &list_ego,
725 NULL);
726
727 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
728 &do_shutdown, NULL);
729}
730
731
732/**
733 *
734 * The main function for gnunet-service-identity-token
735 *
736 * @param argc number of arguments from the cli
737 * @param argv command line arguments
738 * @return 0 ok, 1 on error
739 *
740 */
741int
742main (int argc, char *const *argv)
743{
744 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
745 GNUNET_GETOPT_OPTION_END
746 };
747 int ret;
748
749 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
750 return 2;
751 GNUNET_log_setup ("gnunet-service-identity-token", "WARNING", NULL);
752 ret =
753 (GNUNET_OK ==
754 GNUNET_PROGRAM_run (argc, argv, "gnunet-service-identity-token",
755 _("GNUnet identity token service"),
756 options,
757 &run, NULL)) ? 0: 1;
758 GNUNET_free_non_null ((char *) argv);
759 return ret;
760}
761
762/* end of gnunet-rest-server.c */
diff --git a/src/identity-provider/identity-token.c b/src/identity-provider/identity-token.c
new file mode 100644
index 000000000..a9f210b14
--- /dev/null
+++ b/src/identity-provider/identity-token.c
@@ -0,0 +1,827 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @file identity-token/identity-token.c
23 * @brief helper library to manage identity tokens
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include "gnunet_identity_provider_lib.h"
30#include <jansson.h>
31
32
33/**
34 * Crypto helper functions
35 */
36
37static int
38create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
39 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
40 struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
41{
42 struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
43
44 GNUNET_CRYPTO_hash_to_enc (new_key_hash,
45 &new_key_hash_str);
46 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
47 static const char ctx_key[] = "gnuid-aes-ctx-key";
48 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
49 new_key_hash, sizeof (struct GNUNET_HashCode),
50 ctx_key, strlen (ctx_key),
51 NULL, 0);
52 static const char ctx_iv[] = "gnuid-aes-ctx-iv";
53 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
54 new_key_hash, sizeof (struct GNUNET_HashCode),
55 ctx_iv, strlen (ctx_iv),
56 NULL, 0);
57 return GNUNET_OK;
58}
59
60
61
62/**
63 * Decrypts metainfo part from a token code
64 */
65static int
66decrypt_str_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
67 const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key,
68 const char *cyphertext,
69 size_t cyphertext_len,
70 char **result_str)
71{
72 struct GNUNET_HashCode new_key_hash;
73 struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
74 struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
75
76 char *str_buf = GNUNET_malloc (cyphertext_len);
77 size_t str_size;
78
79 //Calculate symmetric key from ecdh parameters
80 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_ecdh (priv_key,
81 ecdh_key,
82 &new_key_hash));
83
84 create_sym_key_from_ecdh (&new_key_hash,
85 &enc_key,
86 &enc_iv);
87
88 str_size = GNUNET_CRYPTO_symmetric_decrypt (cyphertext,
89 cyphertext_len,
90 &enc_key,
91 &enc_iv,
92 str_buf);
93 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Decrypted bytes: %d Expected bytes: %d\n", str_size, cyphertext_len);
94 if (-1 == str_size)
95 {
96 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH invalid\n");
97 GNUNET_free (str_buf);
98 return GNUNET_SYSERR;
99 }
100 *result_str = GNUNET_malloc (str_size+1);
101 memcpy (*result_str, str_buf, str_size);
102 (*result_str)[str_size] = '\0';
103 GNUNET_free (str_buf);
104 return GNUNET_OK;
105
106}
107
108/**
109 * Decrypt string using pubkey and ECDHE
110*/
111static int
112decrypt_str_ecdhe2 (const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_privkey,
113 const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
114 const char *ciphertext,
115 size_t ciphertext_len,
116 char **plaintext)
117{
118 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
119 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
120 struct GNUNET_HashCode new_key_hash;
121
122 //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
123 *plaintext = GNUNET_malloc (ciphertext_len);
124
125 // Derived key K = H(eB)
126 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (ecdh_privkey,
127 aud_key,
128 &new_key_hash));
129 create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
130 GNUNET_CRYPTO_symmetric_decrypt (ciphertext,
131 ciphertext_len,
132 &skey, &iv,
133 *plaintext);
134 return GNUNET_OK;
135}
136
137
138/**
139 * Encrypt string using pubkey and ECDHE
140 * Returns ECDHE pubkey to be used for decryption
141 */
142static int
143encrypt_str_ecdhe (const char *plaintext,
144 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
145 char **cyphertext,
146 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
147 struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pubkey)
148{
149 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
150 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
151 struct GNUNET_HashCode new_key_hash;
152 ssize_t enc_size;
153
154 // ECDH keypair E = eG
155 *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
156 GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
157 ecdh_pubkey);
158
159 //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
160 *cyphertext = GNUNET_malloc (strlen (plaintext));
161
162 // Derived key K = H(eB)
163 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
164 pub_key,
165 &new_key_hash));
166 create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypting string %s\n (len=%d)",
168 plaintext,
169 strlen (plaintext));
170 enc_size = GNUNET_CRYPTO_symmetric_encrypt (plaintext, strlen (plaintext),
171 &skey, &iv,
172 *cyphertext);
173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypted (len=%d)", enc_size);
174 return GNUNET_OK;
175}
176
177
178
179
180/**
181 * Identity Token API
182 */
183
184
185/**
186 * Create an Identity Token
187 *
188 * @param type the JSON API resource type
189 * @param id the JSON API resource id
190 * @return a new JSON API resource or NULL on error.
191 */
192struct GNUNET_IDENTITY_PROVIDER_Token*
193GNUNET_IDENTITY_PROVIDER_token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey* iss,
194 const struct GNUNET_CRYPTO_EcdsaPublicKey* aud)
195{
196 struct GNUNET_IDENTITY_PROVIDER_Token *token;
197 char* audience;
198 char* issuer;
199
200 issuer = GNUNET_STRINGS_data_to_string_alloc (iss,
201 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
202 audience = GNUNET_STRINGS_data_to_string_alloc (aud,
203 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
204
205
206
207 token = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
208
209 token->header = json_object();
210 token->payload = json_object();
211
212 json_object_set_new (token->header, "alg", json_string ("ED512"));
213 json_object_set_new (token->header, "typ", json_string ("JWT"));
214
215 json_object_set_new (token->payload, "iss", json_string (issuer));
216 json_object_set_new (token->payload, "aud", json_string (audience));
217
218 token->aud_key = *aud;
219 GNUNET_free (issuer);
220 GNUNET_free (audience);
221 return token;
222}
223
224void
225GNUNET_IDENTITY_PROVIDER_token_destroy (struct GNUNET_IDENTITY_PROVIDER_Token *token)
226{
227 json_decref (token->header);
228 json_decref (token->payload);
229 GNUNET_free (token);
230}
231
232void
233GNUNET_IDENTITY_PROVIDER_token_add_attr (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
234 const char* key,
235 const char* value)
236{
237 GNUNET_assert (NULL != token);
238 GNUNET_assert (NULL != token->payload);
239
240 json_object_set_new (token->payload, key, json_string (value));
241}
242
243void
244GNUNET_IDENTITY_PROVIDER_token_add_json (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
245 const char* key,
246 json_t* value)
247{
248 GNUNET_assert (NULL != token);
249 GNUNET_assert (NULL != token->payload);
250
251 json_object_set_new (token->payload, key, value);
252}
253
254
255int
256GNUNET_IDENTITY_PROVIDER_token_parse2 (const char* raw_data,
257 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
258 const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
259 struct GNUNET_IDENTITY_PROVIDER_Token **result)
260{
261 char *enc_token_str;
262 char *tmp_buf;
263 char *token_str;
264 char *enc_token;
265 char *header;
266 char *header_base64;
267 char *payload;
268 char *payload_base64;
269 size_t enc_token_len;
270 json_error_t err_json;
271
272 GNUNET_asprintf (&tmp_buf, "%s", raw_data);
273 strtok (tmp_buf, ",");
274 enc_token_str = strtok (NULL, ",");
275
276 enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
277 strlen (enc_token_str),
278 &enc_token);
279 if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key,
280 aud_key,
281 enc_token,
282 enc_token_len,
283 &token_str))
284 {
285 GNUNET_free (tmp_buf);
286 GNUNET_free (enc_token);
287 return GNUNET_SYSERR;
288 }
289
290 header_base64 = strtok (token_str, ".");
291 payload_base64 = strtok (NULL, ".");
292
293 GNUNET_STRINGS_base64_decode (header_base64,
294 strlen (header_base64),
295 &header);
296 GNUNET_STRINGS_base64_decode (payload_base64,
297 strlen (payload_base64),
298 &payload);
299 //TODO signature
300
301
302 *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
303 (*result)->aud_key = *aud_key;
304 (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
305 (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
306 GNUNET_free (enc_token);
307 GNUNET_free (token_str);
308 GNUNET_free (tmp_buf);
309 GNUNET_free (payload);
310 GNUNET_free (header);
311 return GNUNET_OK;
312}
313
314int
315GNUNET_IDENTITY_PROVIDER_token_parse (const char* raw_data,
316 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
317 struct GNUNET_IDENTITY_PROVIDER_Token **result)
318{
319 char *ecdh_pubkey_str;
320 char *enc_token_str;
321 char *tmp_buf;
322 char *token_str;
323 char *enc_token;
324 char *header;
325 char *header_base64;
326 char *payload;
327 char *payload_base64;
328 size_t enc_token_len;
329 json_error_t err_json;
330 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
331
332 GNUNET_asprintf (&tmp_buf, "%s", raw_data);
333 ecdh_pubkey_str = strtok (tmp_buf, ",");
334 enc_token_str = strtok (NULL, ",");
335
336 GNUNET_STRINGS_string_to_data (ecdh_pubkey_str,
337 strlen (ecdh_pubkey_str),
338 &ecdh_pubkey,
339 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
340 enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
341 strlen (enc_token_str),
342 &enc_token);
343 if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
344 &ecdh_pubkey,
345 enc_token,
346 enc_token_len,
347 &token_str))
348 {
349 GNUNET_free (tmp_buf);
350 GNUNET_free (enc_token);
351 return GNUNET_SYSERR;
352 }
353
354 header_base64 = strtok (token_str, ".");
355 payload_base64 = strtok (NULL, ".");
356
357 GNUNET_STRINGS_base64_decode (header_base64,
358 strlen (header_base64),
359 &header);
360 GNUNET_STRINGS_base64_decode (payload_base64,
361 strlen (payload_base64),
362 &payload);
363 //TODO signature and aud key
364
365
366 *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
367 (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
368 (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
369 GNUNET_free (enc_token);
370 GNUNET_free (token_str);
371 GNUNET_free (tmp_buf);
372 GNUNET_free (payload);
373 GNUNET_free (header);
374 return GNUNET_OK;
375}
376
377int
378GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
379 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
380 char **result)
381{
382 char *payload_str;
383 char *header_str;
384 char *payload_base64;
385 char *header_base64;
386 char *padding;
387 char *signature_target;
388 char *signature_str;
389 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
390 header_str = json_dumps (token->header, JSON_COMPACT);
391 GNUNET_STRINGS_base64_encode (header_str,
392 strlen (header_str),
393 &header_base64);
394 //Remove GNUNET padding of base64
395 padding = strtok(header_base64, "=");
396 while (NULL != padding)
397 padding = strtok(NULL, "=");
398
399 payload_str = json_dumps (token->payload, JSON_COMPACT);
400 GNUNET_STRINGS_base64_encode (payload_str,
401 strlen (payload_str),
402 &payload_base64);
403
404 //Remove GNUNET padding of base64
405 padding = strtok(payload_base64, "=");
406 while (NULL != padding)
407 padding = strtok(NULL, "=");
408
409 GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64);
410 purpose =
411 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
412 strlen (signature_target));
413 purpose->size =
414 htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
415 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
416 memcpy (&purpose[1], signature_target, strlen (signature_target));
417 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
418 purpose,
419 (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature))
420 {
421 GNUNET_free (signature_target);
422 GNUNET_free (payload_str);
423 GNUNET_free (header_str);
424 GNUNET_free (payload_base64);
425 GNUNET_free (header_base64);
426 GNUNET_free (purpose);
427 return GNUNET_SYSERR;
428 }
429
430 GNUNET_STRINGS_base64_encode ((const char*)&token->signature,
431 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
432 &signature_str);
433 GNUNET_asprintf (result, "%s.%s.%s",
434 header_base64, payload_base64, signature_str);
435 GNUNET_free (signature_target);
436 GNUNET_free (payload_str);
437 GNUNET_free (header_str);
438 GNUNET_free (signature_str);
439 GNUNET_free (payload_base64);
440 GNUNET_free (header_base64);
441 GNUNET_free (purpose);
442 return GNUNET_OK;
443}
444
445int
446GNUNET_IDENTITY_PROVIDER_token_serialize (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
447 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
448 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
449 char **result)
450{
451 char *token_str;
452 char *enc_token;
453 char *dh_key_str;
454 char *enc_token_base64;
455 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
456
457 GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (token,
458 priv_key,
459 &token_str));
460
461 GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str,
462 &token->aud_key,
463 &enc_token,
464 ecdh_privkey,
465 &ecdh_pubkey));
466 GNUNET_STRINGS_base64_encode (enc_token,
467 strlen (token_str),
468 &enc_token_base64);
469 dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey,
470 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
471 GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64);
472 GNUNET_free (dh_key_str);
473 GNUNET_free (enc_token_base64);
474 GNUNET_free (enc_token);
475 GNUNET_free (token_str);
476 return GNUNET_OK;
477}
478
479struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload*
480GNUNET_IDENTITY_PROVIDER_ticket_payload_create (const char* nonce,
481 const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
482 const char* lbl_str)
483{
484 struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload;
485
486 payload = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload));
487 GNUNET_asprintf (&payload->nonce, nonce, strlen (nonce));
488 payload->identity_key = *identity_pkey;
489 GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str));
490 return payload;
491}
492
493void
494GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload)
495{
496 GNUNET_free (payload->nonce);
497 GNUNET_free (payload->label);
498 GNUNET_free (payload);
499}
500
501void
502GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *payload,
503 char **result)
504{
505 char* identity_key_str;
506
507 identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key,
508 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
509
510 GNUNET_asprintf (result,
511 "{\"nonce\": \"%u\",\"identity\": \"%s\",\"label\": \"%s\"}",
512 payload->nonce, identity_key_str, payload->label);
513 GNUNET_free (identity_key_str);
514
515}
516
517
518/**
519 * Create the token code
520 * The metadata is encrypted with a share ECDH derived secret using B (aud_key)
521 * and e (ecdh_privkey)
522 * The ticket also contains E (ecdh_pubkey) and a signature over the
523 * metadata and E
524 */
525struct GNUNET_IDENTITY_PROVIDER_TokenTicket*
526GNUNET_IDENTITY_PROVIDER_ticket_create (const char* nonce_str,
527 const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
528 const char* lbl_str,
529 const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key)
530{
531 struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
532 struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *code_payload;
533
534 ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
535 code_payload = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
536 identity_pkey,
537 lbl_str);
538 ticket->aud_key = *aud_key;
539 ticket->payload = code_payload;
540
541
542 return ticket;
543}
544
545void
546GNUNET_IDENTITY_PROVIDER_ticket_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket)
547{
548 GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (ticket->payload);
549 GNUNET_free (ticket);
550}
551
552int
553GNUNET_IDENTITY_PROVIDER_ticket_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket,
554 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
555 char **result)
556{
557 char *code_payload_str;
558 char *enc_ticket_payload;
559 char *ticket_payload_str;
560 char *ticket_sig_str;
561 char *ticket_str;
562 char *dh_key_str;
563 char *write_ptr;
564 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
565
566 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
567
568 GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (ticket->payload,
569 &code_payload_str);
570
571 GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str,
572 &ticket->aud_key,
573 &enc_ticket_payload,
574 &ecdhe_privkey,
575 &ticket->ecdh_pubkey));
576
577 GNUNET_free (ecdhe_privkey);
578
579 purpose =
580 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
581 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
582 strlen (code_payload_str)); // E_K (code_str)
583 purpose->size =
584 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
585 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
586 strlen (code_payload_str));
587 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
588 write_ptr = (char*) &purpose[1];
589 memcpy (write_ptr,
590 &ticket->ecdh_pubkey,
591 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
592 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
593 memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
594 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
595 purpose,
596 &ticket->signature));
597 GNUNET_STRINGS_base64_encode (enc_ticket_payload,
598 strlen (code_payload_str),
599 &ticket_payload_str);
600 ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature,
601 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
602
603 dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey,
604 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
605 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s to encrypt\n", dh_key_str);
606 GNUNET_asprintf (&ticket_str, "{\"meta\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}",
607 ticket_payload_str, dh_key_str, ticket_sig_str);
608 GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result);
609 GNUNET_free (dh_key_str);
610 GNUNET_free (purpose);
611 GNUNET_free (ticket_str);
612 GNUNET_free (ticket_sig_str);
613 GNUNET_free (code_payload_str);
614 GNUNET_free (enc_ticket_payload);
615 GNUNET_free (ticket_payload_str);
616 return GNUNET_OK;
617}
618
619int
620GNUNET_IDENTITY_PROVIDER_ticket_payload_parse(const char *raw_data,
621 ssize_t data_len,
622 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
623 const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey,
624 struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload **result)
625{
626 const char* label_str;
627 const char* nonce_str;
628 const char* identity_key_str;
629
630 json_t *root;
631 json_t *label_json;
632 json_t *identity_json;
633 json_t *nonce_json;
634 json_error_t err_json;
635 char* meta_str;
636 struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey;
637
638 if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
639 ecdhe_pkey,
640 raw_data,
641 data_len,
642 &meta_str))
643 {
644 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata decryption failed\n");
645 return GNUNET_SYSERR;
646 }
647
648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata: %s\n", meta_str);
649 root = json_loads (meta_str, JSON_DECODE_ANY, &err_json);
650 if (!root)
651 {
652 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
653 "Error parsing metadata: %s\n", err_json.text);
654 GNUNET_free (meta_str);
655 return GNUNET_SYSERR;
656 }
657
658 identity_json = json_object_get (root, "identity");
659 if (!json_is_string (identity_json))
660 {
661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662 "Error parsing metadata: %s\n", err_json.text);
663 json_decref (root);
664 GNUNET_free (meta_str);
665 return GNUNET_SYSERR;
666 }
667 identity_key_str = json_string_value (identity_json);
668 GNUNET_STRINGS_string_to_data (identity_key_str,
669 strlen (identity_key_str),
670 &id_pkey,
671 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
672
673
674 label_json = json_object_get (root, "label");
675 if (!json_is_string (label_json))
676 {
677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
678 "Error parsing metadata: %s\n", err_json.text);
679 json_decref (root);
680 GNUNET_free (meta_str);
681 return GNUNET_SYSERR;
682 }
683
684 label_str = json_string_value (label_json);
685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found label: %s\n", label_str);
686
687 nonce_json = json_object_get (root, "nonce");
688 if (!json_is_string (label_json))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Error parsing metadata: %s\n", err_json.text);
692 json_decref (root);
693 GNUNET_free (meta_str);
694 return GNUNET_SYSERR;
695 }
696
697 nonce_str = json_string_value (nonce_json);
698 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found nonce: %s\n", nonce_str);
699
700 *result = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
701 (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey,
702 label_str);
703 GNUNET_free (meta_str);
704 json_decref (root);
705 return GNUNET_OK;
706
707}
708
709int
710GNUNET_IDENTITY_PROVIDER_ticket_parse (const char *raw_data,
711 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
712 struct GNUNET_IDENTITY_PROVIDER_TokenTicket **result)
713{
714 const char* enc_meta_str;
715 const char* ecdh_enc_str;
716 const char* signature_enc_str;
717
718 json_t *root;
719 json_t *signature_json;
720 json_t *ecdh_json;
721 json_t *enc_meta_json;
722 json_error_t err_json;
723 char* enc_meta;
724 char* ticket_decoded;
725 char* write_ptr;
726 size_t enc_meta_len;
727 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
728 struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
729 struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *ticket_payload;
730
731 ticket_decoded = NULL;
732 GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded);
733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Token Code: %s\n", ticket_decoded);
734 root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json);
735 if (!root)
736 {
737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
738 "%s\n", err_json.text);
739 return GNUNET_SYSERR;
740 }
741
742 signature_json = json_object_get (root, "signature");
743 ecdh_json = json_object_get (root, "ecdh");
744 enc_meta_json = json_object_get (root, "meta");
745
746 signature_enc_str = json_string_value (signature_json);
747 ecdh_enc_str = json_string_value (ecdh_json);
748 enc_meta_str = json_string_value (enc_meta_json);
749
750 ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
751
752 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str,
753 strlen (ecdh_enc_str),
754 &ticket->ecdh_pubkey,
755 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)))
756 {
757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in metadata\n", ecdh_enc_str);
758 json_decref (root);
759 GNUNET_free (ticket);
760 return GNUNET_SYSERR;
761 }
762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s for metadata decryption\n", ecdh_enc_str);
763 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str,
764 strlen (signature_enc_str),
765 &ticket->signature,
766 sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
767 {
768 json_decref (root);
769 GNUNET_free (ticket_decoded);
770 GNUNET_free (ticket);
771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in metadata\n");
772 return GNUNET_SYSERR;
773 }
774
775 enc_meta_len = GNUNET_STRINGS_base64_decode (enc_meta_str,
776 strlen (enc_meta_str),
777 &enc_meta);
778
779
780 GNUNET_IDENTITY_PROVIDER_ticket_payload_parse (enc_meta,
781 enc_meta_len,
782 priv_key,
783 (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey,
784 &ticket_payload);
785
786 ticket->payload = ticket_payload;
787 //TODO: check signature here
788 purpose =
789 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
790 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
791 enc_meta_len); // E_K (code_str)
792 purpose->size =
793 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
794 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
795 enc_meta_len);
796 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
797 write_ptr = (char*) &purpose[1];
798 memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
799 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
800 memcpy (write_ptr, enc_meta, enc_meta_len);
801
802 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET,
803 purpose,
804 &ticket->signature,
805 &ticket_payload->identity_key))
806 {
807 GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
808 GNUNET_free (ticket_decoded);
809 json_decref (root);
810 GNUNET_free (purpose);
811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
812 "Error verifying signature for token code\n");
813 return GNUNET_SYSERR;
814 }
815 *result = ticket;
816 GNUNET_free (purpose);
817
818 GNUNET_free (enc_meta);
819 GNUNET_free (ticket_decoded);
820 json_decref (root);
821 return GNUNET_OK;
822
823}
824
825
826
827/* end of identity-token.c */
diff --git a/src/identity-provider/identity-token.conf b/src/identity-provider/identity-token.conf
new file mode 100644
index 000000000..f29f6cdf3
--- /dev/null
+++ b/src/identity-provider/identity-token.conf
@@ -0,0 +1,2 @@
1[identity-token]
2BINARY=gnunet-service-identity-token
diff --git a/src/identity-provider/plugin_rest_identity_token.c b/src/identity-provider/plugin_rest_identity_token.c
new file mode 100644
index 000000000..d2c1b6c5d
--- /dev/null
+++ b/src/identity-provider/plugin_rest_identity_token.c
@@ -0,0 +1,1412 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20/**
21 * @author Martin Schanzenbach
22 * @file identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_gns_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_rest_lib.h"
34#include "microhttpd.h"
35#include <jansson.h>
36#include "gnunet_signatures.h"
37#include "gnunet_identity_provider_lib.h"
38
39/**
40 * REST root namespace
41 */
42#define GNUNET_REST_API_NS_IDENTITY_TOKEN "/gnuid"
43
44/**
45 * Issue namespace
46 */
47#define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/gnuid/issue"
48
49/**
50 * Check namespace
51 */
52#define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/gnuid/check"
53
54/**
55 * Token namespace
56 */
57#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/gnuid/token"
58
59/**
60 * Authorize namespace
61 */
62#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_AUTHORIZE "/gnuid/authorize"
63
64#define GNUNET_REST_JSONAPI_IDENTITY_token_ticket "code"
65
66#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE_CODE "authorization_code"
67
68#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE "grant_type"
69
70#define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
71
72/**
73 * State while collecting all egos
74 */
75#define ID_REST_STATE_INIT 0
76
77/**
78 * Done collecting egos
79 */
80#define ID_REST_STATE_POST_INIT 1
81
82/**
83 * Resource type
84 */
85#define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
86
87/**
88 * URL parameter to create a GNUid token for a specific audience
89 */
90#define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
91
92/**
93 * URL parameter to create a GNUid token for a specific issuer (EGO)
94 */
95#define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
96
97/**
98 * Attributes passed to issue request
99 */
100#define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
101
102/**
103 * Token expiration string
104 */
105#define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
106
107/**
108 * Renew token w/ relative expirations
109 */
110#define GNUNET_IDENTITY_TOKEN_RENEW_TOKEN "renew_token"
111
112/**
113 * Error messages
114 */
115#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
116#define GNUNET_REST_ERROR_NO_DATA "No data"
117
118/**
119 * GNUid token lifetime
120 */
121#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
122
123/**
124 * The configuration handle
125 */
126const struct GNUNET_CONFIGURATION_Handle *cfg;
127
128/**
129 * HTTP methods allows for this plugin
130 */
131static char* allow_methods;
132
133/**
134 * @brief struct returned by the initialization function of the plugin
135 */
136struct Plugin
137{
138 const struct GNUNET_CONFIGURATION_Handle *cfg;
139};
140
141/**
142 * The ego list
143 */
144struct EgoEntry
145{
146 /**
147 * DLL
148 */
149 struct EgoEntry *next;
150
151 /**
152 * DLL
153 */
154 struct EgoEntry *prev;
155
156 /**
157 * Ego Identifier
158 */
159 char *identifier;
160
161 /**
162 * Public key string
163 */
164 char *keystring;
165
166 /**
167 * The Ego
168 */
169 struct GNUNET_IDENTITY_Ego *ego;
170};
171
172
173struct RequestHandle
174{
175 /**
176 * Ego list
177 */
178 struct EgoEntry *ego_head;
179
180 /**
181 * Ego list
182 */
183 struct EgoEntry *ego_tail;
184
185 /**
186 * Selected ego
187 */
188 struct EgoEntry *ego_entry;
189
190 /**
191 * Ptr to current ego private key
192 */
193 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
194
195 /**
196 * Handle to the rest connection
197 */
198 struct RestConnectionDataHandle *conndata_handle;
199
200 /**
201 * The processing state
202 */
203 int state;
204
205 /**
206 * Handle to Identity service.
207 */
208 struct GNUNET_IDENTITY_Handle *identity_handle;
209
210 /**
211 * IDENTITY Operation
212 */
213 struct GNUNET_IDENTITY_Operation *op;
214
215 /**
216 * Handle to NS service
217 */
218 struct GNUNET_NAMESTORE_Handle *ns_handle;
219
220 /**
221 * Handle to GNS service
222 */
223 struct GNUNET_GNS_Handle *gns_handle;
224
225 /**
226 * NS iterator
227 */
228 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
229
230 /**
231 * NS Handle
232 */
233 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
234
235 /**
236 * Desired timeout for the lookup (default is no timeout).
237 */
238 struct GNUNET_TIME_Relative timeout;
239
240 /**
241 * ID of a task associated with the resolution process.
242 */
243 struct GNUNET_SCHEDULER_Task * timeout_task;
244
245 /**
246 * GNS lookup
247 */
248 struct GNUNET_GNS_LookupRequest *lookup_request;
249
250 /**
251 * The plugin result processor
252 */
253 GNUNET_REST_ResultProcessor proc;
254
255 /**
256 * The closure of the result processor
257 */
258 void *proc_cls;
259
260 /**
261 * The name to look up
262 */
263 char *name;
264
265 /**
266 * The url
267 */
268 char *url;
269
270 /**
271 * The data from the REST request
272 */
273 const char* data;
274
275 /**
276 * the length of the REST data
277 */
278 size_t data_size;
279
280 /**
281 * HTTP method
282 */
283 const char* method;
284
285 /**
286 * Error response message
287 */
288 char *emsg;
289
290 /**
291 * Identity Token
292 */
293 struct GNUNET_IDENTITY_PROVIDER_Token *token;
294
295 /**
296 * Identity Token Code
297 */
298 struct GNUNET_IDENTITY_PROVIDER_TokenTicket *token_ticket;
299
300 /**
301 * Response object
302 */
303 struct JsonApiObject *resp_object;
304
305 /**
306 * ID Attribute list given
307 */
308 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
309
310
311};
312
313
314/**
315 * Cleanup lookup handle
316 * @param handle Handle to clean up
317 */
318static void
319cleanup_handle (struct RequestHandle *handle)
320{
321 struct EgoEntry *ego_entry;
322 struct EgoEntry *ego_tmp;
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "Cleaning up\n");
325 if (NULL != handle->resp_object)
326 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
327 if (NULL != handle->name)
328 GNUNET_free (handle->name);
329 if (NULL != handle->timeout_task)
330 GNUNET_SCHEDULER_cancel (handle->timeout_task);
331 if (NULL != handle->identity_handle)
332 GNUNET_IDENTITY_disconnect (handle->identity_handle);
333 if (NULL != handle->gns_handle)
334 GNUNET_GNS_disconnect (handle->gns_handle);
335 if (NULL != handle->ns_it)
336 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
337 if (NULL != handle->ns_qe)
338 GNUNET_NAMESTORE_cancel (handle->ns_qe);
339 if (NULL != handle->ns_handle)
340 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
341 if (NULL != handle->attr_map)
342 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
343 if (NULL != handle->token)
344 GNUNET_IDENTITY_PROVIDER_token_destroy (handle->token);
345 if (NULL != handle->token_ticket)
346 GNUNET_IDENTITY_PROVIDER_ticket_destroy (handle->token_ticket);
347 if (NULL != handle->url)
348 GNUNET_free (handle->url);
349 if (NULL != handle->emsg)
350 GNUNET_free (handle->emsg);
351 for (ego_entry = handle->ego_head;
352 NULL != ego_entry;)
353 {
354 ego_tmp = ego_entry;
355 ego_entry = ego_entry->next;
356 GNUNET_free (ego_tmp->identifier);
357 GNUNET_free (ego_tmp->keystring);
358 GNUNET_free (ego_tmp);
359 }
360 GNUNET_free (handle);
361}
362
363
364/**
365 * Task run on shutdown. Cleans up everything.
366 *
367 * @param cls unused
368 * @param tc scheduler context
369 */
370static void
371do_error (void *cls,
372 const struct GNUNET_SCHEDULER_TaskContext *tc)
373{
374 struct RequestHandle *handle = cls;
375 struct MHD_Response *resp;
376 char *json_error;
377
378 GNUNET_asprintf (&json_error,
379 "{Error while processing request: %s}",
380 handle->emsg);
381
382 resp = GNUNET_REST_create_json_response (json_error);
383 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
384 cleanup_handle (handle);
385 GNUNET_free (json_error);
386}
387
388/**
389 * Task run on shutdown. Cleans up everything.
390 *
391 * @param cls unused
392 * @param tc scheduler context
393 */
394static void
395do_cleanup_handle_delayed (void *cls,
396 const struct GNUNET_SCHEDULER_TaskContext *tc)
397{
398 struct RequestHandle *handle = cls;
399 cleanup_handle(handle);
400}
401
402void
403store_token_cont (void *cls,
404 int32_t success,
405 const char *emsg)
406{
407 char *result_str;
408 struct MHD_Response *resp;
409 struct RequestHandle *handle = cls;
410
411 handle->ns_qe = NULL;
412 if (GNUNET_SYSERR == success)
413 {
414 handle->emsg = GNUNET_strdup (emsg);
415 GNUNET_SCHEDULER_add_now (&do_error, handle);
416 return;
417 }
418 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
420 resp = GNUNET_REST_create_json_response (result_str);
421 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
422 GNUNET_free (result_str);
423 GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
424}
425
426
427
428
429
430
431
432
433
434/**
435 * Build a GNUid token for identity
436 * @param handle the handle
437 * @param ego_entry the ego to build the token for
438 * @param name name of the ego
439 * @param token_aud token audience
440 * @param token the resulting gnuid token
441 * @return identifier string of token (label)
442 */
443static void
444sign_and_return_token (void *cls,
445 const struct GNUNET_SCHEDULER_TaskContext *tc)
446{
447 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
448 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
449 struct GNUNET_CRYPTO_EcdsaPublicKey aud_pkey;
450 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
451 struct JsonApiResource *json_resource;
452 struct RequestHandle *handle = cls;
453 struct GNUNET_GNSRECORD_Data token_record[2];
454 struct GNUNET_HashCode key;
455 struct GNUNET_TIME_Relative etime_rel;
456 json_t *token_str;
457 json_t *name_str;
458 json_t *token_ticket_json;
459 char *lbl_str;
460 char *exp_str;
461 char *token_ticket_str;
462 char *audience;
463 char *nonce_str;
464 char *enc_token_str;
465 char *token_metadata;
466 char *scopes;
467 char* write_ptr;
468 uint64_t time;
469 uint64_t exp_time;
470 uint64_t rnd_key;
471 size_t token_metadata_len;
472
473 //Remote nonce
474 nonce_str = NULL;
475 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
476 strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
477 &key);
478 if ( GNUNET_YES !=
479 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
480 &key) )
481 {
482 handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
483 GNUNET_SCHEDULER_add_now (&do_error, handle);
484 return;
485 }
486 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
487 &key);
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
489 //Token audience
490 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
491 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
492 &key);
493 audience = NULL;
494 if ( GNUNET_YES !=
495 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
496 &key) )
497 {
498 handle->emsg = GNUNET_strdup ("Audience missing!\n");
499 GNUNET_SCHEDULER_add_now (&do_error, handle);
500 return;
501 }
502 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
503 &key);
504 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience to issue token for: %s\n", audience);
505
506 //Audience pubkey (B = bG)
507 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (audience,
508 strlen (audience),
509 &aud_pkey))
510 {
511 handle->emsg = GNUNET_strdup ("Client PKEY invalid!\n");
512 GNUNET_SCHEDULER_add_now (&do_error, handle);
513 return;
514 }
515
516
517 rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
518 GNUNET_STRINGS_base64_encode ((char*)&rnd_key, sizeof (uint64_t), &lbl_str);
519 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
520 GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
521 &pub_key);
522
523 handle->token_ticket = GNUNET_IDENTITY_PROVIDER_ticket_create (nonce_str,
524 &pub_key,
525 lbl_str,
526 &aud_pkey);
527
528 if (GNUNET_OK != GNUNET_IDENTITY_PROVIDER_ticket_serialize (handle->token_ticket,
529 priv_key,
530 &token_ticket_str))
531 {
532 handle->emsg = GNUNET_strdup ("Unable to create ref token!\n");
533 GNUNET_SCHEDULER_add_now (&do_error, handle);
534 return;
535 }
536
537 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
538 strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
539 &key);
540 //Get expiration for token from URL parameter
541 exp_str = NULL;
542 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
543 &key))
544 {
545 exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
546 &key);
547 }
548 if (NULL == exp_str) {
549 handle->emsg = GNUNET_strdup ("No expiration given!\n");
550 GNUNET_SCHEDULER_add_now (&do_error, handle);
551 return;
552 }
553
554 if (GNUNET_OK !=
555 GNUNET_STRINGS_fancy_time_to_relative (exp_str,
556 &etime_rel))
557 {
558 handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
559 GNUNET_SCHEDULER_add_now (&do_error, handle);
560 return;
561 }
562 time = GNUNET_TIME_absolute_get().abs_value_us;
563 exp_time = time + etime_rel.rel_value_us;
564
565 //json_object_set_new (handle->payload, "lbl", json_string (lbl_str));
566 GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "sub", handle->ego_entry->identifier);
567 GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "nbf", json_integer (time));
568 GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "iat", json_integer (time));
569 GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "exp", json_integer (exp_time));
570 GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "nonce", nonce_str);
571
572
573 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
574
575 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
576 lbl_str);
577 name_str = json_string (handle->ego_entry->identifier);
578 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
579 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
580 name_str);
581 json_decref (name_str);
582 token_str = json_string (enc_token_str);
583 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
584 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
585 token_str);
586 token_ticket_json = json_string (token_ticket_str);
587 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
588 GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
589 token_ticket_json);
590 GNUNET_free (token_ticket_str);
591 json_decref (token_ticket_json);
592 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
593 //Token in a serialized encrypted format
594 GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (handle->token,
595 priv_key,
596 &ecdhe_privkey,
597 &enc_token_str));
598
599 //Token record E,E_K (Token)
600 token_record[0].data = enc_token_str;
601 token_record[0].data_size = strlen (enc_token_str) + 1;
602 token_record[0].expiration_time = exp_time;
603 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
604 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
605
606
607 //Meta info
608 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
609 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
610 &key);
611
612 scopes = NULL;
613 if ( GNUNET_YES !=
614 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
615 &key) )
616 {
617 handle->emsg = GNUNET_strdup ("Scopes missing!\n");
618 GNUNET_SCHEDULER_add_now (&do_error, handle);
619 return;
620 }
621 scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
622 &key);
623
624 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
625 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
626 + strlen (scopes) + 1; //With 0-Terminator
627 token_metadata = GNUNET_malloc (token_metadata_len);
628 write_ptr = token_metadata;
629 memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
630 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
631 memcpy (write_ptr, &aud_pkey, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
632 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
633 memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
634
635 GNUNET_free (ecdhe_privkey);
636
637 token_record[1].data = token_metadata;
638 token_record[1].data_size = token_metadata_len;
639 token_record[1].expiration_time = exp_time;
640 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
641 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
642
643 //Persist token
644 handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
645 priv_key,
646 lbl_str,
647 2,
648 token_record,
649 &store_token_cont,
650 handle);
651 GNUNET_free (lbl_str);
652 GNUNET_free (enc_token_str);
653 json_decref (token_str);
654}
655
656
657
658
659
660static void
661attr_collect (void *cls,
662 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
663 const char *label,
664 unsigned int rd_count,
665 const struct GNUNET_GNSRECORD_Data *rd)
666{
667 int i;
668 char* data;
669 json_t *attr_arr;
670 struct RequestHandle *handle = cls;
671 struct GNUNET_HashCode key;
672
673 if (NULL == label)
674 {
675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
676 handle->ns_it = NULL;
677 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
678 return;
679 }
680
681 GNUNET_CRYPTO_hash (label,
682 strlen (label),
683 &key);
684
685 if (0 == rd_count ||
686 ( (NULL != handle->attr_map) &&
687 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
688 &key))
689 )
690 )
691 {
692 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
693 return;
694 }
695
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
697
698 if (1 == rd_count)
699 {
700 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
701 {
702 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
703 rd->data,
704 rd->data_size);
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
706 GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, label, data);
707 GNUNET_free (data);
708 }
709 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
710 return;
711 }
712
713 i = 0;
714 attr_arr = json_array();
715 for (; i < rd_count; i++)
716 {
717 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
718 {
719 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
720 rd[i].data,
721 rd[i].data_size);
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
723 json_array_append_new (attr_arr, json_string (data));
724 GNUNET_free (data);
725 }
726 }
727
728 if (0 < json_array_size (attr_arr))
729 {
730 GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, label, attr_arr);
731 }
732 json_decref (attr_arr);
733 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
734}
735
736
737/**
738 * Create a response with requested ego(s)
739 *
740 * @param con the Rest handle
741 * @param url the requested url
742 * @param cls the request handle
743 */
744static void
745issue_token_cont (struct RestConnectionDataHandle *con,
746 const char *url,
747 void *cls)
748{
749 const char *egoname;
750 char *ego_val;
751 char *audience;
752 struct RequestHandle *handle = cls;
753 struct EgoEntry *ego_entry;
754 struct GNUNET_HashCode key;
755 struct MHD_Response *resp;
756 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
757 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
758 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
759
760 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
761 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
762 {
763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
764 resp = GNUNET_REST_create_json_response (NULL);
765 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
766 cleanup_handle (handle);
767 return;
768 }
769
770 egoname = NULL;
771 ego_entry = NULL;
772 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
773 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
774 &key);
775 if ( GNUNET_YES ==
776 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
777 &key) )
778 {
779 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
780 &key);
781 if (NULL == ego_val)
782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
783 if (NULL != ego_val)
784 {
785 for (ego_entry = handle->ego_head;
786 NULL != ego_entry;
787 ego_entry = ego_entry->next)
788 {
789 if (0 != strcmp (ego_val, ego_entry->identifier))
790 continue;
791 egoname = ego_entry->identifier;
792 break;
793 }
794 if (NULL == egoname || NULL == ego_entry)
795 {
796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
797 resp = GNUNET_REST_create_json_response (NULL);
798 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
799 cleanup_handle (handle);
800 return;
801 }
802 }
803 }
804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
805 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
806 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
807 &key);
808
809 //Token audience
810 audience = NULL;
811 if ( GNUNET_YES !=
812 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
813 &key) )
814 {
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
816 resp = GNUNET_REST_create_json_response (NULL);
817 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
818 cleanup_handle (handle);
819 return;
820 }
821 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
822 &key);
823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
824
825 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
826 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
827 &pub_key);
828 GNUNET_STRINGS_string_to_data (audience,
829 strlen (audience),
830 &aud_key,
831 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
832 handle->token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
833 aud_key);
834 GNUNET_free (aud_key);
835
836
837 //Get identity attributes
838 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
839 handle->ego_entry = ego_entry;
840 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
841 priv_key,
842 &attr_collect,
843 handle);
844}
845
846
847/**
848 * Build a GNUid token for identity
849 * @param handle the handle
850 * @param ego_entry the ego to build the token for
851 * @param name name of the ego
852 * @param token_aud token audience
853 * @param token the resulting gnuid token
854 * @return identifier string of token (label)
855 */
856static void
857return_token_list (void *cls,
858 const struct GNUNET_SCHEDULER_TaskContext *tc)
859{
860 char* result_str;
861 struct RequestHandle *handle = cls;
862 struct MHD_Response *resp;
863
864 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
866 resp = GNUNET_REST_create_json_response (result_str);
867 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
868 GNUNET_free (result_str);
869 cleanup_handle (handle);
870}
871
872/**
873 * Collect all tokens for ego
874 */
875static void
876token_collect (void *cls,
877 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
878 const char *label,
879 unsigned int rd_count,
880 const struct GNUNET_GNSRECORD_Data *rd)
881{
882 int i;
883 char* data;
884 struct RequestHandle *handle = cls;
885 struct EgoEntry *ego_tmp;
886 struct JsonApiResource *json_resource;
887 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
888 json_t *issuer;
889 json_t *token;
890
891 if (NULL == label)
892 {
893 ego_tmp = handle->ego_head;
894 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
895 handle->ego_tail,
896 ego_tmp);
897 GNUNET_free (ego_tmp->identifier);
898 GNUNET_free (ego_tmp->keystring);
899 GNUNET_free (ego_tmp);
900
901 if (NULL == handle->ego_head)
902 {
903 //Done
904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
905 handle->ns_it = NULL;
906 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
907 return;
908 }
909
910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
911 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
912 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
913 priv_key,
914 &token_collect,
915 handle);
916 return;
917 }
918
919 for (i = 0; i < rd_count; i++)
920 {
921 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
922 {
923 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
924 rd[i].data,
925 rd[i].data_size);
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
927 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
928 label);
929 issuer = json_string (handle->ego_head->identifier);
930 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
931 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
932 issuer);
933 json_decref (issuer);
934 token = json_string (data);
935 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
936 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
937 token);
938 json_decref (token);
939
940 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
941 GNUNET_free (data);
942 }
943 }
944
945 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
946}
947
948
949
950/**
951 * Respond to OPTIONS request
952 *
953 * @param con_handle the connection handle
954 * @param url the url
955 * @param cls the RequestHandle
956 */
957static void
958list_token_cont (struct RestConnectionDataHandle *con_handle,
959 const char* url,
960 void *cls)
961{
962 char* ego_val;
963 struct GNUNET_HashCode key;
964 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
965 struct RequestHandle *handle = cls;
966 struct EgoEntry *ego_entry;
967 struct EgoEntry *ego_tmp;
968
969 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
970 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
971 &key);
972
973 if ( GNUNET_YES ==
974 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
975 &key) )
976 {
977 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
978 &key);
979 //Remove non-matching egos
980 for (ego_entry = handle->ego_head;
981 NULL != ego_entry;)
982 {
983 ego_tmp = ego_entry;
984 ego_entry = ego_entry->next;
985 if (0 != strcmp (ego_val, ego_tmp->identifier))
986 {
987 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
988 handle->ego_tail,
989 ego_tmp);
990 GNUNET_free (ego_tmp->identifier);
991 GNUNET_free (ego_tmp->keystring);
992 GNUNET_free (ego_tmp);
993 }
994 }
995 }
996 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
997 if (NULL == handle->ego_head)
998 {
999 //Done
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
1001 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
1002 return;
1003 }
1004 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1005 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1006 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
1007 priv_key,
1008 &token_collect,
1009 handle);
1010
1011}
1012
1013
1014
1015
1016static void
1017process_lookup_result (void *cls, uint32_t rd_count,
1018 const struct GNUNET_GNSRECORD_Data *rd)
1019{
1020 struct RequestHandle *handle = cls;
1021 json_t *root;
1022 struct MHD_Response *resp;
1023 char *result;
1024 char* token_str;
1025 char* record_str;
1026
1027 handle->lookup_request = NULL;
1028 if (2 != rd_count)
1029 {
1030 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1031 "Number of tokens %d != 2.",
1032 rd_count);
1033 handle->emsg = GNUNET_strdup ("Number of tokens != 2.");
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1035 return;
1036 }
1037
1038 root = json_object();
1039 record_str =
1040 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1041 rd->data,
1042 rd->data_size);
1043
1044 //Decrypt and parse
1045 GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_parse (record_str,
1046 handle->priv_key,
1047 &handle->token));
1048
1049 //Readable
1050 GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (handle->token,
1051 handle->priv_key,
1052 &token_str));
1053
1054 json_object_set_new (root, "access_token", json_string (token_str));
1055 json_object_set_new (root, "token_type", json_string ("gnuid"));
1056 GNUNET_free (token_str);
1057 GNUNET_free (record_str);
1058
1059 result = json_dumps (root, JSON_INDENT(1));
1060 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", result);
1061 resp = GNUNET_REST_create_json_response (result);
1062 GNUNET_free (result);
1063 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1064 cleanup_handle (handle);
1065 json_decref (root);
1066}
1067
1068
1069static void
1070exchange_token_ticket_cb (void *cls,
1071 struct GNUNET_IDENTITY_Ego *ego,
1072 void **ctx,
1073 const char *name)
1074{
1075 struct RequestHandle *handle = cls;
1076 struct GNUNET_HashCode key;
1077 char* code;
1078 char* lookup_query;
1079
1080 handle->op = NULL;
1081
1082 if (NULL == ego)
1083 {
1084 handle->emsg = GNUNET_strdup ("No GNS identity found.");
1085 GNUNET_SCHEDULER_add_now (&do_error, handle);
1086 return;
1087 }
1088
1089 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
1090 strlen (GNUNET_REST_JSONAPI_IDENTITY_token_ticket),
1091 &key);
1092
1093 if ( GNUNET_NO ==
1094 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1095 &key) )
1096 {
1097 handle->emsg = GNUNET_strdup ("No code given.");
1098 GNUNET_SCHEDULER_add_now (&do_error, handle);
1099 return;
1100 }
1101 code = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1102 &key);
1103
1104 handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
1105
1106 if (GNUNET_SYSERR == GNUNET_IDENTITY_PROVIDER_ticket_parse (code,
1107 handle->priv_key,
1108 &handle->token_ticket))
1109 {
1110 handle->emsg = GNUNET_strdup ("Error extracting values from token code.");
1111 GNUNET_SCHEDULER_add_now (&do_error, handle);
1112 return;
1113 }
1114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
1115 handle->token_ticket->payload->label);
1116 handle->gns_handle = GNUNET_GNS_connect (cfg);
1117 GNUNET_asprintf (&lookup_query, "%s.gnu", handle->token_ticket->payload->label);
1118 handle->lookup_request = GNUNET_GNS_lookup (handle->gns_handle,
1119 lookup_query,
1120 &handle->token_ticket->payload->identity_key,
1121 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1122 GNUNET_GNS_LO_LOCAL_MASTER,
1123 NULL,
1124 &process_lookup_result,
1125 handle);
1126 GNUNET_free (lookup_query);
1127}
1128
1129/**
1130 * Respond to OAuth2 /token request
1131 *
1132 * @param con_handle the connection handle
1133 * @param url the url
1134 * @param cls the RequestHandle
1135 */
1136static void
1137exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
1138 const char* url,
1139 void *cls)
1140{
1141 struct RequestHandle *handle = cls;
1142 char* grant_type;
1143 struct GNUNET_HashCode key;
1144
1145 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE,
1146 strlen (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE),
1147 &key);
1148
1149 if ( GNUNET_YES ==
1150 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1151 &key) )
1152 {
1153 grant_type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1154 &key);
1155 }
1156
1157 if (0 == strcmp ("authorization_code", grant_type)) {
1158 //Get token from GNS
1159 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
1160 "gns-master",
1161 &exchange_token_ticket_cb,
1162 handle);
1163 }
1164
1165 //TODO fail here
1166}
1167
1168/**
1169 * Respond to OPTIONS request
1170 *
1171 * @param con_handle the connection handle
1172 * @param url the url
1173 * @param cls the RequestHandle
1174 */
1175static void
1176options_cont (struct RestConnectionDataHandle *con_handle,
1177 const char* url,
1178 void *cls)
1179{
1180 struct MHD_Response *resp;
1181 struct RequestHandle *handle = cls;
1182
1183 //For now, independent of path return all options
1184 resp = GNUNET_REST_create_json_response (NULL);
1185 MHD_add_response_header (resp,
1186 "Access-Control-Allow-Methods",
1187 allow_methods);
1188 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1189 cleanup_handle (handle);
1190 return;
1191}
1192
1193/**
1194 * Handle rest request
1195 *
1196 * @param handle the request handle
1197 */
1198static void
1199init_cont (struct RequestHandle *handle)
1200{
1201 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
1202 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
1203 //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
1204 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN, &list_token_cont},
1205 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_TOKEN, &options_cont},
1206 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
1207 GNUNET_REST_HANDLER_END
1208 };
1209
1210 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
1211 {
1212 handle->emsg = GNUNET_strdup ("Request unsupported");
1213 GNUNET_SCHEDULER_add_now (&do_error, handle);
1214 }
1215}
1216
1217/**
1218 * If listing is enabled, prints information about the egos.
1219 *
1220 * This function is initially called for all egos and then again
1221 * whenever a ego's identifier changes or if it is deleted. At the
1222 * end of the initial pass over all egos, the function is once called
1223 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1224 * be invoked in the future or that there was an error.
1225 *
1226 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1227 * this function is only called ONCE, and 'NULL' being passed in
1228 * 'ego' does indicate an error (i.e. name is taken or no default
1229 * value is known). If 'ego' is non-NULL and if '*ctx'
1230 * is set in those callbacks, the value WILL be passed to a subsequent
1231 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1232 * that one was not NULL).
1233 *
1234 * When an identity is renamed, this function is called with the
1235 * (known) ego but the NEW identifier.
1236 *
1237 * When an identity is deleted, this function is called with the
1238 * (known) ego and "NULL" for the 'identifier'. In this case,
1239 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1240 * cleaned up).
1241 *
1242 * @param cls closure
1243 * @param ego ego handle
1244 * @param ctx context for application to store data for this ego
1245 * (during the lifetime of this process, initially NULL)
1246 * @param identifier identifier assigned by the user for this ego,
1247 * NULL if the user just deleted the ego and it
1248 * must thus no longer be used
1249 */
1250static void
1251list_ego (void *cls,
1252 struct GNUNET_IDENTITY_Ego *ego,
1253 void **ctx,
1254 const char *identifier)
1255{
1256 struct RequestHandle *handle = cls;
1257 struct EgoEntry *ego_entry;
1258 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1259
1260 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1261 {
1262 handle->state = ID_REST_STATE_POST_INIT;
1263 init_cont (handle);
1264 return;
1265 }
1266 if (ID_REST_STATE_INIT == handle->state) {
1267 ego_entry = GNUNET_new (struct EgoEntry);
1268 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1269 ego_entry->keystring =
1270 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1271 ego_entry->ego = ego;
1272 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1273 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1274 }
1275
1276}
1277
1278/**
1279 * Function processing the REST call
1280 *
1281 * @param method HTTP method
1282 * @param url URL of the HTTP request
1283 * @param data body of the HTTP request (optional)
1284 * @param data_size length of the body
1285 * @param proc callback function for the result
1286 * @param proc_cls closure for callback function
1287 * @return GNUNET_OK if request accepted
1288 */
1289static void
1290rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1291 GNUNET_REST_ResultProcessor proc,
1292 void *proc_cls)
1293{
1294 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1295 struct GNUNET_HashCode key;
1296 char* attr_list;
1297 char* attr_list_tmp;
1298 char* attr;
1299
1300 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
1301 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
1302 &key);
1303
1304 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1305
1306 handle->proc_cls = proc_cls;
1307 handle->proc = proc;
1308 handle->state = ID_REST_STATE_INIT;
1309 handle->conndata_handle = conndata_handle;
1310 handle->data = conndata_handle->data;
1311 handle->data_size = conndata_handle->data_size;
1312 handle->method = conndata_handle->method;
1313 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1314 &key))
1315 {
1316 handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1317 GNUNET_NO);
1318 attr_list = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1319 &key);
1320 if (NULL != attr_list)
1321 {
1322 attr_list_tmp = GNUNET_strdup (attr_list);
1323 attr = strtok(attr_list_tmp, ",");
1324 for (; NULL != attr; attr = strtok (NULL, ","))
1325 {
1326 GNUNET_CRYPTO_hash (attr,
1327 strlen (attr),
1328 &key);
1329 GNUNET_CONTAINER_multihashmap_put (handle->attr_map,
1330 &key,
1331 attr,
1332 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1333 }
1334 GNUNET_free (attr_list_tmp);
1335 }
1336 }
1337
1338
1339 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1340 if (handle->url[strlen (handle->url)-1] == '/')
1341 handle->url[strlen (handle->url)-1] = '\0';
1342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343 "Connecting...\n");
1344 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1345 &list_ego,
1346 handle);
1347 handle->timeout_task =
1348 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1349 &do_error,
1350 handle);
1351
1352
1353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354 "Connected\n");
1355}
1356
1357/**
1358 * Entry point for the plugin.
1359 *
1360 * @param cls Config info
1361 * @return NULL on error, otherwise the plugin context
1362 */
1363void *
1364libgnunet_plugin_rest_identity_token_init (void *cls)
1365{
1366 static struct Plugin plugin;
1367 struct GNUNET_REST_Plugin *api;
1368
1369 cfg = cls;
1370 if (NULL != plugin.cfg)
1371 return NULL; /* can only initialize once! */
1372 memset (&plugin, 0, sizeof (struct Plugin));
1373 plugin.cfg = cfg;
1374 api = GNUNET_new (struct GNUNET_REST_Plugin);
1375 api->cls = &plugin;
1376 api->name = GNUNET_REST_API_NS_IDENTITY_TOKEN;
1377 api->process_request = &rest_identity_process_request;
1378 GNUNET_asprintf (&allow_methods,
1379 "%s, %s, %s, %s, %s",
1380 MHD_HTTP_METHOD_GET,
1381 MHD_HTTP_METHOD_POST,
1382 MHD_HTTP_METHOD_PUT,
1383 MHD_HTTP_METHOD_DELETE,
1384 MHD_HTTP_METHOD_OPTIONS);
1385
1386 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1387 _("Identity Token REST API initialized\n"));
1388 return api;
1389}
1390
1391
1392/**
1393 * Exit point from the plugin.
1394 *
1395 * @param cls the plugin context (as returned by "init")
1396 * @return always NULL
1397 */
1398void *
1399libgnunet_plugin_rest_identity_token_done (void *cls)
1400{
1401 struct GNUNET_REST_Plugin *api = cls;
1402 struct Plugin *plugin = api->cls;
1403
1404 plugin->cfg = NULL;
1405 GNUNET_free_non_null (allow_methods);
1406 GNUNET_free (api);
1407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1408 "Identity Token REST plugin is finished\n");
1409 return NULL;
1410}
1411
1412/* end of plugin_rest_gns.c */