aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2015-11-19 12:18:35 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2015-11-19 12:18:35 +0000
commitefa9efe25cb84be8cd0f3fb3d545ee6ef7298891 (patch)
treef0682a8b1e77b7c2da776fee0da5f5e8e5407430 /src
parentad0201797ed84806a0a42fe3435dd56bd2c69ae5 (diff)
downloadgnunet-efa9efe25cb84be8cd0f3fb3d545ee6ef7298891.tar.gz
gnunet-efa9efe25cb84be8cd0f3fb3d545ee6ef7298891.zip
-add identity token service
Diffstat (limited to 'src')
-rw-r--r--src/identity-token/Makefile.am14
-rw-r--r--src/identity-token/gnunet-service-identity-token.c453
-rw-r--r--src/identity-token/identity-token.conf1
3 files changed, 468 insertions, 0 deletions
diff --git a/src/identity-token/Makefile.am b/src/identity-token/Makefile.am
index b7ea00bf0..8ada7667f 100644
--- a/src/identity-token/Makefile.am
+++ b/src/identity-token/Makefile.am
@@ -27,6 +27,20 @@ endif
27bin_PROGRAMS = \ 27bin_PROGRAMS = \
28 gnunet-identity-token 28 gnunet-identity-token
29 29
30libexec_PROGRAMS = \
31 gnunet-service-identity-token
32
33gnunet_service_identity_token_SOURCES = \
34 gnunet-service-identity-token.c
35
36gnunet_service_identity_token_LDADD = \
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
30libgnunet_plugin_rest_identity_token_la_SOURCES = \ 44libgnunet_plugin_rest_identity_token_la_SOURCES = \
31 plugin_rest_identity_token.c 45 plugin_rest_identity_token.c
32libgnunet_plugin_rest_identity_token_la_LIBADD = \ 46libgnunet_plugin_rest_identity_token_la_LIBADD = \
diff --git a/src/identity-token/gnunet-service-identity-token.c b/src/identity-token/gnunet-service-identity-token.c
new file mode 100644
index 000000000..62999f2f4
--- /dev/null
+++ b/src/identity-token/gnunet-service-identity-token.c
@@ -0,0 +1,453 @@
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
34#define STATE_INIT 0
35
36#define STATE_POST_INIT 1
37
38#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
39
40static int state;
41
42static struct EgoEntry *ego_head;
43
44static struct EgoEntry *ego_tail;
45
46static struct GNUNET_IDENTITY_Handle *identity_handle;
47
48static struct GNUNET_NAMESTORE_Handle *ns_handle;
49
50static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
51
52static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
53
54static struct GNUNET_SCHEDULER_Task * timeout_task;
55
56static struct GNUNET_SCHEDULER_Task * update_task;
57
58static struct GNUNET_TIME_Relative min_rel_exp;
59
60static char* token;
61
62static char* label;
63
64struct EgoEntry
65{
66 struct EgoEntry *next;
67 struct EgoEntry *prev;
68 struct GNUNET_IDENTITY_Ego *ego;
69};
70
71/**
72 * Our configuration.
73 */
74static const struct GNUNET_CONFIGURATION_Handle *cfg;
75
76static void
77store_token_cont (void *cls,
78 int32_t success,
79 const char *emsg)
80{
81 ns_qe = NULL;
82 if (GNUNET_SYSERR == success)
83 {
84 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
85 "Failed to update token: %s\n",
86 emsg);
87 return;
88 }
89 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Next token\n");
90 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
91}
92
93static void
94handle_token_update (void *cls,
95 const struct GNUNET_SCHEDULER_TaskContext *tc)
96{
97 char *token_header;
98 char *token_payload;
99 char *token_payload_json;
100 char *new_token;
101 char *new_payload_str;
102 char *new_payload_base64;
103 char *sig_str;
104 char *key;
105 char *padding;
106 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
107 struct EgoEntry *ego_entry = cls;
108 struct GNUNET_GNSRECORD_Data token_record;
109 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
110 struct GNUNET_CRYPTO_EcdsaSignature sig;
111 struct GNUNET_TIME_Relative token_rel_exp;
112 struct GNUNET_TIME_Relative token_ttl;
113 struct GNUNET_TIME_Absolute token_exp;
114 struct GNUNET_TIME_Absolute token_nbf;
115 struct GNUNET_TIME_Absolute new_exp;
116 struct GNUNET_TIME_Absolute new_iat;
117 struct GNUNET_TIME_Absolute new_nbf;
118 json_t *payload_json;
119 json_t *value;
120 json_t *new_payload_json;
121 json_t *token_nbf_json;
122 json_t *token_exp_json;
123 json_error_t json_err;
124
125 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
126
127 //Note: We need the token expiration time here. Not the record expiration
128 //time.
129 //There are two types of tokens: Token that expire on GNS level with
130 //an absolute expiration time. Those are basically tokens that will
131 //be automatically revoked on (record)expiration.
132 //Tokens stored with relative expiration times will expire on the token level (token expiration)
133 //but this service will reissue new tokens that can be retrieved from GNS
134 //automatically.
135
136 token_header = strtok (token, ".");
137
138 token_payload = strtok (NULL, ".");
139
140 GNUNET_STRINGS_base64_decode (token_payload,
141 strlen (token_payload),
142 &token_payload_json);
143
144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Payload: %s\n",
145 token_payload_json);
146 payload_json = json_loads (token_payload_json, JSON_DECODE_ANY, &json_err);
147 GNUNET_free (token_payload_json);
148
149 token_exp_json = json_object_get (payload_json, "exp");
150 token_nbf_json = json_object_get (payload_json, "nbf");
151 token_exp.abs_value_us = json_integer_value(token_exp_json);
152 token_nbf.abs_value_us = json_integer_value(token_nbf_json);
153 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
154
155 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
156 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
157 {
158 //This token is not yet expired! Save and skip
159 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
160 {
161 min_rel_exp = token_ttl;
162 }
163 json_decref (payload_json);
164 GNUNET_free (token);
165 token = NULL;
166 GNUNET_free (label);
167 label = NULL;
168 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
169 return;
170 }
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
172 "Token is expired. Create a new one\n");
173 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
174 new_nbf = GNUNET_TIME_absolute_get ();
175 new_iat = new_nbf;
176 new_payload_json = json_object();
177 json_object_foreach(payload_json, key, value) {
178 if (0 == strcmp (key, "exp"))
179 {
180 json_object_set_new (new_payload_json, key, json_integer (new_exp.abs_value_us));
181 }
182 else if (0 == strcmp (key, "nbf"))
183 {
184 json_object_set_new (new_payload_json, key, json_integer (new_nbf.abs_value_us));
185 }
186 else if (0 == strcmp (key, "iat"))
187 {
188 json_object_set_new (new_payload_json, key, json_integer (new_iat.abs_value_us));
189 }
190 else {
191 json_object_set_new (new_payload_json, key, value);
192 }
193 }
194 json_decref (payload_json);
195
196 // reassemble and set
197 new_payload_str = json_dumps (new_payload_json, JSON_COMPACT);
198 json_decref (new_payload_json);
199 GNUNET_STRINGS_base64_encode (new_payload_str,
200 strlen (new_payload_str),
201 &new_payload_base64);
202 //Remove padding
203 padding = strtok(new_payload_base64, "=");
204 while (NULL != padding)
205 padding = strtok(NULL, "=");
206
207 GNUNET_asprintf (&new_token, "%s,%s", token_header, new_payload_base64);
208 purpose =
209 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
210 strlen (new_token));
211 purpose->size =
212 htonl (strlen (new_token) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
213 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
214 memcpy (&purpose[1], new_token, strlen (new_token));
215 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
216 purpose,
217 &sig))
218 GNUNET_break(0);
219 GNUNET_free (new_token);
220 sig_str = GNUNET_STRINGS_data_to_string_alloc (&sig,
221 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
222 GNUNET_asprintf (&new_token, "%s.%s.%s",
223 token_header, new_payload_base64, sig_str);
224 GNUNET_free (sig_str);
225 GNUNET_free (new_payload_str);
226 GNUNET_free (new_payload_base64);
227 GNUNET_free (purpose);
228
229 token_record.data = new_token;
230 token_record.data_size = strlen (new_token);
231 token_record.expiration_time = new_exp.abs_value_us;
232 token_record.record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
233 token_record.flags = GNUNET_GNSRECORD_RF_NONE | GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
234 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
235 priv_key,
236 label,
237 1,
238 &token_record,
239 &store_token_cont,
240 ego_entry);
241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Updating Token w/ %s\n", new_token);
242 GNUNET_free (new_token);
243 GNUNET_free (token);
244 token = NULL;
245 GNUNET_free (label);
246 label = NULL;
247}
248
249static void
250update_identities(void *cls,
251 const struct GNUNET_SCHEDULER_TaskContext *tc);
252
253static void
254token_collect (void *cls,
255 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
256 const char *lbl,
257 unsigned int rd_count,
258 const struct GNUNET_GNSRECORD_Data *rd)
259{
260 struct EgoEntry *ego_entry = cls;
261
262 if (NULL == lbl)
263 {
264 //Done
265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
266 ">>> Updating Ego finished\n");
267 GNUNET_SCHEDULER_add_now (&update_identities, ego_entry->next);
268 return;
269 }
270
271 //TODO autopurge expired tokens here if set in config
272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Found record\n");
273 //There should be only a single record for a token under a label
274 if (1 != rd_count || (rd->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN))
275 {
276 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
277 return;
278 }
279 token = GNUNET_GNSRECORD_value_to_string (rd->record_type,
280 rd->data,
281 rd->data_size);
282 label = GNUNET_strdup (lbl);
283 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Got token: %s\n", token);
284
285 GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
286}
287
288
289
290static void
291update_identities(void *cls,
292 const struct GNUNET_SCHEDULER_TaskContext *tc)
293{
294 struct EgoEntry *next_ego = cls;
295 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
296 if (NULL == next_ego)
297 {
298 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
299 min_rel_exp = MIN_WAIT_TIME;
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Finished. Rescheduling in %d\n", min_rel_exp.rel_value_us);
301 ns_it = NULL;
302 //finished -> TODO reschedule
303 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
304 &update_identities,
305 ego_head);
306 return;
307 }
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Updating Ego\n");
309 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
310 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
311 priv_key,
312 &token_collect,
313 next_ego);
314}
315
316
317/* ************************* Global helpers ********************* */
318
319static void
320init_cont ()
321{
322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ">>> Starting Service\n");
323 //Initially iterate all itenties and refresh all tokens
324 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
325}
326
327static void
328list_ego (void *cls,
329 struct GNUNET_IDENTITY_Ego *ego,
330 void **ctx,
331 const char *identifier)
332{
333 struct EgoEntry *new_entry;
334 if ((NULL == ego) && (STATE_INIT == state))
335 {
336 state = STATE_POST_INIT;
337 init_cont ();
338 return;
339 }
340 if (STATE_INIT == state) {
341 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
342 new_entry->ego = ego;
343 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
344 }
345}
346
347static void
348cleanup()
349{
350 struct EgoEntry *ego_entry;
351 struct EgoEntry *ego_tmp;
352
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Cleaning up\n");
355 if (NULL != timeout_task)
356 GNUNET_SCHEDULER_cancel (timeout_task);
357 if (NULL != update_task)
358 GNUNET_SCHEDULER_cancel (update_task);
359 if (NULL != identity_handle)
360 GNUNET_IDENTITY_disconnect (identity_handle);
361 if (NULL != ns_it)
362 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
363 if (NULL != ns_qe)
364 GNUNET_NAMESTORE_cancel (ns_qe);
365 if (NULL != ns_handle)
366 GNUNET_NAMESTORE_disconnect (ns_handle);
367 if (NULL != token)
368 GNUNET_free (token);
369 if (NULL != label)
370 GNUNET_free (label);
371
372 for (ego_entry = ego_head;
373 NULL != ego_entry;)
374 {
375 ego_tmp = ego_entry;
376 ego_entry = ego_entry->next;
377 GNUNET_free (ego_tmp);
378 }
379}
380
381static void
382do_shutdown (void *cls,
383 const struct GNUNET_SCHEDULER_TaskContext *tc)
384{
385 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
386 "Shutting down...\n");
387 cleanup();
388}
389
390/**
391 * Main function that will be run
392 *
393 * @param cls closure
394 * @param args remaining command-line arguments
395 * @param cfgfile name of the configuration file used (for saving, can be NULL)
396 * @param c configuration
397 */
398static void
399run (void *cls,
400 char *const *args,
401 const char *cfgfile,
402 const struct GNUNET_CONFIGURATION_Handle *c)
403{
404 cfg = c;
405
406
407 //Connect to identity and namestore services
408 ns_handle = GNUNET_NAMESTORE_connect (cfg);
409 if (NULL == ns_handle)
410 {
411 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connectin to namestore");
412 }
413
414 identity_handle = GNUNET_IDENTITY_connect (cfg,
415 &list_ego,
416 NULL);
417
418 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
419 &do_shutdown, NULL);
420}
421
422
423/**
424 *
425 * The main function for gnunet-service-identity-token
426 *
427 * @param argc number of arguments from the cli
428 * @param argv command line arguments
429 * @return 0 ok, 1 on error
430 *
431 */
432int
433main (int argc, char *const *argv)
434{
435 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
436 GNUNET_GETOPT_OPTION_END
437 };
438 int ret;
439
440 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
441 return 2;
442 GNUNET_log_setup ("gnunet-service-identity-token", "WARNING", NULL);
443 ret =
444 (GNUNET_OK ==
445 GNUNET_PROGRAM_run (argc, argv, "gnunet-service-identity-token",
446 _("GNUnet identity token service"),
447 options,
448 &run, NULL)) ? 0: 1;
449 GNUNET_free_non_null ((char *) argv);
450 return ret;
451}
452
453/* end of gnunet-rest-server.c */
diff --git a/src/identity-token/identity-token.conf b/src/identity-token/identity-token.conf
index f40b77e19..f29f6cdf3 100644
--- a/src/identity-token/identity-token.conf
+++ b/src/identity-token/identity-token.conf
@@ -1 +1,2 @@
1[identity-token] 1[identity-token]
2BINARY=gnunet-service-identity-token