diff options
author | Martin Schanzenbach <mschanzenbach@posteo.de> | 2015-11-19 12:18:35 +0000 |
---|---|---|
committer | Martin Schanzenbach <mschanzenbach@posteo.de> | 2015-11-19 12:18:35 +0000 |
commit | efa9efe25cb84be8cd0f3fb3d545ee6ef7298891 (patch) | |
tree | f0682a8b1e77b7c2da776fee0da5f5e8e5407430 /src | |
parent | ad0201797ed84806a0a42fe3435dd56bd2c69ae5 (diff) | |
download | gnunet-efa9efe25cb84be8cd0f3fb3d545ee6ef7298891.tar.gz gnunet-efa9efe25cb84be8cd0f3fb3d545ee6ef7298891.zip |
-add identity token service
Diffstat (limited to 'src')
-rw-r--r-- | src/identity-token/Makefile.am | 14 | ||||
-rw-r--r-- | src/identity-token/gnunet-service-identity-token.c | 453 | ||||
-rw-r--r-- | src/identity-token/identity-token.conf | 1 |
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 | |||
27 | bin_PROGRAMS = \ | 27 | bin_PROGRAMS = \ |
28 | gnunet-identity-token | 28 | gnunet-identity-token |
29 | 29 | ||
30 | libexec_PROGRAMS = \ | ||
31 | gnunet-service-identity-token | ||
32 | |||
33 | gnunet_service_identity_token_SOURCES = \ | ||
34 | gnunet-service-identity-token.c | ||
35 | |||
36 | gnunet_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 | |||
30 | libgnunet_plugin_rest_identity_token_la_SOURCES = \ | 44 | libgnunet_plugin_rest_identity_token_la_SOURCES = \ |
31 | plugin_rest_identity_token.c | 45 | plugin_rest_identity_token.c |
32 | libgnunet_plugin_rest_identity_token_la_LIBADD = \ | 46 | libgnunet_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 | |||
40 | static int state; | ||
41 | |||
42 | static struct EgoEntry *ego_head; | ||
43 | |||
44 | static struct EgoEntry *ego_tail; | ||
45 | |||
46 | static struct GNUNET_IDENTITY_Handle *identity_handle; | ||
47 | |||
48 | static struct GNUNET_NAMESTORE_Handle *ns_handle; | ||
49 | |||
50 | static struct GNUNET_NAMESTORE_QueueEntry *ns_qe; | ||
51 | |||
52 | static struct GNUNET_NAMESTORE_ZoneIterator *ns_it; | ||
53 | |||
54 | static struct GNUNET_SCHEDULER_Task * timeout_task; | ||
55 | |||
56 | static struct GNUNET_SCHEDULER_Task * update_task; | ||
57 | |||
58 | static struct GNUNET_TIME_Relative min_rel_exp; | ||
59 | |||
60 | static char* token; | ||
61 | |||
62 | static char* label; | ||
63 | |||
64 | struct EgoEntry | ||
65 | { | ||
66 | struct EgoEntry *next; | ||
67 | struct EgoEntry *prev; | ||
68 | struct GNUNET_IDENTITY_Ego *ego; | ||
69 | }; | ||
70 | |||
71 | /** | ||
72 | * Our configuration. | ||
73 | */ | ||
74 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
75 | |||
76 | static void | ||
77 | store_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 | |||
93 | static void | ||
94 | handle_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 | |||
249 | static void | ||
250 | update_identities(void *cls, | ||
251 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
252 | |||
253 | static void | ||
254 | token_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 | |||
290 | static void | ||
291 | update_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 | |||
319 | static void | ||
320 | init_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 | |||
327 | static void | ||
328 | list_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 | |||
347 | static void | ||
348 | cleanup() | ||
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 | |||
381 | static void | ||
382 | do_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 | */ | ||
398 | static void | ||
399 | run (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 | */ | ||
432 | int | ||
433 | main (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] |
2 | BINARY=gnunet-service-identity-token | ||