2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
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"
35 #include "gnunet_signatures.h"
36 #include "identity_provider.h"
37 #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;
113 static struct GNUNET_SCHEDULER_Task *update_task;
116 * Timeout for next update pass
118 static struct GNUNET_TIME_Relative min_rel_exp;
122 * Currently processed token
124 static struct IdentityToken *token;
127 * Label for currently processed token
132 * Scopes for processed token
137 * Expiration for processed token
139 static uint64_t rd_exp;
142 * ECDHE Privkey for processed token metadata
144 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
147 * Handle to the statistics service.
149 static struct GNUNET_STATISTICS_Handle *stats;
152 * Notification context, simplifies client broadcasts.
154 static struct GNUNET_SERVER_NotificationContext *nc;
159 static const struct GNUNET_CONFIGURATION_Handle *cfg;
162 struct ExchangeHandle
168 struct GNUNET_SERVER_Client *client;
173 struct TokenTicket *ticket;
178 struct IdentityToken *token;
183 struct GNUNET_GNS_LookupRequest *lookup_request;
188 struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
207 struct GNUNET_SERVER_Client *client;
212 struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
217 struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
222 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
227 struct GNUNET_TIME_Absolute expiration;
242 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
247 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
252 struct IdentityToken *token;
257 struct TokenTicket *ticket;
262 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
265 * The label the token is stored under
276 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
284 struct EgoEntry *next;
289 struct EgoEntry *prev;
294 struct GNUNET_IDENTITY_Ego *ego;
297 * Attribute map. Contains the attributes as json_t
299 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
302 * Attributes are old and should be updated if GNUNET_YES
304 int attributes_dirty;
308 * Continuation for token store call
311 * @param success error code
312 * @param emsg error message
315 store_token_cont (void *cls,
320 if (GNUNET_SYSERR == success)
322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
323 "Failed to update token: %s\n",
327 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
332 * This function updates the old token with new attributes,
333 * removes deleted attributes and expiration times.
335 * @param cls the ego entry
338 handle_token_update (void *cls)
340 char *token_metadata;
343 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
344 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
345 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
346 struct EgoEntry *ego_entry = cls;
347 struct GNUNET_GNSRECORD_Data token_record[2];
348 struct GNUNET_HashCode key_hash;
349 struct GNUNET_TIME_Relative token_rel_exp;
350 struct GNUNET_TIME_Relative token_ttl;
351 struct GNUNET_TIME_Absolute token_exp;
352 struct GNUNET_TIME_Absolute token_nbf;
353 struct GNUNET_TIME_Absolute new_exp;
354 struct GNUNET_TIME_Absolute new_iat;
355 struct GNUNET_TIME_Absolute new_nbf;
356 struct IdentityToken *new_token;
357 struct TokenAttr *cur_value;
358 struct TokenAttr *attr;
359 size_t token_metadata_len;
361 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
362 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
365 //Note: We need the token expiration time here. Not the record expiration
367 //There are two types of tokens: Token that expire on GNS level with
368 //an absolute expiration time. Those are basically tokens that will
369 //be automatically revoked on (record)expiration.
370 //Tokens stored with relative expiration times will expire on the token level (token expiration)
371 //but this service will reissue new tokens that can be retrieved from GNS
374 for (attr = token->attr_head; NULL != attr; attr = attr->next)
376 if (0 == strcmp (attr->name, "exp"))
378 GNUNET_assert (1 == sscanf (attr->val_head->value,
380 &token_exp.abs_value_us));
381 } else if (0 == strcmp (attr->name, "nbf")) {
382 GNUNET_assert (1 == sscanf (attr->val_head->value,
384 &token_nbf.abs_value_us));
387 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
389 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
390 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
392 //This token is not yet expired! Save and skip
393 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
395 min_rel_exp = token_ttl;
401 GNUNET_free (scopes);
403 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
407 "Token is expired. Create a new one\n");
408 new_token = token_create (&pub_key,
410 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
411 new_nbf = GNUNET_TIME_absolute_get ();
413 for (attr = token->attr_head; NULL != attr; attr = attr->next)
415 if (0 == strcmp (attr->name, "exp"))
417 token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
419 else if (0 == strcmp (attr->name, "nbf"))
421 token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
423 else if (0 == strcmp (attr->name, "iat"))
425 token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
427 else if ((0 == strcmp (attr->name, "iss"))
428 || (0 == strcmp (attr->name, "aud")))
432 else if (0 == strcmp (attr->name, "sub"))
434 token_add_attr (new_token,
436 attr->val_head->value);
440 GNUNET_CRYPTO_hash (attr->name,
443 //Check if attr still exists. omit of not
445 GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
448 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
450 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
451 new_token->attr_tail,
457 // reassemble and set
458 GNUNET_assert (token_serialize (new_token,
463 token_record[0].data = enc_token_str;
464 token_record[0].data_size = strlen (enc_token_str) + 1;
465 token_record[0].expiration_time = rd_exp; //Old expiration time
466 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
467 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
470 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
471 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
472 + strlen (scopes) + 1; //With 0-Terminator
473 token_metadata = GNUNET_malloc (token_metadata_len);
474 write_ptr = token_metadata;
475 GNUNET_memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
476 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
477 GNUNET_memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
478 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
479 GNUNET_memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
481 token_record[1].data = token_metadata;
482 token_record[1].data_size = token_metadata_len;
483 token_record[1].expiration_time = rd_exp;
484 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
485 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
487 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
494 token_destroy (new_token);
495 token_destroy (token);
496 GNUNET_free (new_ecdhe_privkey);
497 GNUNET_free (enc_token_str);
501 GNUNET_free (scopes);
507 update_identities(void *cls);
516 * @param value the json_t attribute value
517 * @return #GNUNET_YES
520 clear_ego_attrs (void *cls,
521 const struct GNUNET_HashCode *key,
524 struct TokenAttr *attr = value;
525 struct TokenAttrValue *val;
526 struct TokenAttrValue *tmp_val;
527 for (val = attr->val_head; NULL != val;)
530 GNUNET_CONTAINER_DLL_remove (attr->val_head,
533 GNUNET_free (val->value);
537 GNUNET_free (attr->name);
545 token_collect_error_cb (void *cls)
547 struct EgoEntry *ego_entry = cls;
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 ">>> Updating Ego failed!\n");
551 //Clear attribute map for ego
552 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
555 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
556 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
563 token_collect_finished_cb (void *cls)
565 struct EgoEntry *ego_entry = cls;
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
568 ">>> Updating Ego finished\n");
569 //Clear attribute map for ego
570 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
573 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
574 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
581 * Update all ID_TOKEN records for an identity and store them
583 * @param cls the identity entry
584 * @param zone the identity
585 * @param lbl the name of the record
586 * @param rd_count number of records
587 * @param rd record data
590 token_collect (void *cls,
591 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
593 unsigned int rd_count,
594 const struct GNUNET_GNSRECORD_Data *rd)
596 struct EgoEntry *ego_entry = cls;
597 const struct GNUNET_GNSRECORD_Data *token_record;
598 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
599 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
600 struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key;
602 //There should be only a single record for a token under a label
605 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
609 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
611 token_metadata_record = &rd[0];
612 token_record = &rd[1];
616 token_record = &rd[0];
617 token_metadata_record = &rd[1];
619 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
621 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
624 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
626 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
630 //Get metadata and decrypt token
631 priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data;
632 ecdhe_privkey = *priv_key;
633 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1];
634 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
636 token_parse2 (token_record->data,
641 label = GNUNET_strdup (lbl);
642 rd_exp = token_record->expiration_time;
644 GNUNET_SCHEDULER_add_now (&handle_token_update,
650 attribute_collect_error_cb (void *cls)
652 struct EgoEntry *ego_entry = cls;
654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
655 ">>> Updating Attributes failed!\n");
656 ego_entry->attributes_dirty = GNUNET_NO;
657 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
663 attribute_collect_finished_cb (void *cls)
665 struct EgoEntry *ego_entry = cls;
667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668 ">>> Updating Attributes finished\n");
669 ego_entry->attributes_dirty = GNUNET_NO;
670 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
677 * Collect all ID_ATTR records for an identity and store them
679 * @param cls the identity entry
680 * @param zone the identity
681 * @param lbl the name of the record
682 * @param rd_count number of records
683 * @param rd record data
687 attribute_collect (void *cls,
688 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
690 unsigned int rd_count,
691 const struct GNUNET_GNSRECORD_Data *rd)
693 struct EgoEntry *ego_entry = cls;
694 struct GNUNET_HashCode key;
695 struct TokenAttr *attr;
696 struct TokenAttrValue *val;
702 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
705 GNUNET_CRYPTO_hash (lbl,
710 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
712 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
715 attr = GNUNET_malloc (sizeof (struct TokenAttr));
716 attr->name = GNUNET_strdup (lbl);
717 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
718 val->value = val_str;
719 GNUNET_CONTAINER_DLL_insert (attr->val_head,
722 GNUNET_assert (GNUNET_OK ==
723 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
726 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
729 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
733 attr = GNUNET_malloc (sizeof (struct TokenAttr));
734 attr->name = GNUNET_strdup (lbl);
735 for (i = 0; i < rd_count; i++)
737 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
739 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
742 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
743 val->value = val_str;
744 GNUNET_CONTAINER_DLL_insert (attr->val_head,
749 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
752 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
753 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
758 * Update identity information for ego. If attribute map is
759 * dirty, first update the attributes.
761 * @param cls the ego to update
764 update_identities(void *cls)
766 struct EgoEntry *next_ego = cls;
767 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
770 if (NULL == next_ego)
772 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
773 min_rel_exp = MIN_WAIT_TIME;
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775 ">>> Finished. Rescheduling in %"SCNu64"\n",
776 min_rel_exp.rel_value_us);
778 //finished -> reschedule
779 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
782 min_rel_exp.rel_value_us = 0;
785 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
786 if (GNUNET_YES == next_ego->attributes_dirty)
788 //Starting over. We must update the Attributes for they might have changed.
789 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
791 &attribute_collect_error_cb,
795 &attribute_collect_finished_cb,
801 //Ego will be dirty next time
802 next_ego->attributes_dirty = GNUNET_YES;
803 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
805 &token_collect_error_cb,
809 &token_collect_finished_cb,
816 * Function called initially to start update task
821 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
822 //Initially iterate all itenties and refresh all tokens
823 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
829 * Initial ego collection function.
834 * @param identifier ego name
838 struct GNUNET_IDENTITY_Ego *ego,
840 const char *identifier)
842 struct EgoEntry *new_entry;
843 if ((NULL == ego) && (STATE_INIT == state))
845 state = STATE_POST_INIT;
849 if (STATE_INIT == state) {
850 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
851 new_entry->ego = ego;
852 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
854 new_entry->attributes_dirty = GNUNET_YES;
855 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
865 struct EgoEntry *ego_entry;
866 struct EgoEntry *ego_tmp;
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 GNUNET_SERVER_notification_context_destroy (nc);
877 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
881 if (NULL != timeout_task)
882 GNUNET_SCHEDULER_cancel (timeout_task);
883 if (NULL != update_task)
884 GNUNET_SCHEDULER_cancel (update_task);
885 if (NULL != identity_handle)
886 GNUNET_IDENTITY_disconnect (identity_handle);
887 if (NULL != gns_handle)
888 GNUNET_GNS_disconnect (gns_handle);
890 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
892 GNUNET_NAMESTORE_cancel (ns_qe);
893 if (NULL != ns_handle)
894 GNUNET_NAMESTORE_disconnect (ns_handle);
900 for (ego_entry = ego_head;
904 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
906 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
911 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
912 ego_entry = ego_entry->next;
913 GNUNET_free (ego_tmp);
921 * @param tc task context
924 do_shutdown (void *cls)
926 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
927 "Shutting down...\n");
932 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
933 create_exchange_result_message (const char* token,
935 uint64_t ticket_nonce)
937 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
938 uint16_t token_len = strlen (token) + 1;
939 erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
941 erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
942 erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
944 erm->ticket_nonce = htonl (ticket_nonce);
945 GNUNET_memcpy (&erm[1], token, token_len);
950 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
951 create_issue_result_message (const char* label,
955 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
958 irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
960 + strlen (ticket) + 1
961 + strlen (token) + 1);
962 irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
963 irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
965 + strlen (ticket) + 1
966 + strlen (token) + 1);
967 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
968 GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
969 GNUNET_free (tmp_str);
974 cleanup_issue_handle (struct IssueHandle *handle)
976 if (NULL != handle->attr_map)
977 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
978 if (NULL != handle->scopes)
979 GNUNET_free (handle->scopes);
980 if (NULL != handle->token)
981 token_destroy (handle->token);
982 if (NULL != handle->ticket)
983 ticket_destroy (handle->ticket);
984 if (NULL != handle->label)
985 GNUNET_free (handle->label);
986 GNUNET_free (handle);
990 store_token_issue_cont (void *cls,
994 struct IssueHandle *handle = cls;
995 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
999 handle->ns_qe = NULL;
1000 if (GNUNET_SYSERR == success)
1002 cleanup_issue_handle (handle);
1003 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1005 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1008 if (GNUNET_OK != ticket_serialize (handle->ticket,
1012 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1013 "Error serializing ticket\n");
1014 cleanup_issue_handle (handle);
1015 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1018 if (GNUNET_OK != token_to_string (handle->token,
1022 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1023 "Error serializing token\n");
1024 GNUNET_free (ticket_str);
1025 cleanup_issue_handle (handle);
1026 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1029 irm = create_issue_result_message (handle->label,
1032 irm->id = handle->r_id;
1033 GNUNET_SERVER_notification_context_unicast (nc,
1037 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1038 cleanup_issue_handle (handle);
1040 GNUNET_free (ticket_str);
1041 GNUNET_free (token_str);
1046 * Build a token and store it
1048 * @param cls the IssueHandle
1051 sign_and_return_token (void *cls)
1053 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1054 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1055 struct IssueHandle *handle = cls;
1056 struct GNUNET_GNSRECORD_Data token_record[2];
1058 char *enc_token_str;
1059 char *token_metadata;
1063 size_t token_metadata_len;
1067 GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1070 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1072 handle->ticket = ticket_create (handle->nonce,
1077 time = GNUNET_TIME_absolute_get().abs_value_us;
1078 exp_time = time + token_expiration_interval.rel_value_us;
1080 token_add_attr_int (handle->token, "nbf", time);
1081 token_add_attr_int (handle->token, "iat", time);
1082 token_add_attr_int (handle->token, "exp", exp_time);
1083 token_add_attr (handle->token, "nonce", nonce_str);
1085 //Token in a serialized encrypted format
1086 GNUNET_assert (token_serialize (handle->token,
1091 //Token record E,E_K (Token)
1092 token_record[0].data = enc_token_str;
1093 token_record[0].data_size = strlen (enc_token_str) + 1;
1094 token_record[0].expiration_time = exp_time;
1095 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1096 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1099 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1100 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1101 + strlen (handle->scopes) + 1; //With 0-Terminator
1102 token_metadata = GNUNET_malloc (token_metadata_len);
1103 write_ptr = token_metadata;
1104 GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1105 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1106 GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1107 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1108 GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1110 token_record[1].data = token_metadata;
1111 token_record[1].data_size = token_metadata_len;
1112 token_record[1].expiration_time = exp_time;
1113 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1114 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1117 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1122 &store_token_issue_cont,
1124 GNUNET_free (ecdhe_privkey);
1125 GNUNET_free (nonce_str);
1126 GNUNET_free (enc_token_str);
1127 GNUNET_free (token_metadata);
1132 attr_collect_error (void *cls)
1134 struct IssueHandle *handle = cls;
1136 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1137 handle->ns_it = NULL;
1138 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1143 attr_collect_finished (void *cls)
1145 struct IssueHandle *handle = cls;
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1148 handle->ns_it = NULL;
1149 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1154 * Collect attributes for token
1157 attr_collect (void *cls,
1158 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1160 unsigned int rd_count,
1161 const struct GNUNET_GNSRECORD_Data *rd)
1163 struct IssueHandle *handle = cls;
1166 struct GNUNET_HashCode key;
1168 GNUNET_CRYPTO_hash (label,
1172 if (0 == rd_count ||
1173 ( (NULL != handle->attr_map) &&
1174 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1179 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1187 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1189 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1193 token_add_attr (handle->token,
1198 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1203 for (; i < rd_count; i++)
1205 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1207 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1211 token_add_attr (handle->token, label, data);
1216 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1220 cleanup_exchange_handle (struct ExchangeHandle *handle)
1222 if (NULL != handle->ticket)
1223 ticket_destroy (handle->ticket);
1224 if (NULL != handle->token)
1225 token_destroy (handle->token);
1226 GNUNET_free (handle);
1230 process_lookup_result (void *cls, uint32_t rd_count,
1231 const struct GNUNET_GNSRECORD_Data *rd)
1233 struct ExchangeHandle *handle = cls;
1234 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1238 handle->lookup_request = NULL;
1241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1242 "Number of tokens %d != 2.",
1244 cleanup_exchange_handle (handle);
1245 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1250 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1255 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1256 &handle->aud_privkey,
1260 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1261 &handle->aud_privkey,
1264 erm = create_exchange_result_message (token_str,
1266 handle->ticket->payload->nonce);
1267 erm->id = handle->r_id;
1268 GNUNET_SERVER_notification_context_unicast (nc,
1272 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1274 cleanup_exchange_handle (handle);
1275 GNUNET_free (record_str);
1276 GNUNET_free (token_str);
1285 * Handler for exchange message
1288 * @param client who sent the message
1289 * @param message the message
1292 handle_exchange_message (void *cls,
1293 struct GNUNET_SERVER_Client *client,
1294 const struct GNUNET_MessageHeader *message)
1296 const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1297 struct ExchangeHandle *xchange_handle;
1302 size = ntohs (message->size);
1303 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1306 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1309 em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1310 ticket = (const char *) &em[1];
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312 "Received EXCHANGE of `%s' from client\n",
1314 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1315 xchange_handle->aud_privkey = em->aud_privkey;
1316 xchange_handle->r_id = em->id;
1317 if (GNUNET_SYSERR == ticket_parse (ticket,
1318 &xchange_handle->aud_privkey,
1319 &xchange_handle->ticket))
1321 GNUNET_free (xchange_handle);
1322 GNUNET_SERVER_receive_done (client,
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1327 xchange_handle->ticket->payload->label);
1328 GNUNET_asprintf (&lookup_query,
1330 xchange_handle->ticket->payload->label);
1331 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1332 GNUNET_SERVER_notification_context_add (nc, client);
1333 GNUNET_SERVER_client_set_user_context (client,
1335 xchange_handle->client = client;
1336 xchange_handle->lookup_request
1337 = GNUNET_GNS_lookup (gns_handle,
1339 &xchange_handle->ticket->payload->identity_key,
1340 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1341 GNUNET_GNS_LO_LOCAL_MASTER,
1343 &process_lookup_result,
1345 GNUNET_free (lookup_query);
1351 find_existing_token_error (void *cls)
1353 struct IssueHandle *handle = cls;
1354 cleanup_issue_handle (handle);
1355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
1356 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1361 find_existing_token_finished (void *cls)
1363 struct IssueHandle *handle = cls;
1366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1367 ">>> No existing token found\n");
1369 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1371 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1374 handle->ns_it = NULL;
1375 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1377 &attr_collect_error,
1381 &attr_collect_finished,
1388 * Look for existing token
1390 * @param cls the identity entry
1391 * @param zone the identity
1392 * @param lbl the name of the record
1393 * @param rd_count number of records
1394 * @param rd record data
1398 find_existing_token (void *cls,
1399 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1401 unsigned int rd_count,
1402 const struct GNUNET_GNSRECORD_Data *rd)
1404 struct IssueHandle *handle = cls;
1405 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1406 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1407 struct GNUNET_HashCode key;
1408 int scope_count_token;
1412 //There should be only a single record for a token under a label
1415 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1419 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1421 token_metadata_record = &rd[0];
1425 token_metadata_record = &rd[1];
1427 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1429 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1432 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1434 (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1435 tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1437 if (0 != memcmp (aud_key, &handle->aud_key,
1438 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1440 char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1441 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1442 //Audience does not match!
1443 char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1444 token_metadata_record->data,
1445 token_metadata_record->data_size);
1446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447 "Token does not match audience %s vs %s. Moving on\n",
1450 GNUNET_free (tmp_scopes);
1453 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1457 scope = strtok (tmp_scopes, ",");
1458 scope_count_token = 0;
1459 while (NULL != scope)
1461 GNUNET_CRYPTO_hash (scope,
1465 if ((NULL != handle->attr_map) &&
1466 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1469 "Issued token does not include `%s'. Moving on\n", scope);
1470 GNUNET_free (tmp_scopes);
1471 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1474 scope_count_token++;
1475 scope = strtok (NULL, ",");
1477 GNUNET_free (tmp_scopes);
1478 //All scopes in token are also in request. Now
1480 if ((NULL != handle->attr_map) &&
1481 (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
1483 //We have an existing token
1484 handle->label = GNUNET_strdup (lbl);
1485 handle->ns_it = NULL;
1486 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1488 &attr_collect_error,
1492 &attr_collect_finished,
1497 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1498 "Nuber of attributes in token do not match request\n");
1500 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1506 * Handler for issue message
1509 * @param client who sent the message
1510 * @param message the message
1513 handle_issue_message (void *cls,
1514 struct GNUNET_SERVER_Client *client,
1515 const struct GNUNET_MessageHeader *message)
1517 const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1523 struct GNUNET_HashCode key;
1524 struct IssueHandle *issue_handle;
1526 size = ntohs (message->size);
1527 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1530 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1533 im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1534 scopes = (const char *) &im[1];
1535 if ('\0' != scopes[size - sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage) - 1])
1537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1538 "Malformed scopes received!\n");
1540 GNUNET_SERVER_receive_done (client,
1544 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1545 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1547 scopes_tmp = GNUNET_strdup (scopes);
1549 for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1551 GNUNET_CRYPTO_hash (scope,
1554 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1557 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1559 GNUNET_free (scopes_tmp);
1560 issue_handle->r_id = im->id;
1561 issue_handle->aud_key = im->aud_key;
1562 issue_handle->iss_key = im->iss_key;
1563 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1564 &issue_handle->iss_pkey);
1565 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1566 issue_handle->nonce = ntohl (im->nonce);
1567 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1568 GNUNET_SERVER_notification_context_add (nc, client);
1569 GNUNET_SERVER_client_set_user_context (client, issue_handle);
1570 issue_handle->client = client;
1571 issue_handle->scopes = GNUNET_strdup (scopes);
1572 issue_handle->token = token_create (&issue_handle->iss_pkey,
1573 &issue_handle->aud_key);
1575 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1577 &find_existing_token_error,
1579 &find_existing_token,
1581 &find_existing_token_finished,
1587 * Main function that will be run
1589 * @param cls closure
1590 * @param args remaining command-line arguments
1591 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1592 * @param c configuration
1596 struct GNUNET_SERVER_Handle *server,
1597 const struct GNUNET_CONFIGURATION_Handle *c)
1599 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1600 {&handle_issue_message, NULL,
1601 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1602 {&handle_exchange_message, NULL,
1603 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1609 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1610 GNUNET_SERVER_add_handlers (server, handlers);
1611 nc = GNUNET_SERVER_notification_context_create (server, 1);
1613 //Connect to identity and namestore services
1614 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1615 if (NULL == ns_handle)
1617 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1620 gns_handle = GNUNET_GNS_connect (cfg);
1621 if (NULL == gns_handle)
1623 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1626 identity_handle = GNUNET_IDENTITY_connect (cfg,
1631 GNUNET_CONFIGURATION_get_value_time (cfg,
1632 "identity-provider",
1633 "TOKEN_EXPIRATION_INTERVAL",
1634 &token_expiration_interval))
1636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1637 "Time window for zone iteration: %s\n",
1638 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1641 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1644 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1651 * @param argc number of arguments from the cli
1652 * @param argv command line arguments
1653 * @return 0 ok, 1 on error
1656 main (int argc, char *const *argv)
1658 return (GNUNET_OK ==
1659 GNUNET_SERVICE_run (argc, argv, "identity-provider",
1660 GNUNET_SERVICE_OPTION_NONE,
1661 &run, NULL)) ? 0 : 1;
1664 /* end of gnunet-service-identity-provider.c */