2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @author Martin Schanzenbach
22 * @file src/identity-provider/gnunet-service-identity-provider.c
23 * @brief Identity Token Service
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_signatures.h"
36 #include "identity_provider.h"
37 #include "identity_token.h"
45 * Normal operation state
47 #define STATE_POST_INIT 1
50 * Minimum interval between updates
52 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
55 * Standard token expiration time
57 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
60 * Service state (to detect initial update pass)
65 * Head of ego entry DLL
67 static struct EgoEntry *ego_head;
70 * Tail of ego entry DLL
72 static struct EgoEntry *ego_tail;
77 static struct GNUNET_IDENTITY_Handle *identity_handle;
80 * Token expiration interval
82 static struct GNUNET_TIME_Relative token_expiration_interval;
87 static struct GNUNET_NAMESTORE_Handle *ns_handle;
92 static struct GNUNET_GNS_Handle *gns_handle;
97 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
102 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
107 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;
202 struct GNUNET_SERVER_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;
261 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
269 struct EgoEntry *next;
274 struct EgoEntry *prev;
279 struct GNUNET_IDENTITY_Ego *ego;
282 * Attribute map. Contains the attributes as json_t
284 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
287 * Attributes are old and should be updated if GNUNET_YES
289 int attributes_dirty;
293 * Continuation for token store call
296 * @param success error code
297 * @param emsg error message
300 store_token_cont (void *cls,
305 if (GNUNET_SYSERR == success)
307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
308 "Failed to update token: %s\n",
312 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
317 * This function updates the old token with new attributes,
318 * removes deleted attributes and expiration times.
320 * @param cls the ego entry
321 * @param tc task context
324 handle_token_update (void *cls,
325 const struct GNUNET_SCHEDULER_TaskContext *tc)
327 char *token_metadata;
331 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
332 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
333 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
334 struct EgoEntry *ego_entry = cls;
335 struct GNUNET_GNSRECORD_Data token_record[2];
336 struct GNUNET_HashCode key_hash;
337 struct GNUNET_TIME_Relative token_rel_exp;
338 struct GNUNET_TIME_Relative token_ttl;
339 struct GNUNET_TIME_Absolute token_exp;
340 struct GNUNET_TIME_Absolute token_nbf;
341 struct GNUNET_TIME_Absolute new_exp;
342 struct GNUNET_TIME_Absolute new_iat;
343 struct GNUNET_TIME_Absolute new_nbf;
344 struct IdentityToken *new_token;
345 struct TokenAttr *cur_value;
346 struct TokenAttr *attr;
347 size_t token_metadata_len;
349 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
350 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
353 //Note: We need the token expiration time here. Not the record expiration
355 //There are two types of tokens: Token that expire on GNS level with
356 //an absolute expiration time. Those are basically tokens that will
357 //be automatically revoked on (record)expiration.
358 //Tokens stored with relative expiration times will expire on the token level (token expiration)
359 //but this service will reissue new tokens that can be retrieved from GNS
362 for (attr = token->attr_head; NULL != attr; attr = attr->next)
364 if (0 == strcmp (attr->name, "exp"))
366 sscanf (attr->val_head->value,
368 &token_exp.abs_value_us);
369 } else if (0 == strcmp (attr->name, "nbf")) {
370 sscanf (attr->val_head->value,
372 &token_nbf.abs_value_us);
375 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
377 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
378 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
380 //This token is not yet expired! Save and skip
381 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
383 min_rel_exp = token_ttl;
389 GNUNET_free (scopes);
391 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395 "Token is expired. Create a new one\n");
396 new_token = token_create (&pub_key,
398 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
399 new_nbf = GNUNET_TIME_absolute_get ();
401 for (attr = token->attr_head; NULL != attr; attr = attr->next)
403 if (0 == strcmp (attr->name, "exp"))
405 GNUNET_asprintf (&val_str, "%ul", new_exp.abs_value_us);
406 token_add_attr (new_token, attr->name, val_str);
407 GNUNET_free (val_str);
409 else if (0 == strcmp (attr->name, "nbf"))
411 GNUNET_asprintf (&val_str, "%ul", new_nbf.abs_value_us);
412 token_add_attr (new_token, attr->name, val_str);
413 GNUNET_free (val_str);
415 else if (0 == strcmp (attr->name, "iat"))
417 GNUNET_asprintf (&val_str, "%ul", new_iat.abs_value_us);
418 token_add_attr (new_token, attr->name, val_str);
419 GNUNET_free (val_str);
421 else if ((0 == strcmp (attr->name, "iss"))
422 || (0 == strcmp (attr->name, "aud")))
426 else if (0 == strcmp (attr->name, "sub"))
428 token_add_attr (new_token,
430 attr->val_head->value);
434 GNUNET_CRYPTO_hash (attr->name,
437 //Check if attr still exists. omit of not
439 GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
442 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
444 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
445 new_token->attr_tail,
451 // reassemble and set
452 GNUNET_assert (token_serialize (new_token,
457 token_record[0].data = enc_token_str;
458 token_record[0].data_size = strlen (enc_token_str) + 1;
459 token_record[0].expiration_time = rd_exp; //Old expiration time
460 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
461 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
464 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
465 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
466 + strlen (scopes) + 1; //With 0-Terminator
467 token_metadata = GNUNET_malloc (token_metadata_len);
468 write_ptr = token_metadata;
469 memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
470 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
471 memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
472 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
473 memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
475 token_record[1].data = token_metadata;
476 token_record[1].data_size = token_metadata_len;
477 token_record[1].expiration_time = rd_exp;
478 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
479 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
481 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
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);
501 update_identities(void *cls,
502 const struct GNUNET_SCHEDULER_TaskContext *tc);
510 * @param value the json_t attribute value
514 clear_ego_attrs (void *cls,
515 const struct GNUNET_HashCode *key,
518 struct TokenAttr *attr = value;
519 struct TokenAttrValue *val;
520 struct TokenAttrValue *tmp_val;
521 for (val = attr->val_head; NULL != val;)
524 GNUNET_CONTAINER_DLL_remove (attr->val_head,
527 GNUNET_free (val->value);
531 GNUNET_free (attr->name);
540 * Update all ID_TOKEN records for an identity and store them
542 * @param cls the identity entry
543 * @param zone the identity
544 * @param lbl the name of the record
545 * @param rd_count number of records
546 * @param rd record data
550 token_collect (void *cls,
551 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
553 unsigned int rd_count,
554 const struct GNUNET_GNSRECORD_Data *rd)
556 struct EgoEntry *ego_entry = cls;
557 const struct GNUNET_GNSRECORD_Data *token_record;
558 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
559 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 ">>> Updating Ego finished\n");
566 //Clear attribute map for ego
567 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
570 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
571 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
576 //There should be only a single record for a token under a label
579 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
583 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
585 token_metadata_record = &rd[0];
586 token_record = &rd[1];
588 token_record = &rd[0];
589 token_metadata_record = &rd[1];
591 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
593 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
596 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
598 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
602 //Get metadata and decrypt token
603 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
604 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
605 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
607 token_parse2 (token_record->data,
612 label = GNUNET_strdup (lbl);
613 rd_exp = token_record->expiration_time;
615 GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
621 * Collect all ID_ATTR records for an identity and store them
623 * @param cls the identity entry
624 * @param zone the identity
625 * @param lbl the name of the record
626 * @param rd_count number of records
627 * @param rd record data
631 attribute_collect (void *cls,
632 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
634 unsigned int rd_count,
635 const struct GNUNET_GNSRECORD_Data *rd)
637 struct EgoEntry *ego_entry = cls;
638 struct GNUNET_HashCode key;
639 struct TokenAttr *attr;
640 struct TokenAttrValue *val;
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 ">>> Updating Attributes finished\n");
649 ego_entry->attributes_dirty = GNUNET_NO;
650 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
656 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
659 GNUNET_CRYPTO_hash (lbl,
664 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
666 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
669 attr = GNUNET_malloc (sizeof (struct TokenAttr));
670 attr->name = GNUNET_strdup (lbl);
671 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
672 val->value = val_str;
673 GNUNET_CONTAINER_DLL_insert (attr->val_head,
676 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
679 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
682 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
686 attr = GNUNET_malloc (sizeof (struct TokenAttr));
687 attr->name = GNUNET_strdup (lbl);
688 for (i = 0; i < rd_count; i++)
690 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
692 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
695 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
696 val->value = val_str;
697 GNUNET_CONTAINER_DLL_insert (attr->val_head,
702 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
705 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
706 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
712 * Update identity information for ego. If attribute map is
713 * dirty, first update the attributes.
715 * @param cls the ego to update
716 * param tc task context
720 update_identities(void *cls,
721 const struct GNUNET_SCHEDULER_TaskContext *tc)
723 struct EgoEntry *next_ego = cls;
724 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
726 if (NULL == next_ego)
728 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
729 min_rel_exp = MIN_WAIT_TIME;
730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
731 ">>> Finished. Rescheduling in %d\n",
732 min_rel_exp.rel_value_us);
734 //finished -> reschedule
735 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
738 min_rel_exp.rel_value_us = 0;
741 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
742 if (GNUNET_YES == next_ego->attributes_dirty)
744 //Starting over. We must update the Attributes for they might have changed.
745 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
753 //Ego will be dirty next time
754 next_ego->attributes_dirty = GNUNET_YES;
755 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
765 * Function called initially to start update task
770 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
771 //Initially iterate all itenties and refresh all tokens
772 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
776 * Initial ego collection function.
781 * @param identifier ego name
785 struct GNUNET_IDENTITY_Ego *ego,
787 const char *identifier)
789 struct EgoEntry *new_entry;
790 if ((NULL == ego) && (STATE_INIT == state))
792 state = STATE_POST_INIT;
796 if (STATE_INIT == state) {
797 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
798 new_entry->ego = ego;
799 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
801 new_entry->attributes_dirty = GNUNET_YES;
802 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
812 struct EgoEntry *ego_entry;
813 struct EgoEntry *ego_tmp;
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 GNUNET_SERVER_notification_context_destroy (nc);
824 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
828 if (NULL != timeout_task)
829 GNUNET_SCHEDULER_cancel (timeout_task);
830 if (NULL != update_task)
831 GNUNET_SCHEDULER_cancel (update_task);
832 if (NULL != identity_handle)
833 GNUNET_IDENTITY_disconnect (identity_handle);
834 if (NULL != gns_handle)
835 GNUNET_GNS_disconnect (gns_handle);
837 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
839 GNUNET_NAMESTORE_cancel (ns_qe);
840 if (NULL != ns_handle)
841 GNUNET_NAMESTORE_disconnect (ns_handle);
847 for (ego_entry = ego_head;
851 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
853 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
858 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
859 ego_entry = ego_entry->next;
860 GNUNET_free (ego_tmp);
868 * @param tc task context
871 do_shutdown (void *cls,
872 const struct GNUNET_SCHEDULER_TaskContext *tc)
874 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
875 "Shutting down...\n");
880 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
881 create_exchange_result_message (const char* token,
884 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
885 uint16_t token_len = strlen (token) + 1;
886 erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
888 erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
889 erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
891 memcpy (&erm[1], token, token_len);
896 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
897 create_issue_result_message (const char* ticket)
899 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
901 irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen(ticket) + 1);
902 irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
903 irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen (ticket) + 1);
904 memcpy (&irm[1], ticket, strlen (ticket) + 1);
909 cleanup_issue_handle (struct IssueHandle *handle)
911 if (NULL != handle->attr_map)
912 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
913 if (NULL != handle->scopes)
914 GNUNET_free (handle->scopes);
915 if (NULL != handle->token)
916 token_destroy (handle->token);
917 if (NULL != handle->ticket)
918 ticket_destroy (handle->ticket);
919 GNUNET_free (handle);
923 store_token_issue_cont (void *cls,
927 struct IssueHandle *handle = cls;
928 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
929 char* token_ticket_str;
930 handle->ns_qe = NULL;
931 if (GNUNET_SYSERR == success)
933 cleanup_issue_handle (handle);
934 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
936 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
939 if (GNUNET_OK != ticket_serialize (handle->ticket,
943 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
944 "Error serializing ticket\n");
945 cleanup_issue_handle (handle);
946 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
949 irm = create_issue_result_message (token_ticket_str);
950 GNUNET_SERVER_notification_context_unicast (nc,
954 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
955 cleanup_issue_handle (handle);
957 GNUNET_free (token_ticket_str);
961 * Build a GNUid token for identity
962 * @param handle the handle
963 * @param ego_entry the ego to build the token for
964 * @param name name of the ego
965 * @param token_aud token audience
966 * @param token the resulting gnuid token
967 * @return identifier string of token (label)
970 sign_and_return_token (void *cls,
971 const struct GNUNET_SCHEDULER_TaskContext *tc)
973 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
974 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
975 struct IssueHandle *handle = cls;
976 struct GNUNET_GNSRECORD_Data token_record[2];
980 char *token_metadata;
986 size_t token_metadata_len;
990 GNUNET_asprintf (&nonce_str, "%d", handle->nonce);
991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
994 rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
996 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
999 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1001 handle->ticket = ticket_create (nonce_str,
1006 time = GNUNET_TIME_absolute_get().abs_value_us;
1007 exp_time = time + token_expiration_interval.rel_value_us;
1009 GNUNET_asprintf (&attr_val, "%ul", time);
1010 token_add_attr (handle->token, "nbf", attr_val);
1011 token_add_attr (handle->token, "iat", attr_val);
1012 GNUNET_free (attr_val);
1013 GNUNET_asprintf (&attr_val, "%ul", exp_time);
1014 token_add_attr (handle->token, "exp", attr_val);
1015 GNUNET_free (attr_val);
1016 token_add_attr (handle->token, "nonce", nonce_str);
1018 //Token in a serialized encrypted format
1019 GNUNET_assert (token_serialize (handle->token,
1024 //Token record E,E_K (Token)
1025 token_record[0].data = enc_token_str;
1026 token_record[0].data_size = strlen (enc_token_str) + 1;
1027 token_record[0].expiration_time = exp_time;
1028 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1029 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1032 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1033 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1034 + strlen (handle->scopes) + 1; //With 0-Terminator
1035 token_metadata = GNUNET_malloc (token_metadata_len);
1036 write_ptr = token_metadata;
1037 memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1038 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1039 memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1040 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1041 memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1043 token_record[1].data = token_metadata;
1044 token_record[1].data_size = token_metadata_len;
1045 token_record[1].expiration_time = exp_time;
1046 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1047 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1050 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1055 &store_token_issue_cont,
1057 GNUNET_free (ecdhe_privkey);
1058 GNUNET_free (lbl_str);
1059 GNUNET_free (nonce_str);
1060 GNUNET_free (enc_token_str);
1061 GNUNET_free (token_metadata);
1065 * Collect attributes for token
1068 attr_collect (void *cls,
1069 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1071 unsigned int rd_count,
1072 const struct GNUNET_GNSRECORD_Data *rd)
1076 struct IssueHandle *handle = cls;
1077 struct GNUNET_HashCode key;
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1082 handle->ns_it = NULL;
1083 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1087 GNUNET_CRYPTO_hash (label,
1091 if (0 == rd_count ||
1092 ( (NULL != handle->attr_map) &&
1093 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1098 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1106 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1108 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1112 token_add_attr (handle->token,
1117 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1122 for (; i < rd_count; i++)
1124 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1126 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1130 token_add_attr (handle->token, label, data);
1135 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1139 cleanup_exchange_handle (struct ExchangeHandle *handle)
1141 if (NULL != handle->ticket)
1142 ticket_destroy (handle->ticket);
1143 if (NULL != handle->token)
1144 token_destroy (handle->token);
1145 GNUNET_free (handle);
1149 process_lookup_result (void *cls, uint32_t rd_count,
1150 const struct GNUNET_GNSRECORD_Data *rd)
1152 struct ExchangeHandle *handle = cls;
1153 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1157 handle->lookup_request = NULL;
1160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1161 "Number of tokens %d != 2.",
1163 cleanup_exchange_handle (handle);
1164 GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1169 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1174 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1175 &handle->aud_privkey,
1179 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1180 &handle->aud_privkey,
1183 erm = create_exchange_result_message (token_str,
1185 GNUNET_SERVER_notification_context_unicast (nc,
1189 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1191 cleanup_exchange_handle (handle);
1192 GNUNET_free (record_str);
1193 GNUNET_free (token_str);
1200 * Handler for exchange message
1203 * @param client who sent the message
1204 * @param message the message
1207 handle_exchange_message (void *cls,
1208 struct GNUNET_SERVER_Client *client,
1209 const struct GNUNET_MessageHeader *message)
1211 const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1212 struct ExchangeHandle *xchange_handle;
1217 size = ntohs (message->size);
1218 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1221 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1224 em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1225 ticket = (const char *) &em[1];
1226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1227 "Received EXCHANGE of `%s' from client\n",
1229 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1230 xchange_handle->aud_privkey = em->aud_privkey;
1232 if (GNUNET_SYSERR == ticket_parse (ticket,
1233 &xchange_handle->aud_privkey,
1234 &xchange_handle->ticket))
1236 GNUNET_free (xchange_handle);
1237 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
1241 xchange_handle->ticket->payload->label);
1242 GNUNET_asprintf (&lookup_query,
1244 xchange_handle->ticket->payload->label);
1245 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1246 GNUNET_SERVER_notification_context_add (nc, client);
1247 GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1248 xchange_handle->client = client;
1249 xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1251 &xchange_handle->ticket->payload->identity_key,
1252 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1253 GNUNET_GNS_LO_LOCAL_MASTER,
1255 &process_lookup_result,
1257 GNUNET_free (lookup_query);
1263 * Handler for issue message
1266 * @param client who sent the message
1267 * @param message the message
1270 handle_issue_message (void *cls,
1271 struct GNUNET_SERVER_Client *client,
1272 const struct GNUNET_MessageHeader *message)
1274 const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1280 struct GNUNET_HashCode key;
1281 struct IssueHandle *issue_handle;
1283 size = ntohs (message->size);
1284 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1287 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1290 im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1291 scopes = (const char *) &im[1];
1292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293 "Received ISSUE of `%s' from client\n",
1295 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1296 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1298 scopes_tmp = GNUNET_strdup (scopes);
1299 scope = strtok(scopes_tmp, ",");
1300 for (; NULL != scope; scope = strtok (NULL, ","))
1302 GNUNET_CRYPTO_hash (scope,
1305 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1308 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1310 GNUNET_free (scopes_tmp);
1312 issue_handle->aud_key = im->aud_key;
1313 issue_handle->iss_key = im->iss_key;
1314 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1315 issue_handle->nonce = im->nonce;
1316 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1317 GNUNET_SERVER_notification_context_add (nc, client);
1318 GNUNET_SERVER_client_set_user_context (client, issue_handle);
1319 issue_handle->client = client;
1320 issue_handle->scopes = GNUNET_strdup (scopes);
1321 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1322 &issue_handle->iss_pkey);
1323 issue_handle->token = token_create (&issue_handle->iss_pkey,
1326 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1333 * Main function that will be run
1335 * @param cls closure
1336 * @param args remaining command-line arguments
1337 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1338 * @param c configuration
1342 struct GNUNET_SERVER_Handle *server,
1343 const struct GNUNET_CONFIGURATION_Handle *c)
1345 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1346 {&handle_issue_message, NULL,
1347 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1348 {&handle_exchange_message, NULL,
1349 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1355 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1356 GNUNET_SERVER_add_handlers (server, handlers);
1357 nc = GNUNET_SERVER_notification_context_create (server, 1);
1359 //Connect to identity and namestore services
1360 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1361 if (NULL == ns_handle)
1363 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1366 gns_handle = GNUNET_GNS_connect (cfg);
1367 if (NULL == gns_handle)
1369 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1372 identity_handle = GNUNET_IDENTITY_connect (cfg,
1377 GNUNET_CONFIGURATION_get_value_time (cfg,
1378 "identity-provider",
1379 "TOKEN_EXPIRATION_INTERVAL",
1380 &token_expiration_interval))
1382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1383 "Time window for zone iteration: %s\n",
1384 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1387 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1390 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1391 &do_shutdown, NULL);
1399 * @param argc number of arguments from the cli
1400 * @param argv command line arguments
1401 * @return 0 ok, 1 on error
1405 main (int argc, char *const *argv)
1407 return (GNUNET_OK ==
1408 GNUNET_SERVICE_run (argc, argv, "identity-provider",
1409 GNUNET_SERVICE_OPTION_NONE,
1410 &run, NULL)) ? 0 : 1;
1413 /* end of gnunet-rest-server.c */