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_credential_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_gns_service.h"
36 #include "gnunet_signatures.h"
37 #include "identity_provider.h"
38 #include "identity_token.h"
47 * Normal operation state
49 #define STATE_POST_INIT 1
52 * Minimum interval between updates
54 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
57 * Standard token expiration time
59 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
62 * Service state (to detect initial update pass)
67 * Head of ego entry DLL
69 static struct EgoEntry *ego_head;
72 * Tail of ego entry DLL
74 static struct EgoEntry *ego_tail;
79 static struct GNUNET_IDENTITY_Handle *identity_handle;
82 * Token expiration interval
84 static struct GNUNET_TIME_Relative token_expiration_interval;
89 static struct GNUNET_NAMESTORE_Handle *ns_handle;
94 static struct GNUNET_GNS_Handle *gns_handle;
99 static struct GNUNET_CREDENTIAL_Handle *credential_handle;
104 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
109 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
114 static struct GNUNET_SCHEDULER_Task *timeout_task;
119 static struct GNUNET_SCHEDULER_Task *update_task;
122 * Timeout for next update pass
124 static struct GNUNET_TIME_Relative min_rel_exp;
128 * Currently processed token
130 static struct IdentityToken *token;
133 * Label for currently processed token
138 * Scopes for processed token
143 * Expiration for processed token
145 static uint64_t rd_exp;
148 * ECDHE Privkey for processed token metadata
150 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
153 * Handle to the statistics service.
155 static struct GNUNET_STATISTICS_Handle *stats;
160 static const struct GNUNET_CONFIGURATION_Handle *cfg;
162 struct VerifiedAttributeEntry
167 struct VerifiedAttributeEntry *prev;
172 struct VerifiedAttributeEntry *next;
180 struct ExchangeHandle
186 struct GNUNET_SERVICE_Client *client;
191 struct TokenTicket *ticket;
196 struct IdentityToken *token;
201 struct GNUNET_GNS_LookupRequest *lookup_request;
206 struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
225 struct GNUNET_SERVICE_Client *client;
230 struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
235 struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
240 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
245 struct GNUNET_TIME_Absolute expiration;
255 struct VerifiedAttributeEntry *v_attr_head;
260 struct VerifiedAttributeEntry *v_attr_tail;
270 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
275 struct GNUNET_CREDENTIAL_Request *credential_request;
280 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
285 struct IdentityToken *token;
290 struct TokenTicket *ticket;
295 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
298 * The label the token is stored under
309 * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
317 struct EgoEntry *next;
322 struct EgoEntry *prev;
327 struct GNUNET_IDENTITY_Ego *ego;
330 * Attribute map. Contains the attributes as json_t
332 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
335 * Attributes are old and should be updated if GNUNET_YES
337 int attributes_dirty;
341 * Continuation for token store call
344 * @param success error code
345 * @param emsg error message
348 store_token_cont (void *cls,
353 if (GNUNET_SYSERR == success)
355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356 "Failed to update token: %s\n",
360 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
365 * This function updates the old token with new attributes,
366 * removes deleted attributes and expiration times.
368 * @param cls the ego entry
371 handle_token_update (void *cls)
373 char *token_metadata;
376 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
377 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
378 struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
379 struct EgoEntry *ego_entry = cls;
380 struct GNUNET_GNSRECORD_Data token_record[2];
381 struct GNUNET_HashCode key_hash;
382 struct GNUNET_TIME_Relative token_rel_exp;
383 struct GNUNET_TIME_Relative token_ttl;
384 struct GNUNET_TIME_Absolute token_exp;
385 struct GNUNET_TIME_Absolute token_nbf;
386 struct GNUNET_TIME_Absolute new_exp;
387 struct GNUNET_TIME_Absolute new_iat;
388 struct GNUNET_TIME_Absolute new_nbf;
389 struct IdentityToken *new_token;
390 struct TokenAttr *cur_value;
391 struct TokenAttr *attr;
392 size_t token_metadata_len;
394 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
395 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
398 //Note: We need the token expiration time here. Not the record expiration
400 //There are two types of tokens: Token that expire on GNS level with
401 //an absolute expiration time. Those are basically tokens that will
402 //be automatically revoked on (record)expiration.
403 //Tokens stored with relative expiration times will expire on the token level (token expiration)
404 //but this service will reissue new tokens that can be retrieved from GNS
407 for (attr = token->attr_head; NULL != attr; attr = attr->next)
409 if (0 == strcmp (attr->name, "exp"))
411 GNUNET_assert (1 == sscanf (attr->val_head->value,
413 &token_exp.abs_value_us));
414 } else if (0 == strcmp (attr->name, "nbf")) {
415 GNUNET_assert (1 == sscanf (attr->val_head->value,
417 &token_nbf.abs_value_us));
420 token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
422 token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
423 if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
425 //This token is not yet expired! Save and skip
426 if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
428 min_rel_exp = token_ttl;
434 GNUNET_free (scopes);
436 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "Token is expired. Create a new one\n");
441 new_token = token_create (&pub_key,
443 new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
444 new_nbf = GNUNET_TIME_absolute_get ();
446 for (attr = token->attr_head; NULL != attr; attr = attr->next)
448 if (0 == strcmp (attr->name, "exp"))
450 token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
452 else if (0 == strcmp (attr->name, "nbf"))
454 token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
456 else if (0 == strcmp (attr->name, "iat"))
458 token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
460 else if ((0 == strcmp (attr->name, "iss"))
461 || (0 == strcmp (attr->name, "aud")))
465 else if (0 == strcmp (attr->name, "sub"))
467 token_add_attr (new_token,
469 attr->val_head->value);
473 GNUNET_CRYPTO_hash (attr->name,
476 //Check if attr still exists. omit of not
478 GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
481 cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
483 GNUNET_assert (NULL != cur_value);
484 GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
485 new_token->attr_tail,
491 // reassemble and set
492 GNUNET_assert (token_serialize (new_token,
497 token_record[0].data = enc_token_str;
498 token_record[0].data_size = strlen (enc_token_str) + 1;
499 token_record[0].expiration_time = rd_exp; //Old expiration time
500 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
501 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
504 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
505 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
506 + strlen (scopes) + 1; //With 0-Terminator
507 token_metadata = GNUNET_malloc (token_metadata_len);
508 write_ptr = token_metadata;
509 GNUNET_memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
510 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
511 GNUNET_memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
512 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
513 GNUNET_memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
515 token_record[1].data = token_metadata;
516 token_record[1].data_size = token_metadata_len;
517 token_record[1].expiration_time = rd_exp;
518 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
519 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
521 ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
528 token_destroy (new_token);
529 token_destroy (token);
530 GNUNET_free (new_ecdhe_privkey);
531 GNUNET_free (enc_token_str);
535 GNUNET_free (scopes);
541 update_identities(void *cls);
550 * @param value the json_t attribute value
551 * @return #GNUNET_YES
554 clear_ego_attrs (void *cls,
555 const struct GNUNET_HashCode *key,
558 struct TokenAttr *attr = value;
559 struct TokenAttrValue *val;
560 struct TokenAttrValue *tmp_val;
561 for (val = attr->val_head; NULL != val;)
564 GNUNET_CONTAINER_DLL_remove (attr->val_head,
567 GNUNET_free (val->value);
571 GNUNET_free (attr->name);
579 token_collect_error_cb (void *cls)
581 struct EgoEntry *ego_entry = cls;
583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
584 ">>> Updating Ego failed!\n");
585 //Clear attribute map for ego
586 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
589 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
590 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
597 token_collect_finished_cb (void *cls)
599 struct EgoEntry *ego_entry = cls;
601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
602 ">>> Updating Ego finished\n");
603 //Clear attribute map for ego
604 GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
607 GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
608 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
615 * Update all ID_TOKEN records for an identity and store them
617 * @param cls the identity entry
618 * @param zone the identity
619 * @param lbl the name of the record
620 * @param rd_count number of records
621 * @param rd record data
624 token_collect (void *cls,
625 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
627 unsigned int rd_count,
628 const struct GNUNET_GNSRECORD_Data *rd)
630 struct EgoEntry *ego_entry = cls;
631 const struct GNUNET_GNSRECORD_Data *token_record;
632 const struct GNUNET_GNSRECORD_Data *token_metadata_record;
633 struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
634 struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key;
636 //There should be only a single record for a token under a label
639 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
643 if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
645 token_metadata_record = &rd[0];
646 token_record = &rd[1];
650 token_record = &rd[0];
651 token_metadata_record = &rd[1];
653 if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
655 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
658 if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
660 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
664 //Get metadata and decrypt token
665 priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data;
666 ecdhe_privkey = *priv_key;
667 aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1];
668 scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
670 token_parse2 (token_record->data,
675 label = GNUNET_strdup (lbl);
676 rd_exp = token_record->expiration_time;
678 GNUNET_SCHEDULER_add_now (&handle_token_update,
684 attribute_collect_error_cb (void *cls)
686 struct EgoEntry *ego_entry = cls;
688 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
689 ">>> Updating Attributes failed!\n");
690 ego_entry->attributes_dirty = GNUNET_NO;
691 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
697 attribute_collect_finished_cb (void *cls)
699 struct EgoEntry *ego_entry = cls;
701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 ">>> Updating Attributes finished\n");
703 ego_entry->attributes_dirty = GNUNET_NO;
704 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
711 * Collect all ID_ATTR records for an identity and store them
713 * @param cls the identity entry
714 * @param zone the identity
715 * @param lbl the name of the record
716 * @param rd_count number of records
717 * @param rd record data
721 attribute_collect (void *cls,
722 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
724 unsigned int rd_count,
725 const struct GNUNET_GNSRECORD_Data *rd)
727 struct EgoEntry *ego_entry = cls;
728 struct GNUNET_HashCode key;
729 struct TokenAttr *attr;
730 struct TokenAttrValue *val;
736 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
739 GNUNET_CRYPTO_hash (lbl,
744 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
746 val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
749 attr = GNUNET_malloc (sizeof (struct TokenAttr));
750 attr->name = GNUNET_strdup (lbl);
751 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
752 val->value = val_str;
753 GNUNET_CONTAINER_DLL_insert (attr->val_head,
756 GNUNET_assert (GNUNET_OK ==
757 GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
760 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
763 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
767 attr = GNUNET_malloc (sizeof (struct TokenAttr));
768 attr->name = GNUNET_strdup (lbl);
769 for (i = 0; i < rd_count; i++)
771 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
773 val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
776 val = GNUNET_malloc (sizeof (struct TokenAttrValue));
777 val->value = val_str;
778 GNUNET_CONTAINER_DLL_insert (attr->val_head,
783 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
786 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
787 GNUNET_NAMESTORE_zone_iterator_next (ns_it);
792 * Update identity information for ego. If attribute map is
793 * dirty, first update the attributes.
795 * @param cls the ego to update
798 update_identities(void *cls)
800 struct EgoEntry *next_ego = cls;
801 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
804 if (NULL == next_ego)
806 if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
807 min_rel_exp = MIN_WAIT_TIME;
808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809 ">>> Finished. Rescheduling in %"SCNu64"\n",
810 min_rel_exp.rel_value_us);
812 //finished -> reschedule
813 update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
816 min_rel_exp.rel_value_us = 0;
819 priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
820 if (GNUNET_YES == next_ego->attributes_dirty)
822 //Starting over. We must update the Attributes for they might have changed.
823 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
825 &attribute_collect_error_cb,
829 &attribute_collect_finished_cb,
835 //Ego will be dirty next time
836 next_ego->attributes_dirty = GNUNET_YES;
837 ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
839 &token_collect_error_cb,
843 &token_collect_finished_cb,
850 * Function called initially to start update task
855 GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
856 //Initially iterate all itenties and refresh all tokens
857 update_task = GNUNET_SCHEDULER_add_now (&update_identities,
863 * Initial ego collection function.
868 * @param identifier ego name
872 struct GNUNET_IDENTITY_Ego *ego,
874 const char *identifier)
876 struct EgoEntry *new_entry;
877 if ((NULL == ego) && (STATE_INIT == state))
879 state = STATE_POST_INIT;
883 if (STATE_INIT == state) {
884 new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
885 new_entry->ego = ego;
886 new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
888 new_entry->attributes_dirty = GNUNET_YES;
889 GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
899 struct EgoEntry *ego_entry;
900 struct EgoEntry *ego_tmp;
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
910 if (NULL != timeout_task)
911 GNUNET_SCHEDULER_cancel (timeout_task);
912 if (NULL != update_task)
913 GNUNET_SCHEDULER_cancel (update_task);
914 if (NULL != identity_handle)
915 GNUNET_IDENTITY_disconnect (identity_handle);
916 if (NULL != gns_handle)
917 GNUNET_GNS_disconnect (gns_handle);
918 if (NULL != credential_handle)
919 GNUNET_CREDENTIAL_disconnect (credential_handle);
921 GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
923 GNUNET_NAMESTORE_cancel (ns_qe);
924 if (NULL != ns_handle)
925 GNUNET_NAMESTORE_disconnect (ns_handle);
931 for (ego_entry = ego_head;
935 if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
937 GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
942 GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
943 ego_entry = ego_entry->next;
944 GNUNET_free (ego_tmp);
952 * @param tc task context
955 do_shutdown (void *cls)
957 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
958 "Shutting down...\n");
963 static struct GNUNET_MQ_Envelope*
964 create_exchange_result_message (const char* token,
966 uint64_t ticket_nonce,
969 struct GNUNET_MQ_Envelope *env;
970 struct ExchangeResultMessage *erm;
971 uint16_t token_len = strlen (token) + 1;
973 env = GNUNET_MQ_msg_extra (erm,
975 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
976 erm->ticket_nonce = htonl (ticket_nonce);
978 GNUNET_memcpy (&erm[1], token, token_len);
983 static struct GNUNET_MQ_Envelope*
984 create_issue_result_message (const char* label,
989 struct GNUNET_MQ_Envelope *env;
990 struct IssueResultMessage *irm;
994 GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
995 len = strlen (tmp_str) + 1;
996 env = GNUNET_MQ_msg_extra (irm,
998 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
1000 GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
1001 GNUNET_free (tmp_str);
1006 cleanup_issue_handle (struct IssueHandle *handle)
1008 if (NULL != handle->attr_map)
1009 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
1010 if (NULL != handle->scopes)
1011 GNUNET_free (handle->scopes);
1012 if (NULL != handle->token)
1013 token_destroy (handle->token);
1014 if (NULL != handle->ticket)
1015 ticket_destroy (handle->ticket);
1016 if (NULL != handle->label)
1017 GNUNET_free (handle->label);
1018 if (NULL != handle->ns_it)
1019 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
1020 if (NULL != handle->credential_request)
1021 GNUNET_CREDENTIAL_request_cancel (handle->credential_request);
1022 GNUNET_free (handle);
1026 store_token_issue_cont (void *cls,
1030 struct IssueHandle *handle = cls;
1031 struct GNUNET_MQ_Envelope *env;
1035 handle->ns_qe = NULL;
1036 if (GNUNET_SYSERR == success)
1038 cleanup_issue_handle (handle);
1039 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1041 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1044 if (GNUNET_OK != ticket_serialize (handle->ticket,
1048 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1049 "Error serializing ticket\n");
1050 cleanup_issue_handle (handle);
1051 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1054 if (GNUNET_OK != token_to_string (handle->token,
1058 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1059 "Error serializing token\n");
1060 GNUNET_free (ticket_str);
1061 cleanup_issue_handle (handle);
1062 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1065 env = create_issue_result_message (handle->label,
1069 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1071 cleanup_issue_handle (handle);
1072 GNUNET_free (ticket_str);
1073 GNUNET_free (token_str);
1078 * Build a token and store it
1080 * @param cls the IssueHandle
1083 sign_and_return_token (void *cls)
1085 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1086 struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1087 struct IssueHandle *handle = cls;
1088 struct GNUNET_GNSRECORD_Data token_record[2];
1090 char *enc_token_str;
1091 char *token_metadata;
1095 size_t token_metadata_len;
1099 GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1102 GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1104 handle->ticket = ticket_create (handle->nonce,
1109 time = GNUNET_TIME_absolute_get().abs_value_us;
1110 exp_time = time + token_expiration_interval.rel_value_us;
1112 token_add_attr_int (handle->token, "nbf", time);
1113 token_add_attr_int (handle->token, "iat", time);
1114 token_add_attr_int (handle->token, "exp", exp_time);
1115 token_add_attr (handle->token, "nonce", nonce_str);
1117 //Token in a serialized encrypted format
1118 GNUNET_assert (token_serialize (handle->token,
1123 //Token record E,E_K (Token)
1124 token_record[0].data = enc_token_str;
1125 token_record[0].data_size = strlen (enc_token_str) + 1;
1126 token_record[0].expiration_time = exp_time;
1127 token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1128 token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1131 token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1132 + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1133 + strlen (handle->scopes) + 1; //With 0-Terminator
1134 token_metadata = GNUNET_malloc (token_metadata_len);
1135 write_ptr = token_metadata;
1136 GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1137 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1138 GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1139 write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1140 GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1142 token_record[1].data = token_metadata;
1143 token_record[1].data_size = token_metadata_len;
1144 token_record[1].expiration_time = exp_time;
1145 token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1146 token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1149 handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1154 &store_token_issue_cont,
1156 GNUNET_free (ecdhe_privkey);
1157 GNUNET_free (nonce_str);
1158 GNUNET_free (enc_token_str);
1159 GNUNET_free (token_metadata);
1163 * Credential to JSON
1164 * @param cred the credential
1165 * @return the resulting json, NULL if failed
1168 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
1173 char attribute[cred->issuer_attribute_len + 1];
1176 issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1180 "Issuer in credential malformed\n");
1183 subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
1184 if (NULL == subject)
1186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1187 "Subject in credential malformed\n");
1188 GNUNET_free (issuer);
1191 GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
1192 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
1195 cred->issuer_attribute,
1196 cred->issuer_attribute_len);
1197 attribute[cred->issuer_attribute_len] = '\0';
1198 cred_obj = json_object ();
1199 json_object_set_new (cred_obj, "issuer", json_string (issuer));
1200 json_object_set_new (cred_obj, "subject", json_string (subject));
1201 json_object_set_new (cred_obj, "attribute", json_string (attribute));
1202 json_object_set_new (cred_obj, "signature", json_string (signature));
1203 json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
1204 GNUNET_free (issuer);
1205 GNUNET_free (subject);
1206 GNUNET_free (signature);
1212 handle_vattr_collection (void* cls,
1213 unsigned int d_count,
1214 struct GNUNET_CREDENTIAL_Delegation *dc,
1215 unsigned int c_count,
1216 struct GNUNET_CREDENTIAL_Credential *cred)
1218 struct IssueHandle *handle = cls;
1219 struct VerifiedAttributeEntry *vattr;
1223 handle->credential_request = NULL;
1227 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1230 cred_array = json_array();
1231 for (i=0;i<c_count;i++)
1233 cred_json = credential_to_json (cred);
1234 if (NULL == cred_json)
1236 json_array_append (cred_array, cred_json);
1237 token_add_attr_json (handle->token,
1238 handle->v_attr_head->name,
1241 json_decref (cred_array);
1242 vattr = handle->v_attr_head;
1244 GNUNET_CONTAINER_DLL_remove (handle->v_attr_head,
1245 handle->v_attr_tail,
1247 GNUNET_free (vattr->name);
1248 GNUNET_free (vattr);
1250 if (NULL == handle->v_attr_head)
1252 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1255 handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
1257 handle->v_attr_head->name,
1259 &handle_vattr_collection,
1266 attr_collect_error (void *cls)
1268 struct IssueHandle *handle = cls;
1270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1271 handle->ns_it = NULL;
1272 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1277 attr_collect_finished (void *cls)
1279 struct IssueHandle *handle = cls;
1281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1282 handle->ns_it = NULL;
1284 if (NULL == handle->v_attr_head)
1286 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1289 handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
1291 handle->v_attr_head->name,
1293 &handle_vattr_collection,
1297 * Collect attributes for token
1300 attr_collect (void *cls,
1301 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1303 unsigned int rd_count,
1304 const struct GNUNET_GNSRECORD_Data *rd)
1306 struct IssueHandle *handle = cls;
1309 struct GNUNET_HashCode key;
1311 GNUNET_CRYPTO_hash (label,
1315 if (0 == rd_count ||
1316 ( (NULL != handle->attr_map) &&
1317 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1322 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1330 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1332 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1336 token_add_attr (handle->token,
1341 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1346 for (; i < rd_count; i++)
1348 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1350 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1354 token_add_attr (handle->token, label, data);
1359 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1363 cleanup_exchange_handle (struct ExchangeHandle *handle)
1365 if (NULL != handle->ticket)
1366 ticket_destroy (handle->ticket);
1367 if (NULL != handle->token)
1368 token_destroy (handle->token);
1369 GNUNET_free (handle);
1373 process_lookup_result (void *cls, uint32_t rd_count,
1374 const struct GNUNET_GNSRECORD_Data *rd)
1376 struct ExchangeHandle *handle = cls;
1377 struct GNUNET_MQ_Envelope *env;
1381 handle->lookup_request = NULL;
1384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1385 "Number of tokens %d != 2.",
1387 cleanup_exchange_handle (handle);
1388 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1393 GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1398 GNUNET_assert (GNUNET_OK == token_parse (record_str,
1399 &handle->aud_privkey,
1403 GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1404 &handle->aud_privkey,
1407 env = create_exchange_result_message (token_str,
1409 handle->ticket->payload->nonce,
1411 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1413 cleanup_exchange_handle (handle);
1414 GNUNET_free (record_str);
1415 GNUNET_free (token_str);
1419 * Checks a exchange message
1421 * @param cls client sending the message
1422 * @param xm message of type `struct ExchangeMessage`
1423 * @return #GNUNET_OK if @a xm is well-formed
1426 check_exchange_message (void *cls,
1427 const struct ExchangeMessage *xm)
1431 size = ntohs (xm->header.size);
1432 if (size <= sizeof (struct ExchangeMessage))
1435 return GNUNET_SYSERR;
1442 * Handler for exchange message
1445 * @param client who sent the message
1446 * @param message the message
1449 handle_exchange_message (void *cls,
1450 const struct ExchangeMessage *xm)
1452 struct ExchangeHandle *xchange_handle;
1453 struct GNUNET_SERVICE_Client *client = cls;
1457 ticket = (const char *) &xm[1];
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "Received EXCHANGE of `%s' from client\n",
1461 xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1462 xchange_handle->aud_privkey = xm->aud_privkey;
1463 xchange_handle->r_id = xm->id;
1464 if (GNUNET_SYSERR == ticket_parse (ticket,
1465 &xchange_handle->aud_privkey,
1466 &xchange_handle->ticket))
1468 GNUNET_free (xchange_handle);
1469 GNUNET_SERVICE_client_drop (client);
1472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1473 xchange_handle->ticket->payload->label);
1474 GNUNET_asprintf (&lookup_query,
1476 xchange_handle->ticket->payload->label);
1477 GNUNET_SERVICE_client_continue (client);
1478 xchange_handle->client = client;
1479 xchange_handle->lookup_request
1480 = GNUNET_GNS_lookup (gns_handle,
1482 &xchange_handle->ticket->payload->identity_key,
1483 GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1484 GNUNET_GNS_LO_LOCAL_MASTER,
1485 &process_lookup_result,
1487 GNUNET_free (lookup_query);
1492 * Checks an issue message
1494 * @param cls client sending the message
1495 * @param im message of type `struct IssueMessage`
1496 * @return #GNUNET_OK if @a im is well-formed
1499 check_issue_message(void *cls,
1500 const struct IssueMessage *im)
1504 size = ntohs (im->header.size);
1505 if (size <= sizeof (struct IssueMessage))
1508 return GNUNET_SYSERR;
1510 scopes = (char *) &im[1];
1511 if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1])
1513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1514 "Malformed scopes received!\n");
1516 return GNUNET_SYSERR;
1523 * Handler for issue message
1526 * @param client who sent the message
1527 * @param message the message
1530 handle_issue_message (void *cls,
1531 const struct IssueMessage *im)
1536 const char *v_attrs;
1538 struct GNUNET_HashCode key;
1539 struct IssueHandle *issue_handle;
1540 struct VerifiedAttributeEntry *vattr_entry;
1541 struct GNUNET_SERVICE_Client *client = cls;
1543 scopes = (const char *) &im[1];
1544 v_attrs = (const char *) &im[1] + ntohl(im->scope_len);
1545 issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1546 issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1548 scopes_tmp = GNUNET_strdup (scopes);
1550 for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1552 GNUNET_CRYPTO_hash (scope,
1555 GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1558 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1560 GNUNET_free (scopes_tmp);
1561 scopes_tmp = GNUNET_strdup (v_attrs);
1563 for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1565 vattr_entry = GNUNET_new (struct VerifiedAttributeEntry);
1566 vattr_entry->name = GNUNET_strdup (scope);
1567 GNUNET_CONTAINER_DLL_insert (issue_handle->v_attr_head,
1568 issue_handle->v_attr_tail,
1571 GNUNET_free (scopes_tmp);
1575 issue_handle->r_id = im->id;
1576 issue_handle->aud_key = im->aud_key;
1577 issue_handle->iss_key = im->iss_key;
1578 GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1579 &issue_handle->iss_pkey);
1580 issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1581 issue_handle->nonce = ntohl (im->nonce);
1582 GNUNET_SERVICE_client_continue (client);
1583 issue_handle->client = client;
1584 issue_handle->scopes = GNUNET_strdup (scopes);
1585 issue_handle->token = token_create (&issue_handle->iss_pkey,
1586 &issue_handle->aud_key);
1588 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1590 GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1592 &issue_handle->label);
1594 issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1595 &issue_handle->iss_key,
1596 &attr_collect_error,
1600 &attr_collect_finished,
1606 * Main function that will be run
1608 * @param cls closure
1609 * @param args remaining command-line arguments
1610 * @param cfgfile name of the configuration file used (for saving, can be NULL)
1611 * @param c configuration
1615 const struct GNUNET_CONFIGURATION_Handle *c,
1616 struct GNUNET_SERVICE_Handle *server)
1620 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1622 //Connect to identity and namestore services
1623 ns_handle = GNUNET_NAMESTORE_connect (cfg);
1624 if (NULL == ns_handle)
1626 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1629 gns_handle = GNUNET_GNS_connect (cfg);
1630 if (NULL == gns_handle)
1632 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1634 credential_handle = GNUNET_CREDENTIAL_connect (cfg);
1635 if (NULL == credential_handle)
1637 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
1639 identity_handle = GNUNET_IDENTITY_connect (cfg,
1644 GNUNET_CONFIGURATION_get_value_time (cfg,
1645 "identity-provider",
1646 "TOKEN_EXPIRATION_INTERVAL",
1647 &token_expiration_interval))
1649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1650 "Time window for zone iteration: %s\n",
1651 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1654 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1657 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1661 * Called whenever a client is disconnected.
1663 * @param cls closure
1664 * @param client identification of the client
1665 * @param app_ctx @a client
1668 client_disconnect_cb (void *cls,
1669 struct GNUNET_SERVICE_Client *client,
1672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1673 "Client %p disconnected\n",
1679 * Add a client to our list of active clients.
1682 * @param client client to add
1683 * @param mq message queue for @a client
1684 * @return internal namestore client structure for this client
1687 client_connect_cb (void *cls,
1688 struct GNUNET_SERVICE_Client *client,
1689 struct GNUNET_MQ_Handle *mq)
1691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1692 "Client %p connected\n",
1700 * Define "main" method using service macro.
1703 ("identity-provider",
1704 GNUNET_SERVICE_OPTION_NONE,
1707 &client_disconnect_cb,
1709 GNUNET_MQ_hd_var_size (issue_message,
1710 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE,
1711 struct IssueMessage,
1713 GNUNET_MQ_hd_var_size (exchange_message,
1714 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE,
1715 struct ExchangeMessage,
1717 GNUNET_MQ_handler_end());
1718 /* end of gnunet-service-identity-provider.c */