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;
601 //There should be only a single record for a token under a label
604 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
608 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
610 token_metadata_record = &rd[0];
611 token_record = &rd[1];
615 token_record = &rd[0];
616 token_metadata_record = &rd[1];
618 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
620 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
623 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
625 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
629 //Get metadata and decrypt token
630 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
631 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&(&ecdhe_privkey)[1];
632 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
634 token_parse2 (token_record->data,
639 label = GNUNET_strdup (lbl);
640 rd_exp = token_record->expiration_time;
642 GNUNET_SCHEDULER_add_now (&handle_token_update,
648 attribute_collect_error_cb (void *cls)
650 struct EgoEntry *ego_entry = cls;
652 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
653 ">>> Updating Attributes failed!\n");
654 ego_entry->attributes_dirty = GNUNET_NO;
655 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
661 attribute_collect_finished_cb (void *cls)
663 struct EgoEntry *ego_entry = cls;
665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666 ">>> Updating Attributes finished\n");
667 ego_entry->attributes_dirty = GNUNET_NO;
668 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
675 * Collect all ID_ATTR records for an identity and store them
677 * @param cls the identity entry
678 * @param zone the identity
679 * @param lbl the name of the record
680 * @param rd_count number of records
681 * @param rd record data
685 attribute_collect (void *cls,
686 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
688 unsigned int rd_count,
689 const struct GNUNET_GNSRECORD_Data *rd)
691 struct EgoEntry *ego_entry = cls;
692 struct GNUNET_HashCode key;
693 struct TokenAttr *attr;
694 struct TokenAttrValue *val;
700 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
703 GNUNET_CRYPTO_hash (lbl,
708 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
710 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
713 attr = GNUNET_malloc (sizeof (struct TokenAttr));
714 attr->name = GNUNET_strdup (lbl);
715 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
716 val->value = val_str;
717 GNUNET_CONTAINER_DLL_insert (attr->val_head,
720 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
723 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
726 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
730 attr = GNUNET_malloc (sizeof (struct TokenAttr));
731 attr->name = GNUNET_strdup (lbl);
732 for (i = 0; i < rd_count; i++)
734 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
736 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
739 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
740 val->value = val_str;
741 GNUNET_CONTAINER_DLL_insert (attr->val_head,
746 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
749 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
750 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
755 * Update identity information for ego. If attribute map is
756 * dirty, first update the attributes.
758 * @param cls the ego to update
761 update_identities(void *cls)
763 struct EgoEntry *next_ego = cls;
764 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
767 if (NULL == next_ego)
769 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
770 min_rel_exp = MIN_WAIT_TIME;
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 ">>> Finished. Rescheduling in %lu\n",
773 min_rel_exp.rel_value_us);
775 //finished -> reschedule
776 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
779 min_rel_exp.rel_value_us = 0;
782 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
783 if (GNUNET_YES == next_ego->attributes_dirty)
785 //Starting over. We must update the Attributes for they might have changed.
786 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
788 &attribute_collect_error_cb,
792 &attribute_collect_finished_cb,
798 //Ego will be dirty next time
799 next_ego->attributes_dirty = GNUNET_YES;
800 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
802 &token_collect_error_cb,
806 &token_collect_finished_cb,
813 * Function called initially to start update task
818 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
819 //Initially iterate all itenties and refresh all tokens
820 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
826 * Initial ego collection function.
831 * @param identifier ego name
835 struct GNUNET_IDENTITY_Ego *ego,
837 const char *identifier)
839 struct EgoEntry *new_entry;
840 if ((NULL == ego) && (STATE_INIT == state))
842 state = STATE_POST_INIT;
846 if (STATE_INIT == state) {
847 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
848 new_entry->ego = ego;
849 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
851 new_entry->attributes_dirty = GNUNET_YES;
852 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
862 struct EgoEntry *ego_entry;
863 struct EgoEntry *ego_tmp;
865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 GNUNET_SERVER_notification_context_destroy (nc);
874 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
878 if (NULL != timeout_task)
879 GNUNET_SCHEDULER_cancel (timeout_task);
880 if (NULL != update_task)
881 GNUNET_SCHEDULER_cancel (update_task);
882 if (NULL != identity_handle)
883 GNUNET_IDENTITY_disconnect (identity_handle);
884 if (NULL != gns_handle)
885 GNUNET_GNS_disconnect (gns_handle);
887 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
889 GNUNET_NAMESTORE_cancel (ns_qe);
890 if (NULL != ns_handle)
891 GNUNET_NAMESTORE_disconnect (ns_handle);
897 for (ego_entry = ego_head;
901 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
903 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
908 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
909 ego_entry = ego_entry->next;
910 GNUNET_free (ego_tmp);
918 * @param tc task context
921 do_shutdown (void *cls)
923 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
924 "Shutting down...\n");
929 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
930 create_exchange_result_message (const char* token,
932 uint64_t ticket_nonce)
934 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
935 uint16_t token_len = strlen (token) + 1;
936 erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
938 erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
939 erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
941 erm->ticket_nonce = htonl (ticket_nonce);
942 GNUNET_memcpy (&erm[1], token, token_len);
947 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
948 create_issue_result_message (const char* label,
952 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
955 irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
957 + strlen (ticket) + 1
958 + strlen (token) + 1);
959 irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
960 irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
962 + strlen (ticket) + 1
963 + strlen (token) + 1);
964 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
965 GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
966 GNUNET_free (tmp_str);
971 cleanup_issue_handle (struct IssueHandle *handle)
973 if (NULL != handle->attr_map)
974 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
975 if (NULL != handle->scopes)
976 GNUNET_free (handle->scopes);
977 if (NULL != handle->token)
978 token_destroy (handle->token);
979 if (NULL != handle->ticket)
980 ticket_destroy (handle->ticket);
981 if (NULL != handle->label)
982 GNUNET_free (handle->label);
983 GNUNET_free (handle);
987 store_token_issue_cont (void *cls,
991 struct IssueHandle *handle = cls;
992 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
996 handle->ns_qe = NULL;
997 if (GNUNET_SYSERR == success)
999 cleanup_issue_handle (handle);
1000 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1002 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1005 if (GNUNET_OK != ticket_serialize (handle->ticket,
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1010 "Error serializing ticket\n");
1011 cleanup_issue_handle (handle);
1012 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1015 if (GNUNET_OK != token_to_string (handle->token,
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1020 "Error serializing token\n");
1021 GNUNET_free (ticket_str);
1022 cleanup_issue_handle (handle);
1023 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1026 irm = create_issue_result_message (handle->label,
1029 irm->id = handle->r_id;
1030 GNUNET_SERVER_notification_context_unicast (nc,
1034 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1035 cleanup_issue_handle (handle);
1037 GNUNET_free (ticket_str);
1038 GNUNET_free (token_str);
1043 * Build a token and store it
1045 * @param cls the IssueHandle
1048 sign_and_return_token (void *cls)
1050 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1051 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1052 struct IssueHandle *handle = cls;
1053 struct GNUNET_GNSRECORD_Data token_record[2];
1055 char *enc_token_str;
1056 char *token_metadata;
1060 size_t token_metadata_len;
1064 GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1067 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1069 handle->ticket = ticket_create (handle->nonce,
1074 time = GNUNET_TIME_absolute_get().abs_value_us;
1075 exp_time = time + token_expiration_interval.rel_value_us;
1077 token_add_attr_int (handle->token, "nbf", time);
1078 token_add_attr_int (handle->token, "iat", time);
1079 token_add_attr_int (handle->token, "exp", exp_time);
1080 token_add_attr (handle->token, "nonce", nonce_str);
1082 //Token in a serialized encrypted format
1083 GNUNET_assert (token_serialize (handle->token,
1088 //Token record E,E_K (Token)
1089 token_record[0].data = enc_token_str;
1090 token_record[0].data_size = strlen (enc_token_str) + 1;
1091 token_record[0].expiration_time = exp_time;
1092 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1093 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1096 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1097 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1098 + strlen (handle->scopes) + 1; //With 0-Terminator
1099 token_metadata = GNUNET_malloc (token_metadata_len);
1100 write_ptr = token_metadata;
1101 GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1102 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1103 GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1104 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1105 GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1107 token_record[1].data = token_metadata;
1108 token_record[1].data_size = token_metadata_len;
1109 token_record[1].expiration_time = exp_time;
1110 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1111 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1114 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1119 &store_token_issue_cont,
1121 GNUNET_free (ecdhe_privkey);
1122 GNUNET_free (nonce_str);
1123 GNUNET_free (enc_token_str);
1124 GNUNET_free (token_metadata);
1129 attr_collect_error (void *cls)
1131 struct IssueHandle *handle = cls;
1133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1134 handle->ns_it = NULL;
1135 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1140 attr_collect_finished (void *cls)
1142 struct IssueHandle *handle = cls;
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1145 handle->ns_it = NULL;
1146 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1151 * Collect attributes for token
1154 attr_collect (void *cls,
1155 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1157 unsigned int rd_count,
1158 const struct GNUNET_GNSRECORD_Data *rd)
1160 struct IssueHandle *handle = cls;
1163 struct GNUNET_HashCode key;
1165 GNUNET_CRYPTO_hash (label,
1169 if (0 == rd_count ||
1170 ( (NULL != handle->attr_map) &&
1171 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1176 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1184 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1186 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1190 token_add_attr (handle->token,
1195 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1200 for (; i < rd_count; i++)
1202 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1204 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1208 token_add_attr (handle->token, label, data);
1213 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1217 cleanup_exchange_handle (struct ExchangeHandle *handle)
1219 if (NULL != handle->ticket)
1220 ticket_destroy (handle->ticket);
1221 if (NULL != handle->token)
1222 token_destroy (handle->token);
1223 GNUNET_free (handle);
1227 process_lookup_result (void *cls, uint32_t rd_count,
1228 const struct GNUNET_GNSRECORD_Data *rd)
1230 struct ExchangeHandle *handle = cls;
1231 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1235 handle->lookup_request = NULL;
1238 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1239 "Number of tokens %d != 2.",
1241 cleanup_exchange_handle (handle);
1242 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1247 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1252 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1253 &handle->aud_privkey,
1257 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1258 &handle->aud_privkey,
1261 erm = create_exchange_result_message (token_str,
1263 handle->ticket->payload->nonce);
1264 erm->id = handle->r_id;
1265 GNUNET_SERVER_notification_context_unicast (nc,
1269 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1271 cleanup_exchange_handle (handle);
1272 GNUNET_free (record_str);
1273 GNUNET_free (token_str);
1282 * Handler for exchange message
1285 * @param client who sent the message
1286 * @param message the message
1289 handle_exchange_message (void *cls,
1290 struct GNUNET_SERVER_Client *client,
1291 const struct GNUNET_MessageHeader *message)
1293 const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1294 struct ExchangeHandle *xchange_handle;
1299 size = ntohs (message->size);
1300 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1303 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1306 em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1307 ticket = (const char *) &em[1];
1308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1309 "Received EXCHANGE of `%s' from client\n",
1311 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1312 xchange_handle->aud_privkey = em->aud_privkey;
1313 xchange_handle->r_id = em->id;
1314 if (GNUNET_SYSERR == ticket_parse (ticket,
1315 &xchange_handle->aud_privkey,
1316 &xchange_handle->ticket))
1318 GNUNET_free (xchange_handle);
1319 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1323 xchange_handle->ticket->payload->label);
1324 GNUNET_asprintf (&lookup_query,
1326 xchange_handle->ticket->payload->label);
1327 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1328 GNUNET_SERVER_notification_context_add (nc, client);
1329 GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1330 xchange_handle->client = client;
1331 xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1333 &xchange_handle->ticket->payload->identity_key,
1334 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1335 GNUNET_GNS_LO_LOCAL_MASTER,
1337 &process_lookup_result,
1339 GNUNET_free (lookup_query);
1345 find_existing_token_error (void *cls)
1347 struct IssueHandle *handle = cls;
1348 cleanup_issue_handle (handle);
1349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
1350 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1355 find_existing_token_finished (void *cls)
1357 struct IssueHandle *handle = cls;
1360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1361 ">>> No existing token found\n");
1363 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1365 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1368 handle->ns_it = NULL;
1369 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1371 &attr_collect_error,
1375 &attr_collect_finished,
1382 * Look for existing token
1384 * @param cls the identity entry
1385 * @param zone the identity
1386 * @param lbl the name of the record
1387 * @param rd_count number of records
1388 * @param rd record data
1392 find_existing_token (void *cls,
1393 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1395 unsigned int rd_count,
1396 const struct GNUNET_GNSRECORD_Data *rd)
1398 struct IssueHandle *handle = cls;
1399 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1400 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1401 struct GNUNET_HashCode key;
1402 int scope_count_token;
1406 //There should be only a single record for a token under a label
1409 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1413 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1415 token_metadata_record = &rd[0];
1419 token_metadata_record = &rd[1];
1421 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1423 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1426 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1428 (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1429 tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1431 if (0 != memcmp (aud_key, &handle->aud_key,
1432 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1434 char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1435 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1436 //Audience does not match!
1437 char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1438 token_metadata_record->data,
1439 token_metadata_record->data_size);
1440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1441 "Token does not match audience %s vs %s. Moving on\n",
1444 GNUNET_free (tmp_scopes);
1447 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1451 scope = strtok (tmp_scopes, ",");
1452 scope_count_token = 0;
1453 while (NULL != scope)
1455 GNUNET_CRYPTO_hash (scope,
1459 if ((NULL != handle->attr_map) &&
1460 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463 "Issued token does not include `%s'. Moving on\n", scope);
1464 GNUNET_free (tmp_scopes);
1465 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1468 scope_count_token++;
1469 scope = strtok (NULL, ",");
1471 GNUNET_free (tmp_scopes);
1472 //All scopes in token are also in request. Now
1474 if ((NULL != handle->attr_map) &&
1475 (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
1477 //We have an existing token
1478 handle->label = GNUNET_strdup (lbl);
1479 handle->ns_it = NULL;
1480 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1482 &attr_collect_error,
1486 &attr_collect_finished,
1491 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1492 "Nuber of attributes in token do not match request\n");
1494 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1500 * Handler for issue message
1503 * @param client who sent the message
1504 * @param message the message
1507 handle_issue_message (void *cls,
1508 struct GNUNET_SERVER_Client *client,
1509 const struct GNUNET_MessageHeader *message)
1511 const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1517 struct GNUNET_HashCode key;
1518 struct IssueHandle *issue_handle;
1520 size = ntohs (message->size);
1521 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1524 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1527 im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1528 scopes = (const char *) &im[1];
1529 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1530 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1532 if ('\0' != scopes[size - sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage) - 1])
1534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed scopes received!\n");
1536 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1539 scopes_tmp = GNUNET_strdup (scopes);
1540 scope = strtok(scopes_tmp, ",");
1541 for (; NULL != scope; scope = strtok (NULL, ","))
1543 GNUNET_CRYPTO_hash (scope,
1546 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1549 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1551 GNUNET_free (scopes_tmp);
1552 issue_handle->r_id = im->id;
1553 issue_handle->aud_key = im->aud_key;
1554 issue_handle->iss_key = im->iss_key;
1555 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1556 &issue_handle->iss_pkey);
1557 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1558 issue_handle->nonce = ntohl (im->nonce);
1559 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1560 GNUNET_SERVER_notification_context_add (nc, client);
1561 GNUNET_SERVER_client_set_user_context (client, issue_handle);
1562 issue_handle->client = client;
1563 issue_handle->scopes = GNUNET_strdup (scopes);
1564 issue_handle->token = token_create (&issue_handle->iss_pkey,
1565 &issue_handle->aud_key);
1567 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1569 &find_existing_token_error,
1571 &find_existing_token,
1573 &find_existing_token_finished,
1579 * Main function that will be run
1581 * @param cls closure
1582 * @param args remaining command-line arguments
1583 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1584 * @param c configuration
1588 struct GNUNET_SERVER_Handle *server,
1589 const struct GNUNET_CONFIGURATION_Handle *c)
1591 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1592 {&handle_issue_message, NULL,
1593 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1594 {&handle_exchange_message, NULL,
1595 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1601 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1602 GNUNET_SERVER_add_handlers (server, handlers);
1603 nc = GNUNET_SERVER_notification_context_create (server, 1);
1605 //Connect to identity and namestore services
1606 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1607 if (NULL == ns_handle)
1609 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1612 gns_handle = GNUNET_GNS_connect (cfg);
1613 if (NULL == gns_handle)
1615 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1618 identity_handle = GNUNET_IDENTITY_connect (cfg,
1623 GNUNET_CONFIGURATION_get_value_time (cfg,
1624 "identity-provider",
1625 "TOKEN_EXPIRATION_INTERVAL",
1626 &token_expiration_interval))
1628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1629 "Time window for zone iteration: %s\n",
1630 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1633 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1636 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1643 * @param argc number of arguments from the cli
1644 * @param argv command line arguments
1645 * @return 0 ok, 1 on error
1648 main (int argc, char *const *argv)
1650 return (GNUNET_OK ==
1651 GNUNET_SERVICE_run (argc, argv, "identity-provider",
1652 GNUNET_SERVICE_OPTION_NONE,
1653 &run, NULL)) ? 0 : 1;
1656 /* end of gnunet-service-identity-provider.c */