2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @author Martin Schanzenbach
22 * @file src/identity-provider/gnunet-service-identity-provider.c
23 * @brief Identity Token Service
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_gns_service.h"
36 #include "gnunet_signatures.h"
37 #include "identity_provider.h"
38 #include "identity_token.h"
46 * Normal operation state
48 #define STATE_POST_INIT 1
51 * Minimum interval between updates
53 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
56 * Standard token expiration time
58 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
61 * Service state (to detect initial update pass)
66 * Head of ego entry DLL
68 static struct EgoEntry *ego_head;
71 * Tail of ego entry DLL
73 static struct EgoEntry *ego_tail;
78 static struct GNUNET_IDENTITY_Handle *identity_handle;
81 * Token expiration interval
83 static struct GNUNET_TIME_Relative token_expiration_interval;
88 static struct GNUNET_NAMESTORE_Handle *ns_handle;
93 static struct GNUNET_GNS_Handle *gns_handle;
98 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
103 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
108 static struct GNUNET_SCHEDULER_Task * timeout_task;
114 static struct GNUNET_SCHEDULER_Task * update_task;
117 * Timeout for next update pass
119 static struct GNUNET_TIME_Relative min_rel_exp;
123 * Currently processed token
125 static struct IdentityToken *token;
128 * Label for currently processed token
133 * Scopes for processed token
138 * Expiration for processed token
140 static uint64_t rd_exp;
143 * ECDHE Privkey for processed token metadata
145 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
148 * Handle to the statistics service.
150 static struct GNUNET_STATISTICS_Handle *stats;
153 * Notification context, simplifies client broadcasts.
155 static struct GNUNET_SERVER_NotificationContext *nc;
160 static const struct GNUNET_CONFIGURATION_Handle *cfg;
163 struct ExchangeHandle
169 struct GNUNET_SERVER_Client *client;
174 struct TokenTicket *ticket;
179 struct IdentityToken *token;
184 struct GNUNET_GNS_LookupRequest *lookup_request;
189 struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
203 struct GNUNET_SERVER_Client *client;
208 struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
213 struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
218 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
223 struct GNUNET_TIME_Absolute expiration;
238 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
243 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
248 struct IdentityToken *token;
253 struct TokenTicket *ticket;
258 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
262 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
270 struct EgoEntry *next;
275 struct EgoEntry *prev;
280 struct GNUNET_IDENTITY_Ego *ego;
283 * Attribute map. Contains the attributes as json_t
285 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
288 * Attributes are old and should be updated if GNUNET_YES
290 int attributes_dirty;
294 * Continuation for token store call
297 * @param success error code
298 * @param emsg error message
301 store_token_cont (void *cls,
306 if (GNUNET_SYSERR == success)
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
309 "Failed to update token: %s\n",
313 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
318 * This function updates the old token with new attributes,
319 * removes deleted attributes and expiration times.
321 * @param cls the ego entry
322 * @param tc task context
325 handle_token_update (void *cls,
326 const struct GNUNET_SCHEDULER_TaskContext *tc)
328 char *token_metadata;
332 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
333 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
334 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
335 struct EgoEntry *ego_entry = cls;
336 struct GNUNET_GNSRECORD_Data token_record[2];
337 struct GNUNET_HashCode key_hash;
338 struct GNUNET_TIME_Relative token_rel_exp;
339 struct GNUNET_TIME_Relative token_ttl;
340 struct GNUNET_TIME_Absolute token_exp;
341 struct GNUNET_TIME_Absolute token_nbf;
342 struct GNUNET_TIME_Absolute new_exp;
343 struct GNUNET_TIME_Absolute new_iat;
344 struct GNUNET_TIME_Absolute new_nbf;
345 struct IdentityToken *new_token;
346 json_t *payload_json;
349 json_t *token_nbf_json;
350 json_t *token_exp_json;
351 size_t token_metadata_len;
353 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
354 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
357 //Note: We need the token expiration time here. Not the record expiration
359 //There are two types of tokens: Token that expire on GNS level with
360 //an absolute expiration time. Those are basically tokens that will
361 //be automatically revoked on (record)expiration.
362 //Tokens stored with relative expiration times will expire on the token level (token expiration)
363 //but this service will reissue new tokens that can be retrieved from GNS
366 payload_json = token->payload;
368 token_exp_json = json_object_get (payload_json, "exp");
369 token_nbf_json = json_object_get (payload_json, "nbf");
370 token_exp.abs_value_us = json_integer_value(token_exp_json);
371 token_nbf.abs_value_us = json_integer_value(token_nbf_json);
372 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
374 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
375 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
377 //This token is not yet expired! Save and skip
378 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
380 min_rel_exp = token_ttl;
382 json_decref (payload_json);
387 GNUNET_free (scopes);
389 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Token is expired. Create a new one\n");
394 new_token = token_create (&pub_key,
396 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
397 new_nbf = GNUNET_TIME_absolute_get ();
400 json_object_foreach(payload_json, key, value) {
401 if (0 == strcmp (key, "exp"))
403 token_add_json (new_token, key, json_integer (new_exp.abs_value_us));
405 else if (0 == strcmp (key, "nbf"))
407 token_add_json (new_token, key, json_integer (new_nbf.abs_value_us));
409 else if (0 == strcmp (key, "iat"))
411 token_add_json (new_token, key, json_integer (new_iat.abs_value_us));
413 else if ((0 == strcmp (key, "iss"))
414 || (0 == strcmp (key, "aud")))
418 else if ((0 == strcmp (key, "sub"))
419 || (0 == strcmp (key, "rnl")))
421 token_add_json (new_token, key, value);
424 GNUNET_CRYPTO_hash (key,
427 //Check if attr still exists. omit of not
428 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
431 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
433 token_add_json (new_token, key, cur_value);
438 // reassemble and set
439 GNUNET_assert (token_serialize (new_token,
444 json_decref (payload_json);
446 token_record[0].data = enc_token_str;
447 token_record[0].data_size = strlen (enc_token_str) + 1;
448 token_record[0].expiration_time = rd_exp; //Old expiration time
449 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
450 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
453 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
454 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
455 + strlen (scopes) + 1; //With 0-Terminator
456 token_metadata = GNUNET_malloc (token_metadata_len);
457 write_ptr = token_metadata;
458 memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
459 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
460 memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
461 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
462 memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
464 token_record[1].data = token_metadata;
465 token_record[1].data_size = token_metadata_len;
466 token_record[1].expiration_time = rd_exp;
467 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
468 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
470 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
478 token_destroy (new_token);
479 token_destroy (token);
480 GNUNET_free (new_ecdhe_privkey);
481 GNUNET_free (enc_token_str);
485 GNUNET_free (scopes);
490 update_identities(void *cls,
491 const struct GNUNET_SCHEDULER_TaskContext *tc);
499 * @param value the json_t attribute value
503 clear_ego_attrs (void *cls,
504 const struct GNUNET_HashCode *key,
507 json_t *attr_value = value;
509 json_decref (attr_value);
517 * Update all ID_TOKEN records for an identity and store them
519 * @param cls the identity entry
520 * @param zone the identity
521 * @param lbl the name of the record
522 * @param rd_count number of records
523 * @param rd record data
527 token_collect (void *cls,
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
530 unsigned int rd_count,
531 const struct GNUNET_GNSRECORD_Data *rd)
533 struct EgoEntry *ego_entry = cls;
534 const struct GNUNET_GNSRECORD_Data *token_record;
535 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
536 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542 ">>> Updating Ego finished\n");
543 //Clear attribute map for ego
544 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
547 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
548 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
553 //There should be only a single record for a token under a label
556 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
560 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
562 token_metadata_record = &rd[0];
563 token_record = &rd[1];
565 token_record = &rd[0];
566 token_metadata_record = &rd[1];
568 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
570 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
573 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
575 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
579 //Get metadata and decrypt token
580 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
581 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
582 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
584 token_parse2 (token_record->data,
589 label = GNUNET_strdup (lbl);
590 rd_exp = token_record->expiration_time;
592 GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
598 * Collect all ID_ATTR records for an identity and store them
600 * @param cls the identity entry
601 * @param zone the identity
602 * @param lbl the name of the record
603 * @param rd_count number of records
604 * @param rd record data
608 attribute_collect (void *cls,
609 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
611 unsigned int rd_count,
612 const struct GNUNET_GNSRECORD_Data *rd)
614 struct EgoEntry *ego_entry = cls;
616 struct GNUNET_HashCode key;
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 ">>> Updating Attributes finished\n");
625 ego_entry->attributes_dirty = GNUNET_NO;
626 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
632 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
635 GNUNET_CRYPTO_hash (lbl,
640 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
642 attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
645 attr_value = json_string (attr);
646 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
649 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
653 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
657 attr_value = json_array();
658 for (i = 0; i < rd_count; i++)
660 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
662 attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
665 json_array_append_new (attr_value, json_string (attr));
670 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
673 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
674 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
680 * Update identity information for ego. If attribute map is
681 * dirty, first update the attributes.
683 * @param cls the ego to update
684 * param tc task context
688 update_identities(void *cls,
689 const struct GNUNET_SCHEDULER_TaskContext *tc)
691 struct EgoEntry *next_ego = cls;
692 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
694 if (NULL == next_ego)
696 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
697 min_rel_exp = MIN_WAIT_TIME;
698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699 ">>> Finished. Rescheduling in %d\n",
700 min_rel_exp.rel_value_us);
702 //finished -> reschedule
703 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
706 min_rel_exp.rel_value_us = 0;
709 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
710 if (GNUNET_YES == next_ego->attributes_dirty)
712 //Starting over. We must update the Attributes for they might have changed.
713 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
721 //Ego will be dirty next time
722 next_ego->attributes_dirty = GNUNET_YES;
723 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
733 * Function called initially to start update task
738 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
739 //Initially iterate all itenties and refresh all tokens
740 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
744 * Initial ego collection function.
749 * @param identifier ego name
753 struct GNUNET_IDENTITY_Ego *ego,
755 const char *identifier)
757 struct EgoEntry *new_entry;
758 if ((NULL == ego) && (STATE_INIT == state))
760 state = STATE_POST_INIT;
764 if (STATE_INIT == state) {
765 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
766 new_entry->ego = ego;
767 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
769 new_entry->attributes_dirty = GNUNET_YES;
770 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
780 struct EgoEntry *ego_entry;
781 struct EgoEntry *ego_tmp;
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
787 GNUNET_SERVER_notification_context_destroy (nc);
792 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
796 if (NULL != timeout_task)
797 GNUNET_SCHEDULER_cancel (timeout_task);
798 if (NULL != update_task)
799 GNUNET_SCHEDULER_cancel (update_task);
800 if (NULL != identity_handle)
801 GNUNET_IDENTITY_disconnect (identity_handle);
802 if (NULL != gns_handle)
803 GNUNET_GNS_disconnect (gns_handle);
805 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
807 GNUNET_NAMESTORE_cancel (ns_qe);
808 if (NULL != ns_handle)
809 GNUNET_NAMESTORE_disconnect (ns_handle);
815 for (ego_entry = ego_head;
819 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
821 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
826 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
827 ego_entry = ego_entry->next;
828 GNUNET_free (ego_tmp);
836 * @param tc task context
839 do_shutdown (void *cls,
840 const struct GNUNET_SCHEDULER_TaskContext *tc)
842 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
843 "Shutting down...\n");
848 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
849 create_exchange_result_message (const char* token,
852 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
853 uint16_t token_len = strlen (token) + 1;
854 erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
856 erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
857 erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
859 memcpy (&erm[1], token, token_len);
864 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
865 create_issue_result_message (const char* ticket)
867 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
869 irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen(ticket) + 1);
870 irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
871 irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen (ticket) + 1);
872 memcpy (&irm[1], ticket, strlen (ticket) + 1);
877 cleanup_issue_handle (struct IssueHandle *handle)
879 if (NULL != handle->attr_map)
880 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
881 if (NULL != handle->scopes)
882 GNUNET_free (handle->scopes);
883 if (NULL != handle->token)
884 token_destroy (handle->token);
885 if (NULL != handle->ticket)
886 ticket_destroy (handle->ticket);
887 GNUNET_free (handle);
891 store_token_issue_cont (void *cls,
895 struct IssueHandle *handle = cls;
896 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
897 char* token_ticket_str;
898 handle->ns_qe = NULL;
899 if (GNUNET_SYSERR == success)
901 cleanup_issue_handle (handle);
902 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
904 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
907 if (GNUNET_OK != ticket_serialize (handle->ticket,
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
912 "Error serializing ticket\n");
913 cleanup_issue_handle (handle);
914 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
917 irm = create_issue_result_message (token_ticket_str);
918 GNUNET_SERVER_notification_context_unicast (nc,
922 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
923 cleanup_issue_handle (handle);
925 GNUNET_free (token_ticket_str);
929 * Build a GNUid token for identity
930 * @param handle the handle
931 * @param ego_entry the ego to build the token for
932 * @param name name of the ego
933 * @param token_aud token audience
934 * @param token the resulting gnuid token
935 * @return identifier string of token (label)
938 sign_and_return_token (void *cls,
939 const struct GNUNET_SCHEDULER_TaskContext *tc)
941 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
942 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
943 struct IssueHandle *handle = cls;
944 struct GNUNET_GNSRECORD_Data token_record[2];
948 char *token_metadata;
953 size_t token_metadata_len;
957 GNUNET_asprintf (&nonce_str, "%d", handle->nonce);
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
961 rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
963 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
966 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
968 handle->ticket = ticket_create (nonce_str,
973 time = GNUNET_TIME_absolute_get().abs_value_us;
974 exp_time = time + token_expiration_interval.rel_value_us;
976 token_add_json (handle->token, "nbf", json_integer (time));
977 token_add_json (handle->token, "iat", json_integer (time));
978 token_add_json (handle->token, "exp", json_integer (exp_time));
979 token_add_attr (handle->token, "nonce", nonce_str);
981 //Token in a serialized encrypted format
982 GNUNET_assert (token_serialize (handle->token,
987 //Token record E,E_K (Token)
988 token_record[0].data = enc_token_str;
989 token_record[0].data_size = strlen (enc_token_str) + 1;
990 token_record[0].expiration_time = exp_time;
991 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
992 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
995 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
996 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
997 + strlen (handle->scopes) + 1; //With 0-Terminator
998 token_metadata = GNUNET_malloc (token_metadata_len);
999 write_ptr = token_metadata;
1000 memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1001 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1002 memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1003 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1004 memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1006 token_record[1].data = token_metadata;
1007 token_record[1].data_size = token_metadata_len;
1008 token_record[1].expiration_time = exp_time;
1009 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1010 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1013 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1018 &store_token_issue_cont,
1020 GNUNET_free (ecdhe_privkey);
1021 GNUNET_free (lbl_str);
1022 GNUNET_free (nonce_str);
1023 GNUNET_free (enc_token_str);
1024 GNUNET_free (token_metadata);
1028 * Collect attributes for token
1031 attr_collect (void *cls,
1032 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1034 unsigned int rd_count,
1035 const struct GNUNET_GNSRECORD_Data *rd)
1040 struct IssueHandle *handle = cls;
1041 struct GNUNET_HashCode key;
1045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1046 handle->ns_it = NULL;
1047 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1051 GNUNET_CRYPTO_hash (label,
1055 if (0 == rd_count ||
1056 ( (NULL != handle->attr_map) &&
1057 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1062 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1070 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1072 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1076 token_add_json (handle->token,
1078 json_string (data));
1081 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1086 attr_arr = json_array();
1087 for (; i < rd_count; i++)
1089 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1091 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1095 json_array_append_new (attr_arr, json_string (data));
1100 if (0 < json_array_size (attr_arr))
1102 token_add_json (handle->token, label, attr_arr);
1104 json_decref (attr_arr);
1105 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1109 cleanup_exchange_handle (struct ExchangeHandle *handle)
1111 if (NULL != handle->ticket)
1112 ticket_destroy (handle->ticket);
1113 if (NULL != handle->token)
1114 token_destroy (handle->token);
1115 GNUNET_free (handle);
1119 process_lookup_result (void *cls, uint32_t rd_count,
1120 const struct GNUNET_GNSRECORD_Data *rd)
1122 struct ExchangeHandle *handle = cls;
1123 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1127 handle->lookup_request = NULL;
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131 "Number of tokens %d != 2.",
1133 cleanup_exchange_handle (handle);
1134 GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1139 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1144 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1145 &handle->aud_privkey,
1149 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1150 &handle->aud_privkey,
1153 erm = create_exchange_result_message (token_str,
1155 GNUNET_SERVER_notification_context_unicast (nc,
1159 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1161 cleanup_exchange_handle (handle);
1162 GNUNET_free (record_str);
1163 GNUNET_free (token_str);
1170 * Handler for exchange message
1173 * @param client who sent the message
1174 * @param message the message
1177 handle_exchange_message (void *cls,
1178 struct GNUNET_SERVER_Client *client,
1179 const struct GNUNET_MessageHeader *message)
1181 const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1182 struct ExchangeHandle *xchange_handle;
1187 size = ntohs (message->size);
1188 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1191 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1194 em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1195 ticket = (const char *) &em[1];
1196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197 "Received EXCHANGE of `%s' from client\n",
1199 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1200 xchange_handle->aud_privkey = em->aud_privkey;
1202 if (GNUNET_SYSERR == ticket_parse (ticket,
1203 &xchange_handle->aud_privkey,
1204 &xchange_handle->ticket))
1206 GNUNET_free (xchange_handle);
1207 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1210 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
1211 xchange_handle->ticket->payload->label);
1212 GNUNET_asprintf (&lookup_query,
1214 xchange_handle->ticket->payload->label);
1215 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1216 GNUNET_SERVER_notification_context_add (nc, client);
1217 GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1218 xchange_handle->client = client;
1219 xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1221 &xchange_handle->ticket->payload->identity_key,
1222 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1223 GNUNET_GNS_LO_LOCAL_MASTER,
1225 &process_lookup_result,
1227 GNUNET_free (lookup_query);
1233 * Handler for issue message
1236 * @param client who sent the message
1237 * @param message the message
1240 handle_issue_message (void *cls,
1241 struct GNUNET_SERVER_Client *client,
1242 const struct GNUNET_MessageHeader *message)
1244 const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1250 struct GNUNET_HashCode key;
1251 struct IssueHandle *issue_handle;
1253 size = ntohs (message->size);
1254 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1257 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1260 im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1261 scopes = (const char *) &im[1];
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "Received ISSUE of `%s' from client\n",
1265 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1266 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1268 scopes_tmp = GNUNET_strdup (scopes);
1269 scope = strtok(scopes_tmp, ",");
1270 for (; NULL != scope; scope = strtok (NULL, ","))
1272 GNUNET_CRYPTO_hash (scope,
1275 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1278 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1280 GNUNET_free (scopes_tmp);
1282 issue_handle->aud_key = im->aud_key;
1283 issue_handle->iss_key = im->iss_key;
1284 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1285 issue_handle->nonce = im->nonce;
1286 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1287 GNUNET_SERVER_notification_context_add (nc, client);
1288 GNUNET_SERVER_client_set_user_context (client, issue_handle);
1289 issue_handle->client = client;
1290 issue_handle->scopes = GNUNET_strdup (scopes);
1291 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1292 &issue_handle->iss_pkey);
1293 issue_handle->token = token_create (&issue_handle->iss_pkey,
1296 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1303 * Main function that will be run
1305 * @param cls closure
1306 * @param args remaining command-line arguments
1307 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1308 * @param c configuration
1312 struct GNUNET_SERVER_Handle *server,
1313 const struct GNUNET_CONFIGURATION_Handle *c)
1315 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1316 {&handle_issue_message, NULL,
1317 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1318 {&handle_exchange_message, NULL,
1319 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1325 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1326 GNUNET_SERVER_add_handlers (server, handlers);
1327 nc = GNUNET_SERVER_notification_context_create (server, 1);
1329 //Connect to identity and namestore services
1330 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1331 if (NULL == ns_handle)
1333 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1336 gns_handle = GNUNET_GNS_connect (cfg);
1337 if (NULL == gns_handle)
1339 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1342 identity_handle = GNUNET_IDENTITY_connect (cfg,
1347 GNUNET_CONFIGURATION_get_value_time (cfg,
1348 "identity-provider",
1349 "TOKEN_EXPIRATION_INTERVAL",
1350 &token_expiration_interval))
1352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353 "Time window for zone iteration: %s\n",
1354 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1357 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1360 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1361 &do_shutdown, NULL);
1369 * @param argc number of arguments from the cli
1370 * @param argv command line arguments
1371 * @return 0 ok, 1 on error
1375 main (int argc, char *const *argv)
1377 return (GNUNET_OK ==
1378 GNUNET_SERVICE_run (argc, argv, "identity-provider",
1379 GNUNET_SERVICE_OPTION_NONE,
1380 &run, NULL)) ? 0 : 1;
1383 /* end of gnunet-rest-server.c */