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;
114 static struct GNUNET_SCHEDULER_Task * update_task;
117 * Timeout for next update pass
119 static struct GNUNET_TIME_Relative min_rel_exp;
123 * Currently processed token
125 static struct IdentityToken *token;
128 * Label for currently processed token
133 * Scopes for processed token
138 * Expiration for processed token
140 static uint64_t rd_exp;
143 * ECDHE Privkey for processed token metadata
145 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
148 * Handle to the statistics service.
150 static struct GNUNET_STATISTICS_Handle *stats;
153 * Notification context, simplifies client broadcasts.
155 static struct GNUNET_SERVER_NotificationContext *nc;
160 static const struct GNUNET_CONFIGURATION_Handle *cfg;
163 struct ExchangeHandle
169 struct GNUNET_SERVER_Client *client;
174 struct TokenTicket *ticket;
179 struct IdentityToken *token;
184 struct GNUNET_GNS_LookupRequest *lookup_request;
189 struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
203 struct GNUNET_SERVER_Client *client;
208 struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
213 struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
218 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
223 struct GNUNET_TIME_Absolute expiration;
238 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
243 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
248 struct IdentityToken *token;
253 struct TokenTicket *ticket;
258 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
261 * The label the token is stored under
267 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
275 struct EgoEntry *next;
280 struct EgoEntry *prev;
285 struct GNUNET_IDENTITY_Ego *ego;
288 * Attribute map. Contains the attributes as json_t
290 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
293 * Attributes are old and should be updated if GNUNET_YES
295 int attributes_dirty;
299 * Continuation for token store call
302 * @param success error code
303 * @param emsg error message
306 store_token_cont (void *cls,
311 if (GNUNET_SYSERR == success)
313 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
314 "Failed to update token: %s\n",
318 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
323 * This function updates the old token with new attributes,
324 * removes deleted attributes and expiration times.
326 * @param cls the ego entry
327 * @param tc task context
330 handle_token_update (void *cls,
331 const struct GNUNET_SCHEDULER_TaskContext *tc)
333 char *token_metadata;
336 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
337 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
338 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
339 struct EgoEntry *ego_entry = cls;
340 struct GNUNET_GNSRECORD_Data token_record[2];
341 struct GNUNET_HashCode key_hash;
342 struct GNUNET_TIME_Relative token_rel_exp;
343 struct GNUNET_TIME_Relative token_ttl;
344 struct GNUNET_TIME_Absolute token_exp;
345 struct GNUNET_TIME_Absolute token_nbf;
346 struct GNUNET_TIME_Absolute new_exp;
347 struct GNUNET_TIME_Absolute new_iat;
348 struct GNUNET_TIME_Absolute new_nbf;
349 struct IdentityToken *new_token;
350 struct TokenAttr *cur_value;
351 struct TokenAttr *attr;
352 size_t token_metadata_len;
354 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
355 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
358 //Note: We need the token expiration time here. Not the record expiration
360 //There are two types of tokens: Token that expire on GNS level with
361 //an absolute expiration time. Those are basically tokens that will
362 //be automatically revoked on (record)expiration.
363 //Tokens stored with relative expiration times will expire on the token level (token expiration)
364 //but this service will reissue new tokens that can be retrieved from GNS
367 for (attr = token->attr_head; NULL != attr; attr = attr->next)
369 if (0 == strcmp (attr->name, "exp"))
371 sscanf (attr->val_head->value,
373 &token_exp.abs_value_us);
374 } else if (0 == strcmp (attr->name, "nbf")) {
375 sscanf (attr->val_head->value,
377 &token_nbf.abs_value_us);
380 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
382 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
383 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
385 //This token is not yet expired! Save and skip
386 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
388 min_rel_exp = token_ttl;
394 GNUNET_free (scopes);
396 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400 "Token is expired. Create a new one\n");
401 new_token = token_create (&pub_key,
403 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
404 new_nbf = GNUNET_TIME_absolute_get ();
406 for (attr = token->attr_head; NULL != attr; attr = attr->next)
408 if (0 == strcmp (attr->name, "exp"))
410 token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
412 else if (0 == strcmp (attr->name, "nbf"))
414 token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
416 else if (0 == strcmp (attr->name, "iat"))
418 token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
420 else if ((0 == strcmp (attr->name, "iss"))
421 || (0 == strcmp (attr->name, "aud")))
425 else if (0 == strcmp (attr->name, "sub"))
427 token_add_attr (new_token,
429 attr->val_head->value);
433 GNUNET_CRYPTO_hash (attr->name,
436 //Check if attr still exists. omit of not
438 GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
441 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
443 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
444 new_token->attr_tail,
450 // reassemble and set
451 GNUNET_assert (token_serialize (new_token,
456 token_record[0].data = enc_token_str;
457 token_record[0].data_size = strlen (enc_token_str) + 1;
458 token_record[0].expiration_time = rd_exp; //Old expiration time
459 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
460 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
463 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
464 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
465 + strlen (scopes) + 1; //With 0-Terminator
466 token_metadata = GNUNET_malloc (token_metadata_len);
467 write_ptr = token_metadata;
468 memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
469 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
470 memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
471 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
472 memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
474 token_record[1].data = token_metadata;
475 token_record[1].data_size = token_metadata_len;
476 token_record[1].expiration_time = rd_exp;
477 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
478 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
480 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
488 token_destroy (new_token);
489 token_destroy (token);
490 GNUNET_free (new_ecdhe_privkey);
491 GNUNET_free (enc_token_str);
495 GNUNET_free (scopes);
500 update_identities(void *cls,
501 const struct GNUNET_SCHEDULER_TaskContext *tc);
509 * @param value the json_t attribute value
513 clear_ego_attrs (void *cls,
514 const struct GNUNET_HashCode *key,
517 struct TokenAttr *attr = value;
518 struct TokenAttrValue *val;
519 struct TokenAttrValue *tmp_val;
520 for (val = attr->val_head; NULL != val;)
523 GNUNET_CONTAINER_DLL_remove (attr->val_head,
526 GNUNET_free (val->value);
530 GNUNET_free (attr->name);
538 * Update all ID_TOKEN records for an identity and store them
540 * @param cls the identity entry
541 * @param zone the identity
542 * @param lbl the name of the record
543 * @param rd_count number of records
544 * @param rd record data
548 token_collect (void *cls,
549 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
551 unsigned int rd_count,
552 const struct GNUNET_GNSRECORD_Data *rd)
554 struct EgoEntry *ego_entry = cls;
555 const struct GNUNET_GNSRECORD_Data *token_record;
556 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
557 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
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,
574 //There should be only a single record for a token under a label
577 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
581 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
583 token_metadata_record = &rd[0];
584 token_record = &rd[1];
586 token_record = &rd[0];
587 token_metadata_record = &rd[1];
589 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
591 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
594 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
596 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
600 //Get metadata and decrypt token
601 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
602 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
603 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
605 token_parse2 (token_record->data,
610 label = GNUNET_strdup (lbl);
611 rd_exp = token_record->expiration_time;
613 GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
619 * Collect all ID_ATTR records for an identity and store them
621 * @param cls the identity entry
622 * @param zone the identity
623 * @param lbl the name of the record
624 * @param rd_count number of records
625 * @param rd record data
629 attribute_collect (void *cls,
630 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
632 unsigned int rd_count,
633 const struct GNUNET_GNSRECORD_Data *rd)
635 struct EgoEntry *ego_entry = cls;
636 struct GNUNET_HashCode key;
637 struct TokenAttr *attr;
638 struct TokenAttrValue *val;
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646 ">>> Updating Attributes finished\n");
647 ego_entry->attributes_dirty = GNUNET_NO;
648 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
654 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
657 GNUNET_CRYPTO_hash (lbl,
662 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
664 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
667 attr = GNUNET_malloc (sizeof (struct TokenAttr));
668 attr->name = GNUNET_strdup (lbl);
669 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
670 val->value = val_str;
671 GNUNET_CONTAINER_DLL_insert (attr->val_head,
674 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
677 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
680 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
684 attr = GNUNET_malloc (sizeof (struct TokenAttr));
685 attr->name = GNUNET_strdup (lbl);
686 for (i = 0; i < rd_count; i++)
688 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
690 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
693 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
694 val->value = val_str;
695 GNUNET_CONTAINER_DLL_insert (attr->val_head,
700 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
703 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
704 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
710 * Update identity information for ego. If attribute map is
711 * dirty, first update the attributes.
713 * @param cls the ego to update
714 * param tc task context
718 update_identities(void *cls,
719 const struct GNUNET_SCHEDULER_TaskContext *tc)
721 struct EgoEntry *next_ego = cls;
722 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
724 if (NULL == next_ego)
726 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
727 min_rel_exp = MIN_WAIT_TIME;
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 ">>> Finished. Rescheduling in %d\n",
730 min_rel_exp.rel_value_us);
732 //finished -> reschedule
733 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
736 min_rel_exp.rel_value_us = 0;
739 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
740 if (GNUNET_YES == next_ego->attributes_dirty)
742 //Starting over. We must update the Attributes for they might have changed.
743 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
751 //Ego will be dirty next time
752 next_ego->attributes_dirty = GNUNET_YES;
753 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
763 * Function called initially to start update task
768 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
769 //Initially iterate all itenties and refresh all tokens
770 update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
774 * Initial ego collection function.
779 * @param identifier ego name
783 struct GNUNET_IDENTITY_Ego *ego,
785 const char *identifier)
787 struct EgoEntry *new_entry;
788 if ((NULL == ego) && (STATE_INIT == state))
790 state = STATE_POST_INIT;
794 if (STATE_INIT == state) {
795 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
796 new_entry->ego = ego;
797 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
799 new_entry->attributes_dirty = GNUNET_YES;
800 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
810 struct EgoEntry *ego_entry;
811 struct EgoEntry *ego_tmp;
813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817 GNUNET_SERVER_notification_context_destroy (nc);
822 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
826 if (NULL != timeout_task)
827 GNUNET_SCHEDULER_cancel (timeout_task);
828 if (NULL != update_task)
829 GNUNET_SCHEDULER_cancel (update_task);
830 if (NULL != identity_handle)
831 GNUNET_IDENTITY_disconnect (identity_handle);
832 if (NULL != gns_handle)
833 GNUNET_GNS_disconnect (gns_handle);
835 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
837 GNUNET_NAMESTORE_cancel (ns_qe);
838 if (NULL != ns_handle)
839 GNUNET_NAMESTORE_disconnect (ns_handle);
845 for (ego_entry = ego_head;
849 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
851 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
856 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
857 ego_entry = ego_entry->next;
858 GNUNET_free (ego_tmp);
866 * @param tc task context
869 do_shutdown (void *cls,
870 const struct GNUNET_SCHEDULER_TaskContext *tc)
872 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
873 "Shutting down...\n");
878 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
879 create_exchange_result_message (const char* token,
881 uint64_t ticket_nonce)
883 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
884 uint16_t token_len = strlen (token) + 1;
885 erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
887 erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
888 erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
890 erm->ticket_nonce = htonl (ticket_nonce);
891 memcpy (&erm[1], token, token_len);
896 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
897 create_issue_result_message (const char* label,
901 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
904 irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
906 + strlen (ticket) + 1
907 + strlen (token) + 1);
908 irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
909 irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
911 + strlen (ticket) + 1
912 + strlen (token) + 1);
913 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
914 memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
915 GNUNET_free (tmp_str);
920 cleanup_issue_handle (struct IssueHandle *handle)
922 if (NULL != handle->attr_map)
923 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
924 if (NULL != handle->scopes)
925 GNUNET_free (handle->scopes);
926 if (NULL != handle->token)
927 token_destroy (handle->token);
928 if (NULL != handle->ticket)
929 ticket_destroy (handle->ticket);
930 if (NULL != handle->label)
931 GNUNET_free (handle->label);
932 GNUNET_free (handle);
936 store_token_issue_cont (void *cls,
940 struct IssueHandle *handle = cls;
941 struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
944 handle->ns_qe = NULL;
945 if (GNUNET_SYSERR == success)
947 cleanup_issue_handle (handle);
948 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
950 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
953 if (GNUNET_OK != ticket_serialize (handle->ticket,
957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
958 "Error serializing ticket\n");
959 cleanup_issue_handle (handle);
960 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
963 if (GNUNET_OK != token_to_string (handle->token,
967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
968 "Error serializing token\n");
969 GNUNET_free (ticket_str);
970 cleanup_issue_handle (handle);
971 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
974 irm = create_issue_result_message (handle->label, ticket_str, token_str);
975 GNUNET_SERVER_notification_context_unicast (nc,
979 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
980 cleanup_issue_handle (handle);
982 GNUNET_free (ticket_str);
983 GNUNET_free (token_str);
987 * Build a GNUid token for identity
988 * @param handle the handle
989 * @param ego_entry the ego to build the token for
990 * @param name name of the ego
991 * @param token_aud token audience
992 * @param token the resulting gnuid token
993 * @return identifier string of token (label)
996 sign_and_return_token (void *cls,
997 const struct GNUNET_SCHEDULER_TaskContext *tc)
999 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1000 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1001 struct IssueHandle *handle = cls;
1002 struct GNUNET_GNSRECORD_Data token_record[2];
1004 char *enc_token_str;
1005 char *token_metadata;
1009 size_t token_metadata_len;
1013 GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1016 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1018 handle->ticket = ticket_create (handle->nonce,
1023 time = GNUNET_TIME_absolute_get().abs_value_us;
1024 exp_time = time + token_expiration_interval.rel_value_us;
1026 token_add_attr_int (handle->token, "nbf", time);
1027 token_add_attr_int (handle->token, "iat", time);
1028 token_add_attr_int (handle->token, "exp", exp_time);
1029 token_add_attr (handle->token, "nonce", nonce_str);
1031 //Token in a serialized encrypted format
1032 GNUNET_assert (token_serialize (handle->token,
1037 //Token record E,E_K (Token)
1038 token_record[0].data = enc_token_str;
1039 token_record[0].data_size = strlen (enc_token_str) + 1;
1040 token_record[0].expiration_time = exp_time;
1041 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1042 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1045 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1046 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1047 + strlen (handle->scopes) + 1; //With 0-Terminator
1048 token_metadata = GNUNET_malloc (token_metadata_len);
1049 write_ptr = token_metadata;
1050 memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1051 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1052 memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1053 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1054 memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1056 token_record[1].data = token_metadata;
1057 token_record[1].data_size = token_metadata_len;
1058 token_record[1].expiration_time = exp_time;
1059 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1060 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1063 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1068 &store_token_issue_cont,
1070 GNUNET_free (ecdhe_privkey);
1071 GNUNET_free (nonce_str);
1072 GNUNET_free (enc_token_str);
1073 GNUNET_free (token_metadata);
1077 * Collect attributes for token
1080 attr_collect (void *cls,
1081 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1083 unsigned int rd_count,
1084 const struct GNUNET_GNSRECORD_Data *rd)
1088 struct IssueHandle *handle = cls;
1089 struct GNUNET_HashCode key;
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1094 handle->ns_it = NULL;
1095 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1099 GNUNET_CRYPTO_hash (label,
1103 if (0 == rd_count ||
1104 ( (NULL != handle->attr_map) &&
1105 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1110 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1118 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1120 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1124 token_add_attr (handle->token,
1129 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1134 for (; i < rd_count; i++)
1136 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1138 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1142 token_add_attr (handle->token, label, data);
1147 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1151 cleanup_exchange_handle (struct ExchangeHandle *handle)
1153 if (NULL != handle->ticket)
1154 ticket_destroy (handle->ticket);
1155 if (NULL != handle->token)
1156 token_destroy (handle->token);
1157 GNUNET_free (handle);
1161 process_lookup_result (void *cls, uint32_t rd_count,
1162 const struct GNUNET_GNSRECORD_Data *rd)
1164 struct ExchangeHandle *handle = cls;
1165 struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1169 handle->lookup_request = NULL;
1172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1173 "Number of tokens %d != 2.",
1175 cleanup_exchange_handle (handle);
1176 GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1181 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1186 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1187 &handle->aud_privkey,
1191 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1192 &handle->aud_privkey,
1195 erm = create_exchange_result_message (token_str,
1197 handle->ticket->payload->nonce);
1198 GNUNET_SERVER_notification_context_unicast (nc,
1202 GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1204 cleanup_exchange_handle (handle);
1205 GNUNET_free (record_str);
1206 GNUNET_free (token_str);
1215 * Handler for exchange message
1218 * @param client who sent the message
1219 * @param message the message
1222 handle_exchange_message (void *cls,
1223 struct GNUNET_SERVER_Client *client,
1224 const struct GNUNET_MessageHeader *message)
1226 const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1227 struct ExchangeHandle *xchange_handle;
1232 size = ntohs (message->size);
1233 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1236 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1239 em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1240 ticket = (const char *) &em[1];
1241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1242 "Received EXCHANGE of `%s' from client\n",
1244 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1245 xchange_handle->aud_privkey = em->aud_privkey;
1247 if (GNUNET_SYSERR == ticket_parse (ticket,
1248 &xchange_handle->aud_privkey,
1249 &xchange_handle->ticket))
1251 GNUNET_free (xchange_handle);
1252 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1256 xchange_handle->ticket->payload->label);
1257 GNUNET_asprintf (&lookup_query,
1259 xchange_handle->ticket->payload->label);
1260 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1261 GNUNET_SERVER_notification_context_add (nc, client);
1262 GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1263 xchange_handle->client = client;
1264 xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1266 &xchange_handle->ticket->payload->identity_key,
1267 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1268 GNUNET_GNS_LO_LOCAL_MASTER,
1270 &process_lookup_result,
1272 GNUNET_free (lookup_query);
1279 * Look for existing token
1281 * @param cls the identity entry
1282 * @param zone the identity
1283 * @param lbl the name of the record
1284 * @param rd_count number of records
1285 * @param rd record data
1289 find_existing_token (void *cls,
1290 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1292 unsigned int rd_count,
1293 const struct GNUNET_GNSRECORD_Data *rd)
1295 struct IssueHandle *handle = cls;
1296 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1297 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1298 struct GNUNET_HashCode key;
1299 int scope_count_token;
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 ">>> No existing token found\n");
1311 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1313 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1316 handle->ns_it = NULL;
1317 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1324 //There should be only a single record for a token under a label
1327 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1331 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1333 token_metadata_record = &rd[0];
1335 token_metadata_record = &rd[1];
1337 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1339 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1342 ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1344 (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1345 tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1347 if (0 != memcmp (aud_key, &handle->aud_key,
1348 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1350 char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1351 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1352 //Audience does not match!
1353 char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1354 token_metadata_record->data,
1355 token_metadata_record->data_size);
1356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1357 "Token does not match audience %s vs %s. Moving on\n",
1360 GNUNET_free (tmp_scopes);
1361 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1365 scope = strtok (tmp_scopes, ",");
1366 scope_count_token = 0;
1367 while (NULL != scope)
1369 GNUNET_CRYPTO_hash (scope,
1373 if ((NULL != handle->attr_map) &&
1374 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1377 "Issued token does not include `%s'. Moving on\n", scope);
1378 GNUNET_free (tmp_scopes);
1379 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1382 scope_count_token++;
1383 scope = strtok (NULL, ",");
1385 GNUNET_free (tmp_scopes);
1386 //All scopes in token are also in request. Now
1388 if (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token)
1390 //We have an existing token
1391 handle->label = GNUNET_strdup (lbl);
1392 handle->ns_it = NULL;
1393 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1400 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1401 "Nuber of attributes in token do not match request\n");
1403 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1409 * Handler for issue message
1412 * @param client who sent the message
1413 * @param message the message
1416 handle_issue_message (void *cls,
1417 struct GNUNET_SERVER_Client *client,
1418 const struct GNUNET_MessageHeader *message)
1420 const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1426 struct GNUNET_HashCode key;
1427 struct IssueHandle *issue_handle;
1429 size = ntohs (message->size);
1430 if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1433 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1436 im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1437 scopes = (const char *) &im[1];
1438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1439 "Received ISSUE of `%s' from client\n",
1441 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1442 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1444 scopes_tmp = GNUNET_strdup (scopes);
1445 scope = strtok(scopes_tmp, ",");
1446 for (; NULL != scope; scope = strtok (NULL, ","))
1448 GNUNET_CRYPTO_hash (scope,
1451 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1454 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1456 GNUNET_free (scopes_tmp);
1458 issue_handle->aud_key = im->aud_key;
1459 issue_handle->iss_key = im->iss_key;
1460 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1461 &issue_handle->iss_pkey);
1462 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1463 issue_handle->nonce = ntohl (im->nonce);
1464 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1465 GNUNET_SERVER_notification_context_add (nc, client);
1466 GNUNET_SERVER_client_set_user_context (client, issue_handle);
1467 issue_handle->client = client;
1468 issue_handle->scopes = GNUNET_strdup (scopes);
1469 issue_handle->token = token_create (&issue_handle->iss_pkey,
1470 &issue_handle->aud_key);
1472 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1474 &find_existing_token,
1479 * Main function that will be run
1481 * @param cls closure
1482 * @param args remaining command-line arguments
1483 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1484 * @param c configuration
1488 struct GNUNET_SERVER_Handle *server,
1489 const struct GNUNET_CONFIGURATION_Handle *c)
1491 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1492 {&handle_issue_message, NULL,
1493 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1494 {&handle_exchange_message, NULL,
1495 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1501 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1502 GNUNET_SERVER_add_handlers (server, handlers);
1503 nc = GNUNET_SERVER_notification_context_create (server, 1);
1505 //Connect to identity and namestore services
1506 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1507 if (NULL == ns_handle)
1509 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1512 gns_handle = GNUNET_GNS_connect (cfg);
1513 if (NULL == gns_handle)
1515 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1518 identity_handle = GNUNET_IDENTITY_connect (cfg,
1523 GNUNET_CONFIGURATION_get_value_time (cfg,
1524 "identity-provider",
1525 "TOKEN_EXPIRATION_INTERVAL",
1526 &token_expiration_interval))
1528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1529 "Time window for zone iteration: %s\n",
1530 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1533 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1536 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1537 &do_shutdown, NULL);
1545 * @param argc number of arguments from the cli
1546 * @param argv command line arguments
1547 * @return 0 ok, 1 on error
1551 main (int argc, char *const *argv)
1553 return (GNUNET_OK ==
1554 GNUNET_SERVICE_run (argc, argv, "identity-provider",
1555 GNUNET_SERVICE_OPTION_NONE,
1556 &run, NULL)) ? 0 : 1;
1559 /* end of gnunet-rest-server.c */