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;
154 static const struct GNUNET_CONFIGURATION_Handle *cfg;
157 struct ExchangeHandle
163 struct GNUNET_SERVICE_Client *client;
168 struct TokenTicket *ticket;
173 struct IdentityToken *token;
178 struct GNUNET_GNS_LookupRequest *lookup_request;
183 struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
202 struct GNUNET_SERVICE_Client *client;
207 struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
212 struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
217 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
222 struct GNUNET_TIME_Absolute expiration;
237 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
242 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
247 struct IdentityToken *token;
252 struct TokenTicket *ticket;
257 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
260 * The label the token is stored under
271 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
279 struct EgoEntry *next;
284 struct EgoEntry *prev;
289 struct GNUNET_IDENTITY_Ego *ego;
292 * Attribute map. Contains the attributes as json_t
294 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
297 * Attributes are old and should be updated if GNUNET_YES
299 int attributes_dirty;
303 * Continuation for token store call
306 * @param success error code
307 * @param emsg error message
310 store_token_cont (void *cls,
315 if (GNUNET_SYSERR == success)
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 "Failed to update token: %s\n",
322 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
327 * This function updates the old token with new attributes,
328 * removes deleted attributes and expiration times.
330 * @param cls the ego entry
333 handle_token_update (void *cls)
335 char *token_metadata;
338 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
339 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
340 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
341 struct EgoEntry *ego_entry = cls;
342 struct GNUNET_GNSRECORD_Data token_record[2];
343 struct GNUNET_HashCode key_hash;
344 struct GNUNET_TIME_Relative token_rel_exp;
345 struct GNUNET_TIME_Relative token_ttl;
346 struct GNUNET_TIME_Absolute token_exp;
347 struct GNUNET_TIME_Absolute token_nbf;
348 struct GNUNET_TIME_Absolute new_exp;
349 struct GNUNET_TIME_Absolute new_iat;
350 struct GNUNET_TIME_Absolute new_nbf;
351 struct IdentityToken *new_token;
352 struct TokenAttr *cur_value;
353 struct TokenAttr *attr;
354 size_t token_metadata_len;
356 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
357 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
360 //Note: We need the token expiration time here. Not the record expiration
362 //There are two types of tokens: Token that expire on GNS level with
363 //an absolute expiration time. Those are basically tokens that will
364 //be automatically revoked on (record)expiration.
365 //Tokens stored with relative expiration times will expire on the token level (token expiration)
366 //but this service will reissue new tokens that can be retrieved from GNS
369 for (attr = token->attr_head; NULL != attr; attr = attr->next)
371 if (0 == strcmp (attr->name, "exp"))
373 GNUNET_assert (1 == sscanf (attr->val_head->value,
375 &token_exp.abs_value_us));
376 } else if (0 == strcmp (attr->name, "nbf")) {
377 GNUNET_assert (1 == sscanf (attr->val_head->value,
379 &token_nbf.abs_value_us));
382 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
384 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
385 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
387 //This token is not yet expired! Save and skip
388 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
390 min_rel_exp = token_ttl;
396 GNUNET_free (scopes);
398 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Token is expired. Create a new one\n");
403 new_token = token_create (&pub_key,
405 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
406 new_nbf = GNUNET_TIME_absolute_get ();
408 for (attr = token->attr_head; NULL != attr; attr = attr->next)
410 if (0 == strcmp (attr->name, "exp"))
412 token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
414 else if (0 == strcmp (attr->name, "nbf"))
416 token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
418 else if (0 == strcmp (attr->name, "iat"))
420 token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
422 else if ((0 == strcmp (attr->name, "iss"))
423 || (0 == strcmp (attr->name, "aud")))
427 else if (0 == strcmp (attr->name, "sub"))
429 token_add_attr (new_token,
431 attr->val_head->value);
435 GNUNET_CRYPTO_hash (attr->name,
438 //Check if attr still exists. omit of not
440 GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
443 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
445 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
446 new_token->attr_tail,
452 // reassemble and set
453 GNUNET_assert (token_serialize (new_token,
458 token_record[0].data = enc_token_str;
459 token_record[0].data_size = strlen (enc_token_str) + 1;
460 token_record[0].expiration_time = rd_exp; //Old expiration time
461 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
462 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
465 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
466 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
467 + strlen (scopes) + 1; //With 0-Terminator
468 token_metadata = GNUNET_malloc (token_metadata_len);
469 write_ptr = token_metadata;
470 GNUNET_memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
471 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
472 GNUNET_memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
473 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
474 GNUNET_memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
476 token_record[1].data = token_metadata;
477 token_record[1].data_size = token_metadata_len;
478 token_record[1].expiration_time = rd_exp;
479 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
480 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
482 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
489 token_destroy (new_token);
490 token_destroy (token);
491 GNUNET_free (new_ecdhe_privkey);
492 GNUNET_free (enc_token_str);
496 GNUNET_free (scopes);
502 update_identities(void *cls);
511 * @param value the json_t attribute value
512 * @return #GNUNET_YES
515 clear_ego_attrs (void *cls,
516 const struct GNUNET_HashCode *key,
519 struct TokenAttr *attr = value;
520 struct TokenAttrValue *val;
521 struct TokenAttrValue *tmp_val;
522 for (val = attr->val_head; NULL != val;)
525 GNUNET_CONTAINER_DLL_remove (attr->val_head,
528 GNUNET_free (val->value);
532 GNUNET_free (attr->name);
540 token_collect_error_cb (void *cls)
542 struct EgoEntry *ego_entry = cls;
544 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545 ">>> Updating Ego failed!\n");
546 //Clear attribute map for ego
547 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
550 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
551 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
558 token_collect_finished_cb (void *cls)
560 struct EgoEntry *ego_entry = cls;
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563 ">>> Updating Ego finished\n");
564 //Clear attribute map for ego
565 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
568 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
569 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
576 * Update all ID_TOKEN records for an identity and store them
578 * @param cls the identity entry
579 * @param zone the identity
580 * @param lbl the name of the record
581 * @param rd_count number of records
582 * @param rd record data
585 token_collect (void *cls,
586 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
588 unsigned int rd_count,
589 const struct GNUNET_GNSRECORD_Data *rd)
591 struct EgoEntry *ego_entry = cls;
592 const struct GNUNET_GNSRECORD_Data *token_record;
593 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
594 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
595 struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key;
597 //There should be only a single record for a token under a label
600 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
604 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
606 token_metadata_record = &rd[0];
607 token_record = &rd[1];
611 token_record = &rd[0];
612 token_metadata_record = &rd[1];
614 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
616 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
619 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
621 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
625 //Get metadata and decrypt token
626 priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data;
627 ecdhe_privkey = *priv_key;
628 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1];
629 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
631 token_parse2 (token_record->data,
636 label = GNUNET_strdup (lbl);
637 rd_exp = token_record->expiration_time;
639 GNUNET_SCHEDULER_add_now (&handle_token_update,
645 attribute_collect_error_cb (void *cls)
647 struct EgoEntry *ego_entry = cls;
649 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
650 ">>> Updating Attributes failed!\n");
651 ego_entry->attributes_dirty = GNUNET_NO;
652 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
658 attribute_collect_finished_cb (void *cls)
660 struct EgoEntry *ego_entry = cls;
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 ">>> Updating Attributes finished\n");
664 ego_entry->attributes_dirty = GNUNET_NO;
665 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
672 * Collect all ID_ATTR records for an identity and store them
674 * @param cls the identity entry
675 * @param zone the identity
676 * @param lbl the name of the record
677 * @param rd_count number of records
678 * @param rd record data
682 attribute_collect (void *cls,
683 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
685 unsigned int rd_count,
686 const struct GNUNET_GNSRECORD_Data *rd)
688 struct EgoEntry *ego_entry = cls;
689 struct GNUNET_HashCode key;
690 struct TokenAttr *attr;
691 struct TokenAttrValue *val;
697 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
700 GNUNET_CRYPTO_hash (lbl,
705 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
707 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
710 attr = GNUNET_malloc (sizeof (struct TokenAttr));
711 attr->name = GNUNET_strdup (lbl);
712 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
713 val->value = val_str;
714 GNUNET_CONTAINER_DLL_insert (attr->val_head,
717 GNUNET_assert (GNUNET_OK ==
718 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
721 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
724 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
728 attr = GNUNET_malloc (sizeof (struct TokenAttr));
729 attr->name = GNUNET_strdup (lbl);
730 for (i = 0; i < rd_count; i++)
732 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
734 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
737 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
738 val->value = val_str;
739 GNUNET_CONTAINER_DLL_insert (attr->val_head,
744 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
747 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
748 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
753 * Update identity information for ego. If attribute map is
754 * dirty, first update the attributes.
756 * @param cls the ego to update
759 update_identities(void *cls)
761 struct EgoEntry *next_ego = cls;
762 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
765 if (NULL == next_ego)
767 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
768 min_rel_exp = MIN_WAIT_TIME;
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770 ">>> Finished. Rescheduling in %"SCNu64"\n",
771 min_rel_exp.rel_value_us);
773 //finished -> reschedule
774 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
777 min_rel_exp.rel_value_us = 0;
780 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
781 if (GNUNET_YES == next_ego->attributes_dirty)
783 //Starting over. We must update the Attributes for they might have changed.
784 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
786 &attribute_collect_error_cb,
790 &attribute_collect_finished_cb,
796 //Ego will be dirty next time
797 next_ego->attributes_dirty = GNUNET_YES;
798 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
800 &token_collect_error_cb,
804 &token_collect_finished_cb,
811 * Function called initially to start update task
816 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
817 //Initially iterate all itenties and refresh all tokens
818 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
824 * Initial ego collection function.
829 * @param identifier ego name
833 struct GNUNET_IDENTITY_Ego *ego,
835 const char *identifier)
837 struct EgoEntry *new_entry;
838 if ((NULL == ego) && (STATE_INIT == state))
840 state = STATE_POST_INIT;
844 if (STATE_INIT == state) {
845 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
846 new_entry->ego = ego;
847 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
849 new_entry->attributes_dirty = GNUNET_YES;
850 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
860 struct EgoEntry *ego_entry;
861 struct EgoEntry *ego_tmp;
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
871 if (NULL != timeout_task)
872 GNUNET_SCHEDULER_cancel (timeout_task);
873 if (NULL != update_task)
874 GNUNET_SCHEDULER_cancel (update_task);
875 if (NULL != identity_handle)
876 GNUNET_IDENTITY_disconnect (identity_handle);
877 if (NULL != gns_handle)
878 GNUNET_GNS_disconnect (gns_handle);
880 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
882 GNUNET_NAMESTORE_cancel (ns_qe);
883 if (NULL != ns_handle)
884 GNUNET_NAMESTORE_disconnect (ns_handle);
890 for (ego_entry = ego_head;
894 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
896 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
901 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
902 ego_entry = ego_entry->next;
903 GNUNET_free (ego_tmp);
911 * @param tc task context
914 do_shutdown (void *cls)
916 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
917 "Shutting down...\n");
922 static struct GNUNET_MQ_Envelope*
923 create_exchange_result_message (const char* token,
925 uint64_t ticket_nonce,
928 struct GNUNET_MQ_Envelope *env;
929 struct ExchangeResultMessage *erm;
930 uint16_t token_len = strlen (token) + 1;
932 env = GNUNET_MQ_msg_extra (erm,
934 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
935 erm->ticket_nonce = htonl (ticket_nonce);
937 GNUNET_memcpy (&erm[1], token, token_len);
942 static struct GNUNET_MQ_Envelope*
943 create_issue_result_message (const char* label,
948 struct GNUNET_MQ_Envelope *env;
949 struct IssueResultMessage *irm;
953 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
954 len = strlen (tmp_str) + 1;
955 env = GNUNET_MQ_msg_extra (irm,
957 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
959 GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
960 GNUNET_free (tmp_str);
965 cleanup_issue_handle (struct IssueHandle *handle)
967 if (NULL != handle->attr_map)
968 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
969 if (NULL != handle->scopes)
970 GNUNET_free (handle->scopes);
971 if (NULL != handle->token)
972 token_destroy (handle->token);
973 if (NULL != handle->ticket)
974 ticket_destroy (handle->ticket);
975 if (NULL != handle->label)
976 GNUNET_free (handle->label);
977 GNUNET_free (handle);
981 store_token_issue_cont (void *cls,
985 struct IssueHandle *handle = cls;
986 struct GNUNET_MQ_Envelope *env;
990 handle->ns_qe = NULL;
991 if (GNUNET_SYSERR == success)
993 cleanup_issue_handle (handle);
994 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
996 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
999 if (GNUNET_OK != ticket_serialize (handle->ticket,
1003 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1004 "Error serializing ticket\n");
1005 cleanup_issue_handle (handle);
1006 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1009 if (GNUNET_OK != token_to_string (handle->token,
1013 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1014 "Error serializing token\n");
1015 GNUNET_free (ticket_str);
1016 cleanup_issue_handle (handle);
1017 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1020 env = create_issue_result_message (handle->label,
1024 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1026 cleanup_issue_handle (handle);
1027 GNUNET_free (ticket_str);
1028 GNUNET_free (token_str);
1033 * Build a token and store it
1035 * @param cls the IssueHandle
1038 sign_and_return_token (void *cls)
1040 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1041 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1042 struct IssueHandle *handle = cls;
1043 struct GNUNET_GNSRECORD_Data token_record[2];
1045 char *enc_token_str;
1046 char *token_metadata;
1050 size_t token_metadata_len;
1054 GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1057 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1059 handle->ticket = ticket_create (handle->nonce,
1064 time = GNUNET_TIME_absolute_get().abs_value_us;
1065 exp_time = time + token_expiration_interval.rel_value_us;
1067 token_add_attr_int (handle->token, "nbf", time);
1068 token_add_attr_int (handle->token, "iat", time);
1069 token_add_attr_int (handle->token, "exp", exp_time);
1070 token_add_attr (handle->token, "nonce", nonce_str);
1072 //Token in a serialized encrypted format
1073 GNUNET_assert (token_serialize (handle->token,
1078 //Token record E,E_K (Token)
1079 token_record[0].data = enc_token_str;
1080 token_record[0].data_size = strlen (enc_token_str) + 1;
1081 token_record[0].expiration_time = exp_time;
1082 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1083 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1086 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1087 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1088 + strlen (handle->scopes) + 1; //With 0-Terminator
1089 token_metadata = GNUNET_malloc (token_metadata_len);
1090 write_ptr = token_metadata;
1091 GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1092 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1093 GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1094 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1095 GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1097 token_record[1].data = token_metadata;
1098 token_record[1].data_size = token_metadata_len;
1099 token_record[1].expiration_time = exp_time;
1100 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1101 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1104 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1109 &store_token_issue_cont,
1111 GNUNET_free (ecdhe_privkey);
1112 GNUNET_free (nonce_str);
1113 GNUNET_free (enc_token_str);
1114 GNUNET_free (token_metadata);
1119 attr_collect_error (void *cls)
1121 struct IssueHandle *handle = cls;
1123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1124 handle->ns_it = NULL;
1125 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1130 attr_collect_finished (void *cls)
1132 struct IssueHandle *handle = cls;
1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1135 handle->ns_it = NULL;
1136 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1141 * Collect attributes for token
1144 attr_collect (void *cls,
1145 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1147 unsigned int rd_count,
1148 const struct GNUNET_GNSRECORD_Data *rd)
1150 struct IssueHandle *handle = cls;
1153 struct GNUNET_HashCode key;
1155 GNUNET_CRYPTO_hash (label,
1159 if (0 == rd_count ||
1160 ( (NULL != handle->attr_map) &&
1161 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1166 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1174 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1176 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1180 token_add_attr (handle->token,
1185 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1190 for (; i < rd_count; i++)
1192 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1194 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1198 token_add_attr (handle->token, label, data);
1203 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1207 cleanup_exchange_handle (struct ExchangeHandle *handle)
1209 if (NULL != handle->ticket)
1210 ticket_destroy (handle->ticket);
1211 if (NULL != handle->token)
1212 token_destroy (handle->token);
1213 GNUNET_free (handle);
1217 process_lookup_result (void *cls, uint32_t rd_count,
1218 const struct GNUNET_GNSRECORD_Data *rd)
1220 struct ExchangeHandle *handle = cls;
1221 struct GNUNET_MQ_Envelope *env;
1225 handle->lookup_request = NULL;
1228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1229 "Number of tokens %d != 2.",
1231 cleanup_exchange_handle (handle);
1232 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1237 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1242 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1243 &handle->aud_privkey,
1247 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1248 &handle->aud_privkey,
1251 env = create_exchange_result_message (token_str,
1253 handle->ticket->payload->nonce,
1255 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1257 cleanup_exchange_handle (handle);
1258 GNUNET_free (record_str);
1259 GNUNET_free (token_str);
1263 * Checks a exchange message
1265 * @param cls client sending the message
1266 * @param xm message of type `struct ExchangeMessage`
1267 * @return #GNUNET_OK if @a xm is well-formed
1270 check_exchange_message (void *cls,
1271 const struct ExchangeMessage *xm)
1275 size = ntohs (xm->header.size);
1276 if (size <= sizeof (struct ExchangeMessage))
1279 return GNUNET_SYSERR;
1286 * Handler for exchange message
1289 * @param client who sent the message
1290 * @param message the message
1293 handle_exchange_message (void *cls,
1294 const struct ExchangeMessage *xm)
1296 struct ExchangeHandle *xchange_handle;
1297 struct GNUNET_SERVICE_Client *client = cls;
1301 ticket = (const char *) &xm[1];
1302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1303 "Received EXCHANGE of `%s' from client\n",
1305 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1306 xchange_handle->aud_privkey = xm->aud_privkey;
1307 xchange_handle->r_id = xm->id;
1308 if (GNUNET_SYSERR == ticket_parse (ticket,
1309 &xchange_handle->aud_privkey,
1310 &xchange_handle->ticket))
1312 GNUNET_free (xchange_handle);
1313 GNUNET_SERVICE_client_drop (client);
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1317 xchange_handle->ticket->payload->label);
1318 GNUNET_asprintf (&lookup_query,
1320 xchange_handle->ticket->payload->label);
1321 GNUNET_SERVICE_client_continue (client);
1322 xchange_handle->client = client;
1323 xchange_handle->lookup_request
1324 = GNUNET_GNS_lookup (gns_handle,
1326 &xchange_handle->ticket->payload->identity_key,
1327 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1328 GNUNET_GNS_LO_LOCAL_MASTER,
1330 &process_lookup_result,
1332 GNUNET_free (lookup_query);
1338 find_existing_token_error (void *cls)
1340 struct IssueHandle *handle = cls;
1341 cleanup_issue_handle (handle);
1342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
1343 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1348 find_existing_token_finished (void *cls)
1350 struct IssueHandle *handle = cls;
1353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354 ">>> No existing token found\n");
1356 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1358 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1361 handle->ns_it = NULL;
1362 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1364 &attr_collect_error,
1368 &attr_collect_finished,
1375 * Look for existing token
1377 * @param cls the identity entry
1378 * @param zone the identity
1379 * @param lbl the name of the record
1380 * @param rd_count number of records
1381 * @param rd record data
1385 find_existing_token (void *cls,
1386 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1388 unsigned int rd_count,
1389 const struct GNUNET_GNSRECORD_Data *rd)
1391 struct IssueHandle *handle = cls;
1392 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1393 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1394 struct GNUNET_HashCode key;
1395 int scope_count_token;
1399 //There should be only a single record for a token under a label
1402 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1406 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1408 token_metadata_record = &rd[0];
1412 token_metadata_record = &rd[1];
1414 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1416 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1419 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1421 (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1422 tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1424 if (0 != memcmp (aud_key, &handle->aud_key,
1425 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1427 char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1428 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1429 //Audience does not match!
1430 char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1431 token_metadata_record->data,
1432 token_metadata_record->data_size);
1433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1434 "Token does not match audience %s vs %s. Moving on\n",
1437 GNUNET_free (tmp_scopes);
1440 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1444 scope = strtok (tmp_scopes, ",");
1445 scope_count_token = 0;
1446 while (NULL != scope)
1448 GNUNET_CRYPTO_hash (scope,
1452 if ((NULL != handle->attr_map) &&
1453 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1456 "Issued token does not include `%s'. Moving on\n", scope);
1457 GNUNET_free (tmp_scopes);
1458 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1461 scope_count_token++;
1462 scope = strtok (NULL, ",");
1464 GNUNET_free (tmp_scopes);
1465 //All scopes in token are also in request. Now
1467 if ((NULL != handle->attr_map) &&
1468 (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
1470 //We have an existing token
1471 handle->label = GNUNET_strdup (lbl);
1472 handle->ns_it = NULL;
1473 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1475 &attr_collect_error,
1479 &attr_collect_finished,
1484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1485 "Nuber of attributes in token do not match request\n");
1487 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1491 * Checks an issue message
1493 * @param cls client sending the message
1494 * @param im message of type `struct IssueMessage`
1495 * @return #GNUNET_OK if @a im is well-formed
1498 check_issue_message(void *cls,
1499 const struct IssueMessage *im)
1503 size = ntohs (im->header.size);
1504 if (size <= sizeof (struct IssueMessage))
1507 return GNUNET_SYSERR;
1509 scopes = (char *) &im[1];
1510 if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1])
1512 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1513 "Malformed scopes received!\n");
1515 return GNUNET_SYSERR;
1522 * Handler for issue message
1525 * @param client who sent the message
1526 * @param message the message
1529 handle_issue_message (void *cls,
1530 const struct IssueMessage *im)
1535 struct GNUNET_HashCode key;
1536 struct IssueHandle *issue_handle;
1537 struct GNUNET_SERVICE_Client *client = cls;
1539 scopes = (const char *) &im[1];
1540 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1541 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1543 scopes_tmp = GNUNET_strdup (scopes);
1545 for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1547 GNUNET_CRYPTO_hash (scope,
1550 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1553 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1555 GNUNET_free (scopes_tmp);
1556 issue_handle->r_id = im->id;
1557 issue_handle->aud_key = im->aud_key;
1558 issue_handle->iss_key = im->iss_key;
1559 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1560 &issue_handle->iss_pkey);
1561 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1562 issue_handle->nonce = ntohl (im->nonce);
1563 GNUNET_SERVICE_client_continue (client);
1564 issue_handle->client = client;
1565 issue_handle->scopes = GNUNET_strdup (scopes);
1566 issue_handle->token = token_create (&issue_handle->iss_pkey,
1567 &issue_handle->aud_key);
1569 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1571 &find_existing_token_error,
1573 &find_existing_token,
1575 &find_existing_token_finished,
1581 * Main function that will be run
1583 * @param cls closure
1584 * @param args remaining command-line arguments
1585 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1586 * @param c configuration
1590 const struct GNUNET_CONFIGURATION_Handle *c,
1591 struct GNUNET_SERVICE_Handle *server)
1595 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1597 //Connect to identity and namestore services
1598 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1599 if (NULL == ns_handle)
1601 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1604 gns_handle = GNUNET_GNS_connect (cfg);
1605 if (NULL == gns_handle)
1607 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1610 identity_handle = GNUNET_IDENTITY_connect (cfg,
1615 GNUNET_CONFIGURATION_get_value_time (cfg,
1616 "identity-provider",
1617 "TOKEN_EXPIRATION_INTERVAL",
1618 &token_expiration_interval))
1620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621 "Time window for zone iteration: %s\n",
1622 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1625 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1628 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1632 * Called whenever a client is disconnected.
1634 * @param cls closure
1635 * @param client identification of the client
1636 * @param app_ctx @a client
1639 client_disconnect_cb (void *cls,
1640 struct GNUNET_SERVICE_Client *client,
1643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644 "Client %p disconnected\n",
1650 * Add a client to our list of active clients.
1653 * @param client client to add
1654 * @param mq message queue for @a client
1655 * @return internal namestore client structure for this client
1658 client_connect_cb (void *cls,
1659 struct GNUNET_SERVICE_Client *client,
1660 struct GNUNET_MQ_Handle *mq)
1662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1663 "Client %p connected\n",
1671 * Define "main" method using service macro.
1674 ("identity-provider",
1675 GNUNET_SERVICE_OPTION_NONE,
1678 &client_disconnect_cb,
1680 GNUNET_MQ_hd_var_size (issue_message,
1681 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE,
1682 struct IssueMessage,
1684 GNUNET_MQ_hd_var_size (exchange_message,
1685 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE,
1686 struct ExchangeMessage,
1688 GNUNET_MQ_handler_end());
1689 /* end of gnunet-service-identity-provider.c */