Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / identity-provider / gnunet-service-identity-provider.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
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.
9
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.
14
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.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file src/identity-provider/gnunet-service-identity-provider.c
23  * @brief Identity Token Service
24  *
25  */
26 #include "platform.h"
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"
38 #include <inttypes.h>
39
40 /**
41  * First pass state
42  */
43 #define STATE_INIT 0
44
45 /**
46  * Normal operation state
47  */
48 #define STATE_POST_INIT 1
49
50 /**
51  * Minimum interval between updates
52  */
53 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
54
55 /**
56  * Standard token expiration time
57  */
58 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
59
60 /**
61  * Service state (to detect initial update pass)
62  */
63 static int state;
64
65 /**
66  * Head of ego entry DLL
67  */
68 static struct EgoEntry *ego_head;
69
70 /**
71  * Tail of ego entry DLL
72  */
73 static struct EgoEntry *ego_tail;
74
75 /**
76  * Identity handle
77  */
78 static struct GNUNET_IDENTITY_Handle *identity_handle;
79
80 /**
81  * Token expiration interval
82  */
83 static struct GNUNET_TIME_Relative token_expiration_interval;
84
85 /**
86  * Namestore handle
87  */
88 static struct GNUNET_NAMESTORE_Handle *ns_handle;
89
90 /**
91  * GNS handle
92  */
93 static struct GNUNET_GNS_Handle *gns_handle;
94
95 /**
96  * Namestore qe
97  */
98 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
99
100 /**
101  * Namestore iterator
102  */
103 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
104
105 /**
106  * Timeout task
107  */
108 static struct GNUNET_SCHEDULER_Task *timeout_task;
109
110 /**
111  * Update task
112  */
113 static struct GNUNET_SCHEDULER_Task *update_task;
114
115 /**
116  * Timeout for next update pass
117  */
118 static struct GNUNET_TIME_Relative min_rel_exp;
119
120
121 /**
122  * Currently processed token
123  */
124 static struct IdentityToken *token;
125
126 /**
127  * Label for currently processed token
128  */
129 static char* label;
130
131 /**
132  * Scopes for processed token
133  */
134 static char* scopes;
135
136 /**
137  * Expiration for processed token
138  */
139 static uint64_t rd_exp;
140
141 /**
142  * ECDHE Privkey for processed token metadata
143  */
144 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
145
146 /**
147  * Handle to the statistics service.
148  */
149 static struct GNUNET_STATISTICS_Handle *stats;
150
151 /**
152  * Our configuration.
153  */
154 static const struct GNUNET_CONFIGURATION_Handle *cfg;
155
156
157 struct ExchangeHandle
158 {
159
160   /**
161    * Client connection
162    */
163   struct GNUNET_SERVICE_Client *client;
164
165   /**
166    * Ticket
167    */
168   struct TokenTicket *ticket;
169
170   /**
171    * Token returned
172    */
173   struct IdentityToken *token;
174
175   /**
176    * LookupRequest
177    */
178   struct GNUNET_GNS_LookupRequest *lookup_request;
179
180   /**
181    * Audience Key
182    */
183   struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
184
185   /**
186    * Label to return
187    */
188   char *label;
189
190   /**
191    * request id
192    */
193   uint32_t r_id;
194 };
195
196 struct IssueHandle
197 {
198
199   /**
200    * Client connection
201    */
202   struct GNUNET_SERVICE_Client *client;
203
204   /**
205    * Issuer Key
206    */
207   struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
208
209   /**
210    * Issue pubkey
211    */
212   struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
213
214   /**
215    * Audience Key
216    */
217   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
218
219   /**
220    * Expiration
221    */
222   struct GNUNET_TIME_Absolute expiration;
223
224   /**
225    * Scopes
226    */
227   char *scopes;
228
229   /**
230    * nonce
231    */
232   uint64_t nonce;
233
234   /**
235    * NS iterator
236    */
237   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
238
239   /**
240    * Attribute map
241    */
242   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
243
244   /**
245    * Token
246    */
247   struct IdentityToken *token;
248
249   /**
250    * Ticket
251    */
252   struct TokenTicket *ticket;
253
254   /**
255    * QueueEntry
256    */
257   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
258
259   /**
260    * The label the token is stored under
261    */
262   char *label;
263
264   /**
265    * request id
266    */
267   uint32_t r_id;
268 };
269
270 /**
271  * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
272  *
273  */
274 struct EgoEntry
275 {
276   /**
277    * DLL
278    */
279   struct EgoEntry *next;
280
281   /**
282    * DLL
283    */
284   struct EgoEntry *prev;
285
286   /**
287    * Ego handle
288    */
289   struct GNUNET_IDENTITY_Ego *ego;
290
291   /**
292    * Attribute map. Contains the attributes as json_t
293    */
294   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
295
296   /**
297    * Attributes are old and should be updated if GNUNET_YES
298    */
299   int attributes_dirty;
300 };
301
302 /**
303  * Continuation for token store call
304  *
305  * @param cls NULL
306  * @param success error code
307  * @param emsg error message
308  */
309 static void
310 store_token_cont (void *cls,
311                   int32_t success,
312                   const char *emsg)
313 {
314   ns_qe = NULL;
315   if (GNUNET_SYSERR == success)
316   {
317     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318                 "Failed to update token: %s\n",
319                 emsg);
320     return;
321   }
322   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
323 }
324
325
326 /**
327  * This function updates the old token with new attributes,
328  * removes deleted attributes and expiration times.
329  *
330  * @param cls the ego entry
331  */
332 static void
333 handle_token_update (void *cls)
334 {
335   char *token_metadata;
336   char *write_ptr;
337   char *enc_token_str;
338   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
339   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
340   struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
341   struct EgoEntry *ego_entry = cls;
342   struct GNUNET_GNSRECORD_Data token_record[2];
343   struct GNUNET_HashCode key_hash;
344   struct GNUNET_TIME_Relative token_rel_exp;
345   struct GNUNET_TIME_Relative token_ttl;
346   struct GNUNET_TIME_Absolute token_exp;
347   struct GNUNET_TIME_Absolute token_nbf;
348   struct GNUNET_TIME_Absolute new_exp;
349   struct GNUNET_TIME_Absolute new_iat;
350   struct GNUNET_TIME_Absolute new_nbf;
351   struct IdentityToken *new_token;
352   struct TokenAttr *cur_value;
353   struct TokenAttr *attr;
354   size_t token_metadata_len;
355
356   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
357   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
358                                       &pub_key);
359
360   //Note: We need the token expiration time here. Not the record expiration
361   //time.
362   //There are two types of tokens: Token that expire on GNS level with
363   //an absolute expiration time. Those are basically tokens that will
364   //be automatically revoked on (record)expiration.
365   //Tokens stored with relative expiration times will expire on the token level (token expiration)
366   //but this service will reissue new tokens that can be retrieved from GNS
367   //automatically.
368
369   for (attr = token->attr_head; NULL != attr; attr = attr->next)
370   {
371     if (0 == strcmp (attr->name, "exp"))
372     {
373       GNUNET_assert (1 == sscanf (attr->val_head->value,
374               "%"SCNu64,
375               &token_exp.abs_value_us));
376     } else if (0 == strcmp (attr->name, "nbf")) {
377       GNUNET_assert (1 == sscanf (attr->val_head->value,
378               "%"SCNu64,
379               &token_nbf.abs_value_us));
380     }
381   }
382   token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
383
384   token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
385   if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
386   {
387     //This token is not yet expired! Save and skip
388     if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
389     {
390       min_rel_exp = token_ttl;
391     }
392     GNUNET_free (token);
393     token = NULL;
394     GNUNET_free (label);
395     label = NULL;
396     GNUNET_free (scopes);
397     scopes = NULL;
398     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
399     return;
400   }
401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402               "Token is expired. Create a new one\n");
403   new_token = token_create (&pub_key,
404                             &token->aud_key);
405   new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
406   new_nbf = GNUNET_TIME_absolute_get ();
407   new_iat = new_nbf;
408   for (attr = token->attr_head; NULL != attr; attr = attr->next)
409   {
410     if (0 == strcmp (attr->name, "exp"))
411     {
412       token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
413     }
414     else if (0 == strcmp (attr->name, "nbf"))
415     {
416       token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
417     }
418     else if (0 == strcmp (attr->name, "iat"))
419     {
420       token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
421     }
422     else if ((0 == strcmp (attr->name, "iss"))
423              || (0 == strcmp (attr->name, "aud")))
424     {
425       //Omit
426     }
427     else if (0 == strcmp (attr->name, "sub"))
428     {
429       token_add_attr (new_token,
430                       attr->name,
431                       attr->val_head->value);
432     }
433     else
434     {
435       GNUNET_CRYPTO_hash (attr->name,
436                           strlen (attr->name),
437                           &key_hash);
438       //Check if attr still exists. omit of not
439       if (GNUNET_NO !=
440           GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
441                                                   &key_hash))
442       {
443         cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
444                                                        &key_hash);
445         GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
446                                      new_token->attr_tail,
447                                      cur_value);
448       }
449     }
450   }
451
452   // reassemble and set
453   GNUNET_assert (token_serialize (new_token,
454                                   priv_key,
455                                   &new_ecdhe_privkey,
456                                   &enc_token_str));
457
458   token_record[0].data = enc_token_str;
459   token_record[0].data_size = strlen (enc_token_str) + 1;
460   token_record[0].expiration_time = rd_exp; //Old expiration time
461   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
462   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
463
464   //Meta
465   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
466     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
467     + strlen (scopes) + 1; //With 0-Terminator
468   token_metadata = GNUNET_malloc (token_metadata_len);
469   write_ptr = token_metadata;
470   GNUNET_memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
471   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
472   GNUNET_memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
473   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
474   GNUNET_memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
475
476   token_record[1].data = token_metadata;
477   token_record[1].data_size = token_metadata_len;
478   token_record[1].expiration_time = rd_exp;
479   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
480   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
481
482   ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
483                                           priv_key,
484                                           label,
485                                           2,
486                                           token_record,
487                                           &store_token_cont,
488                                           ego_entry);
489   token_destroy (new_token);
490   token_destroy (token);
491   GNUNET_free (new_ecdhe_privkey);
492   GNUNET_free (enc_token_str);
493   token = NULL;
494   GNUNET_free (label);
495   label = NULL;
496   GNUNET_free (scopes);
497   scopes = NULL;
498 }
499
500
501 static void
502 update_identities(void *cls);
503
504
505 /**
506  *
507  * Cleanup attr_map
508  *
509  * @param cls NULL
510  * @param key the key
511  * @param value the json_t attribute value
512  * @return #GNUNET_YES
513  */
514 static int
515 clear_ego_attrs (void *cls,
516                  const struct GNUNET_HashCode *key,
517                  void *value)
518 {
519   struct TokenAttr *attr = value;
520   struct TokenAttrValue *val;
521   struct TokenAttrValue *tmp_val;
522   for (val = attr->val_head; NULL != val;)
523   {
524     tmp_val = val->next;
525     GNUNET_CONTAINER_DLL_remove (attr->val_head,
526                                  attr->val_tail,
527                                  val);
528     GNUNET_free (val->value);
529     GNUNET_free (val);
530     val = tmp_val;
531   }
532   GNUNET_free (attr->name);
533   GNUNET_free (attr);
534
535   return GNUNET_YES;
536 }
537
538
539 static void
540 token_collect_error_cb (void *cls)
541 {
542   struct EgoEntry *ego_entry = cls;
543
544   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545               ">>> Updating Ego failed!\n");
546   //Clear attribute map for ego
547   GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
548                                          &clear_ego_attrs,
549                                          ego_entry);
550   GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
551   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
552                                           ego_entry->next);
553
554 }
555
556
557 static void
558 token_collect_finished_cb (void *cls)
559 {
560   struct EgoEntry *ego_entry = cls;
561
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,
566                                          &clear_ego_attrs,
567                                          ego_entry);
568   GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
569   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
570                                           ego_entry->next);
571 }
572
573
574 /**
575  *
576  * Update all ID_TOKEN records for an identity and store them
577  *
578  * @param cls the identity entry
579  * @param zone the identity
580  * @param lbl the name of the record
581  * @param rd_count number of records
582  * @param rd record data
583  */
584 static void
585 token_collect (void *cls,
586                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
587                const char *lbl,
588                unsigned int rd_count,
589                const struct GNUNET_GNSRECORD_Data *rd)
590 {
591   struct EgoEntry *ego_entry = cls;
592   const struct GNUNET_GNSRECORD_Data *token_record;
593   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
594   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
595   struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key;
596
597   //There should be only a single record for a token under a label
598   if (2 != rd_count)
599   {
600     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
601     return;
602   }
603
604   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
605   {
606     token_metadata_record = &rd[0];
607     token_record = &rd[1];
608   }
609   else
610   {
611     token_record = &rd[0];
612     token_metadata_record = &rd[1];
613   }
614   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
615   {
616     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
617     return;
618   }
619   if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
620   {
621     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
622     return;
623   }
624
625   //Get metadata and decrypt token
626   priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data;
627   ecdhe_privkey = *priv_key;
628   aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1];
629   scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
630
631   token_parse2 (token_record->data,
632                 &ecdhe_privkey,
633                 aud_key,
634                 &token);
635
636   label = GNUNET_strdup (lbl);
637   rd_exp = token_record->expiration_time;
638
639   GNUNET_SCHEDULER_add_now (&handle_token_update,
640                             ego_entry);
641 }
642
643
644 static void
645 attribute_collect_error_cb (void *cls)
646 {
647   struct EgoEntry *ego_entry = cls;
648
649   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
650               ">>> Updating Attributes failed!\n");
651   ego_entry->attributes_dirty = GNUNET_NO;
652   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
653                                           ego_entry);
654 }
655
656
657 static void
658 attribute_collect_finished_cb (void *cls)
659 {
660   struct EgoEntry *ego_entry = cls;
661
662   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663               ">>> Updating Attributes finished\n");
664   ego_entry->attributes_dirty = GNUNET_NO;
665   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
666                                           ego_entry);
667 }
668
669
670 /**
671  *
672  * Collect all ID_ATTR records for an identity and store them
673  *
674  * @param cls the identity entry
675  * @param zone the identity
676  * @param lbl the name of the record
677  * @param rd_count number of records
678  * @param rd record data
679  *
680  */
681 static void
682 attribute_collect (void *cls,
683                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
684                    const char *lbl,
685                    unsigned int rd_count,
686                    const struct GNUNET_GNSRECORD_Data *rd)
687 {
688   struct EgoEntry *ego_entry = cls;
689   struct GNUNET_HashCode key;
690   struct TokenAttr *attr;
691   struct TokenAttrValue *val;
692   char *val_str;
693   int i;
694
695   if (0 == rd_count)
696   {
697     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
698     return;
699   }
700   GNUNET_CRYPTO_hash (lbl,
701                       strlen (lbl),
702                       &key);
703   if (1 == rd_count)
704   {
705     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
706     {
707       val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
708                                                   rd->data,
709                                                   rd->data_size);
710       attr = GNUNET_malloc (sizeof (struct TokenAttr));
711       attr->name = GNUNET_strdup (lbl);
712       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
713       val->value = val_str;
714       GNUNET_CONTAINER_DLL_insert (attr->val_head,
715                                    attr->val_tail,
716                                    val);
717       GNUNET_assert (GNUNET_OK ==
718                      GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
719                                                         &key,
720                                                         attr,
721                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
722     }
723
724     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
725     return;
726   }
727
728   attr = GNUNET_malloc (sizeof (struct TokenAttr));
729   attr->name = GNUNET_strdup (lbl);
730   for (i = 0; i < rd_count; i++)
731   {
732     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
733     {
734       val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
735                                                   rd[i].data,
736                                                   rd[i].data_size);
737       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
738       val->value = val_str;
739       GNUNET_CONTAINER_DLL_insert (attr->val_head,
740                                    attr->val_tail,
741                                    val);
742     }
743   }
744   GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
745                                                                  &key,
746                                                                  attr,
747                                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
748   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
749 }
750
751 /**
752  *
753  * Update identity information for ego. If attribute map is
754  * dirty, first update the attributes.
755  *
756  * @param cls the ego to update
757  */
758 static void
759 update_identities(void *cls)
760 {
761   struct EgoEntry *next_ego = cls;
762   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
763
764   update_task = NULL;
765   if (NULL == next_ego)
766   {
767     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
768       min_rel_exp = MIN_WAIT_TIME;
769     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770                 ">>> Finished. Rescheduling in %"SCNu64"\n",
771                 min_rel_exp.rel_value_us);
772     ns_it = NULL;
773     //finished -> reschedule
774     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
775                                                 &update_identities,
776                                                 ego_head);
777     min_rel_exp.rel_value_us = 0;
778     return;
779   }
780   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
781   if (GNUNET_YES == next_ego->attributes_dirty)
782   {
783     //Starting over. We must update the Attributes for they might have changed.
784     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
785                                                    priv_key,
786                                                    &attribute_collect_error_cb,
787                                                    next_ego,
788                                                    &attribute_collect,
789                                                    next_ego,
790                                                    &attribute_collect_finished_cb,
791                                                    next_ego);
792
793   }
794   else
795   {
796     //Ego will be dirty next time
797     next_ego->attributes_dirty = GNUNET_YES;
798     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
799                                                    priv_key,
800                                                    &token_collect_error_cb,
801                                                    next_ego,
802                                                    &token_collect,
803                                                    next_ego,
804                                                    &token_collect_finished_cb,
805                                                    next_ego);
806   }
807 }
808
809
810 /**
811  * Function called initially to start update task
812  */
813 static void
814 init_cont ()
815 {
816   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
817   //Initially iterate all itenties and refresh all tokens
818   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
819                                           ego_head);
820 }
821
822
823 /**
824  * Initial ego collection function.
825  *
826  * @param cls NULL
827  * @param ego ego
828  * @param ctx context
829  * @param identifier ego name
830  */
831 static void
832 list_ego (void *cls,
833           struct GNUNET_IDENTITY_Ego *ego,
834           void **ctx,
835           const char *identifier)
836 {
837   struct EgoEntry *new_entry;
838   if ((NULL == ego) && (STATE_INIT == state))
839   {
840     state = STATE_POST_INIT;
841     init_cont ();
842     return;
843   }
844   if (STATE_INIT == state) {
845     new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
846     new_entry->ego = ego;
847     new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
848                                                                 GNUNET_NO);
849     new_entry->attributes_dirty = GNUNET_YES;
850     GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
851   }
852 }
853
854 /**
855  * Cleanup task
856  */
857 static void
858 cleanup()
859 {
860   struct EgoEntry *ego_entry;
861   struct EgoEntry *ego_tmp;
862
863   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864               "Cleaning up\n");
865   if (NULL != stats)
866   {
867     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
868     stats = NULL;
869   }
870
871   if (NULL != timeout_task)
872     GNUNET_SCHEDULER_cancel (timeout_task);
873   if (NULL != update_task)
874     GNUNET_SCHEDULER_cancel (update_task);
875   if (NULL != identity_handle)
876     GNUNET_IDENTITY_disconnect (identity_handle);
877   if (NULL != gns_handle)
878     GNUNET_GNS_disconnect (gns_handle);
879   if (NULL != ns_it)
880     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
881   if (NULL != ns_qe)
882     GNUNET_NAMESTORE_cancel (ns_qe);
883   if (NULL != ns_handle)
884     GNUNET_NAMESTORE_disconnect (ns_handle);
885   if (NULL != token)
886     GNUNET_free (token);
887   if (NULL != label)
888     GNUNET_free (label);
889
890   for (ego_entry = ego_head;
891        NULL != ego_entry;)
892   {
893     ego_tmp = ego_entry;
894     if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
895     {
896       GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
897                                              &clear_ego_attrs,
898                                              ego_tmp);
899
900     }
901     GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
902     ego_entry = ego_entry->next;
903     GNUNET_free (ego_tmp);
904   }
905 }
906
907 /**
908  * Shutdown task
909  *
910  * @param cls NULL
911  * @param tc task context
912  */
913 static void
914 do_shutdown (void *cls)
915 {
916   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
917               "Shutting down...\n");
918   cleanup();
919 }
920
921
922 static struct GNUNET_MQ_Envelope*
923 create_exchange_result_message (const char* token,
924                                 const char* label,
925                                 uint64_t ticket_nonce,
926                                 uint64_t id)
927 {
928   struct GNUNET_MQ_Envelope *env;
929   struct ExchangeResultMessage *erm;
930   uint16_t token_len = strlen (token) + 1;
931
932   env = GNUNET_MQ_msg_extra (erm,
933                              token_len,
934                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
935   erm->ticket_nonce = htonl (ticket_nonce);
936   erm->id = id;
937   GNUNET_memcpy (&erm[1], token, token_len);
938   return env;
939 }
940
941
942 static struct GNUNET_MQ_Envelope*
943 create_issue_result_message (const char* label,
944                              const char* ticket,
945                              const char* token,
946                              uint64_t id)
947 {
948   struct GNUNET_MQ_Envelope *env;
949   struct IssueResultMessage *irm;
950   char *tmp_str;
951   size_t len;
952
953   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
954   len = strlen (tmp_str) + 1;
955   env = GNUNET_MQ_msg_extra (irm,
956                              len,
957                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
958   irm->id = id;
959   GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
960   GNUNET_free (tmp_str);
961   return env;
962 }
963
964 static void
965 cleanup_issue_handle (struct IssueHandle *handle)
966 {
967   if (NULL != handle->attr_map)
968     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
969   if (NULL != handle->scopes)
970     GNUNET_free (handle->scopes);
971   if (NULL != handle->token)
972     token_destroy (handle->token);
973   if (NULL != handle->ticket)
974     ticket_destroy (handle->ticket);
975   if (NULL != handle->label)
976     GNUNET_free (handle->label);
977   GNUNET_free (handle);
978 }
979
980 static void
981 store_token_issue_cont (void *cls,
982                         int32_t success,
983                         const char *emsg)
984 {
985   struct IssueHandle *handle = cls;
986   struct GNUNET_MQ_Envelope *env;
987   char *ticket_str;
988   char *token_str;
989
990   handle->ns_qe = NULL;
991   if (GNUNET_SYSERR == success)
992   {
993     cleanup_issue_handle (handle);
994     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
995                 "Unknown Error\n");
996     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
997     return;
998   }
999   if (GNUNET_OK != ticket_serialize (handle->ticket,
1000                                      &handle->iss_key,
1001                                      &ticket_str))
1002   {
1003     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1004                 "Error serializing ticket\n");
1005     cleanup_issue_handle (handle);
1006     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1007     return;
1008   }
1009   if (GNUNET_OK != token_to_string (handle->token,
1010                                     &handle->iss_key,
1011                                     &token_str))
1012   {
1013     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1014                 "Error serializing token\n");
1015     GNUNET_free (ticket_str);
1016     cleanup_issue_handle (handle);
1017     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1018     return;
1019   }
1020   env = create_issue_result_message (handle->label,
1021                                      ticket_str,
1022                                      token_str,
1023                                      handle->r_id);
1024   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1025                   env);
1026   cleanup_issue_handle (handle);
1027   GNUNET_free (ticket_str);
1028   GNUNET_free (token_str);
1029 }
1030
1031
1032 /**
1033  * Build a token and store it
1034  *
1035  * @param cls the IssueHandle
1036  */
1037 static void
1038 sign_and_return_token (void *cls)
1039 {
1040   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1041   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1042   struct IssueHandle *handle = cls;
1043   struct GNUNET_GNSRECORD_Data token_record[2];
1044   char *nonce_str;
1045   char *enc_token_str;
1046   char *token_metadata;
1047   char* write_ptr;
1048   uint64_t time;
1049   uint64_t exp_time;
1050   size_t token_metadata_len;
1051
1052   //Remote nonce
1053   nonce_str = NULL;
1054   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1055   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1056
1057   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1058                                       &pub_key);
1059   handle->ticket = ticket_create (handle->nonce,
1060                                   &pub_key,
1061                                   handle->label,
1062                                   &handle->aud_key);
1063
1064   time = GNUNET_TIME_absolute_get().abs_value_us;
1065   exp_time = time + token_expiration_interval.rel_value_us;
1066
1067   token_add_attr_int (handle->token, "nbf", time);
1068   token_add_attr_int (handle->token, "iat", time);
1069   token_add_attr_int (handle->token, "exp", exp_time);
1070   token_add_attr (handle->token, "nonce", nonce_str);
1071
1072   //Token in a serialized encrypted format
1073   GNUNET_assert (token_serialize (handle->token,
1074                                   &handle->iss_key,
1075                                   &ecdhe_privkey,
1076                                   &enc_token_str));
1077
1078   //Token record E,E_K (Token)
1079   token_record[0].data = enc_token_str;
1080   token_record[0].data_size = strlen (enc_token_str) + 1;
1081   token_record[0].expiration_time = exp_time;
1082   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1083   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1084
1085
1086   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1087     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1088     + strlen (handle->scopes) + 1; //With 0-Terminator
1089   token_metadata = GNUNET_malloc (token_metadata_len);
1090   write_ptr = token_metadata;
1091   GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1092   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1093   GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1094   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1095   GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1096
1097   token_record[1].data = token_metadata;
1098   token_record[1].data_size = token_metadata_len;
1099   token_record[1].expiration_time = exp_time;
1100   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1101   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1102
1103   //Persist token
1104   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1105                                                   &handle->iss_key,
1106                                                   handle->label,
1107                                                   2,
1108                                                   token_record,
1109                                                   &store_token_issue_cont,
1110                                                   handle);
1111   GNUNET_free (ecdhe_privkey);
1112   GNUNET_free (nonce_str);
1113   GNUNET_free (enc_token_str);
1114   GNUNET_free (token_metadata);
1115 }
1116
1117
1118 static void
1119 attr_collect_error (void *cls)
1120 {
1121   struct IssueHandle *handle = cls;
1122
1123   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1124   handle->ns_it = NULL;
1125   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1126 }
1127
1128
1129 static void
1130 attr_collect_finished (void *cls)
1131 {
1132   struct IssueHandle *handle = cls;
1133
1134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1135   handle->ns_it = NULL;
1136   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1137 }
1138
1139
1140 /**
1141  * Collect attributes for token
1142  */
1143 static void
1144 attr_collect (void *cls,
1145               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1146               const char *label,
1147               unsigned int rd_count,
1148               const struct GNUNET_GNSRECORD_Data *rd)
1149 {
1150   struct IssueHandle *handle = cls;
1151   int i;
1152   char* data;
1153   struct GNUNET_HashCode key;
1154
1155   GNUNET_CRYPTO_hash (label,
1156                       strlen (label),
1157                       &key);
1158
1159   if (0 == rd_count ||
1160       ( (NULL != handle->attr_map) &&
1161         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1162                                                                &key))
1163       )
1164      )
1165   {
1166     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1167     return;
1168   }
1169
1170   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1171
1172   if (1 == rd_count)
1173   {
1174     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1175     {
1176       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1177                                                rd->data,
1178                                                rd->data_size);
1179       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1180       token_add_attr (handle->token,
1181                       label,
1182                       data);
1183       GNUNET_free (data);
1184     }
1185     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1186     return;
1187   }
1188
1189   i = 0;
1190   for (; i < rd_count; i++)
1191   {
1192     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1193     {
1194       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1195                                                rd[i].data,
1196                                                rd[i].data_size);
1197       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1198       token_add_attr (handle->token, label, data);
1199       GNUNET_free (data);
1200     }
1201   }
1202
1203   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1204 }
1205
1206 static void
1207 cleanup_exchange_handle (struct ExchangeHandle *handle)
1208 {
1209   if (NULL != handle->ticket)
1210     ticket_destroy (handle->ticket);
1211   if (NULL != handle->token)
1212     token_destroy (handle->token);
1213   GNUNET_free (handle);
1214 }
1215
1216 static void
1217 process_lookup_result (void *cls, uint32_t rd_count,
1218                        const struct GNUNET_GNSRECORD_Data *rd)
1219 {
1220   struct ExchangeHandle *handle = cls;
1221   struct GNUNET_MQ_Envelope *env;
1222   char* token_str;
1223   char* record_str;
1224
1225   handle->lookup_request = NULL;
1226   if (2 != rd_count)
1227   {
1228     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1229                 "Number of tokens %d != 2.",
1230                 rd_count);
1231     cleanup_exchange_handle (handle);
1232     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1233     return;
1234   }
1235
1236   record_str =
1237     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1238                                       rd->data,
1239                                       rd->data_size);
1240
1241   //Decrypt and parse
1242   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1243                                             &handle->aud_privkey,
1244                                             &handle->token));
1245
1246   //Readable
1247   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1248                                                &handle->aud_privkey,
1249                                                &token_str));
1250
1251   env = create_exchange_result_message (token_str,
1252                                         handle->label,
1253                                         handle->ticket->payload->nonce,
1254                                         handle->r_id);
1255   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
1256                   env);
1257   cleanup_exchange_handle (handle);
1258   GNUNET_free (record_str);
1259   GNUNET_free (token_str);
1260 }
1261
1262 /**
1263  * Checks a exchange message
1264  *
1265  * @param cls client sending the message
1266  * @param xm message of type `struct ExchangeMessage`
1267  * @return #GNUNET_OK if @a xm is well-formed
1268  */
1269 static int
1270 check_exchange_message (void *cls,
1271                         const struct ExchangeMessage *xm)
1272 {
1273   uint16_t size;
1274
1275   size = ntohs (xm->header.size);
1276   if (size <= sizeof (struct ExchangeMessage))
1277   {
1278     GNUNET_break (0);
1279     return GNUNET_SYSERR;
1280   }
1281   return GNUNET_OK;
1282 }
1283
1284 /**
1285  *
1286  * Handler for exchange message
1287  *
1288  * @param cls unused
1289  * @param client who sent the message
1290  * @param message the message
1291  */
1292 static void
1293 handle_exchange_message (void *cls,
1294                          const struct ExchangeMessage *xm)
1295 {
1296   struct ExchangeHandle *xchange_handle;
1297   struct GNUNET_SERVICE_Client *client = cls;
1298   const char *ticket;
1299   char *lookup_query;
1300
1301   ticket = (const char *) &xm[1];
1302   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1303               "Received EXCHANGE of `%s' from client\n",
1304               ticket);
1305   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1306   xchange_handle->aud_privkey = xm->aud_privkey;
1307   xchange_handle->r_id = xm->id;
1308   if (GNUNET_SYSERR == ticket_parse (ticket,
1309                                      &xchange_handle->aud_privkey,
1310                                      &xchange_handle->ticket))
1311   {
1312     GNUNET_free (xchange_handle);
1313     GNUNET_SERVICE_client_drop (client);
1314     return;
1315   }
1316   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1317               xchange_handle->ticket->payload->label);
1318   GNUNET_asprintf (&lookup_query,
1319                    "%s.gnu",
1320                    xchange_handle->ticket->payload->label);
1321   GNUNET_SERVICE_client_continue (client);
1322   xchange_handle->client = client;
1323   xchange_handle->lookup_request
1324     = GNUNET_GNS_lookup (gns_handle,
1325                          lookup_query,
1326                          &xchange_handle->ticket->payload->identity_key,
1327                          GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1328                          GNUNET_GNS_LO_LOCAL_MASTER,
1329                          &process_lookup_result,
1330                          xchange_handle);
1331   GNUNET_free (lookup_query);
1332
1333 }
1334
1335
1336 static void
1337 find_existing_token_error (void *cls)
1338 {
1339   struct IssueHandle *handle = cls;
1340   cleanup_issue_handle (handle);
1341   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
1342   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1343 }
1344
1345
1346 static void
1347 find_existing_token_finished (void *cls)
1348 {
1349   struct IssueHandle *handle = cls;
1350   uint64_t rnd_key;
1351
1352   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353               ">>> No existing token found\n");
1354   rnd_key =
1355     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1356                               UINT64_MAX);
1357   GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1358                                 sizeof (uint64_t),
1359                                 &handle->label);
1360   handle->ns_it = NULL;
1361   handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1362                                                          &handle->iss_key,
1363                                                          &attr_collect_error,
1364                                                          handle,
1365                                                          &attr_collect,
1366                                                          handle,
1367                                                          &attr_collect_finished,
1368                                                          handle);
1369 }
1370
1371
1372 /**
1373  *
1374  * Look for existing token
1375  *
1376  * @param cls the identity entry
1377  * @param zone the identity
1378  * @param lbl the name of the record
1379  * @param rd_count number of records
1380  * @param rd record data
1381  *
1382  */
1383 static void
1384 find_existing_token (void *cls,
1385                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1386                      const char *lbl,
1387                      unsigned int rd_count,
1388                      const struct GNUNET_GNSRECORD_Data *rd)
1389 {
1390   struct IssueHandle *handle = cls;
1391   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1392   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1393   struct GNUNET_HashCode key;
1394   int scope_count_token;
1395   char *scope;
1396   char *tmp_scopes;
1397
1398   //There should be only a single record for a token under a label
1399   if (2 != rd_count)
1400   {
1401     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1402     return;
1403   }
1404
1405   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1406   {
1407     token_metadata_record = &rd[0];
1408   }
1409   else
1410   {
1411     token_metadata_record = &rd[1];
1412   }
1413   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1414   {
1415     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1416     return;
1417   }
1418   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1419   aud_key =
1420     (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1421   tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1422
1423   if (0 != memcmp (aud_key, &handle->aud_key,
1424                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1425   {
1426     char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1427                                                       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1428     //Audience does not match!
1429     char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1430                                                   token_metadata_record->data,
1431                                                   token_metadata_record->data_size);
1432     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433                 "Token does not match audience %s vs %s. Moving on\n",
1434                 tmp2,
1435                 tmp);
1436     GNUNET_free (tmp_scopes);
1437     GNUNET_free (tmp2);
1438     GNUNET_free (tmp);
1439     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1440     return;
1441   }
1442
1443   scope = strtok (tmp_scopes, ",");
1444   scope_count_token = 0;
1445   while (NULL != scope)
1446   {
1447     GNUNET_CRYPTO_hash (scope,
1448                         strlen (scope),
1449                         &key);
1450
1451     if ((NULL != handle->attr_map) &&
1452         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1453     {
1454       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1455                   "Issued token does not include `%s'. Moving on\n", scope);
1456       GNUNET_free (tmp_scopes);
1457       GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1458       return;
1459     }
1460     scope_count_token++;
1461     scope = strtok (NULL, ",");
1462   }
1463   GNUNET_free (tmp_scopes);
1464   //All scopes in token are also in request. Now
1465   //Check length
1466   if ((NULL != handle->attr_map) &&
1467       (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
1468   {
1469     //We have an existing token
1470     handle->label = GNUNET_strdup (lbl);
1471     handle->ns_it = NULL;
1472     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1473                                                            &handle->iss_key,
1474                                                            &attr_collect_error,
1475                                                            handle,
1476                                                            &attr_collect,
1477                                                            handle,
1478                                                            &attr_collect_finished,
1479                                                            handle);
1480
1481     return;
1482   }
1483   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1484               "Nuber of attributes in token do not match request\n");
1485   //No luck
1486   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1487 }
1488
1489 /**
1490  * Checks an issue message
1491  *
1492  * @param cls client sending the message
1493  * @param im message of type `struct IssueMessage`
1494  * @return #GNUNET_OK if @a im is well-formed
1495  */
1496 static int
1497 check_issue_message(void *cls,
1498                     const struct IssueMessage *im)
1499 {
1500   uint16_t size;
1501
1502   size = ntohs (im->header.size);
1503   if (size <= sizeof (struct IssueMessage))
1504   {
1505     GNUNET_break (0);
1506     return GNUNET_SYSERR;
1507   }
1508   scopes = (char *) &im[1];
1509   if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1])
1510   {
1511     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1512                 "Malformed scopes received!\n");
1513     GNUNET_break (0);
1514     return GNUNET_SYSERR;
1515   }
1516   return GNUNET_OK;
1517 }
1518
1519 /**
1520  *
1521  * Handler for issue message
1522  *
1523  * @param cls unused
1524  * @param client who sent the message
1525  * @param message the message
1526  */
1527 static void
1528 handle_issue_message (void *cls,
1529                       const struct IssueMessage *im)
1530 {
1531   const char *scopes;
1532   char *scopes_tmp;
1533   char *scope;
1534   struct GNUNET_HashCode key;
1535   struct IssueHandle *issue_handle;
1536   struct GNUNET_SERVICE_Client *client = cls;
1537
1538   scopes = (const char *) &im[1];
1539   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1540   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1541                                                                  GNUNET_NO);
1542   scopes_tmp = GNUNET_strdup (scopes);
1543
1544   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1545   {
1546     GNUNET_CRYPTO_hash (scope,
1547                         strlen (scope),
1548                         &key);
1549     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1550                                        &key,
1551                                        scope,
1552                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1553   }
1554   GNUNET_free (scopes_tmp);
1555   issue_handle->r_id = im->id;
1556   issue_handle->aud_key = im->aud_key;
1557   issue_handle->iss_key = im->iss_key;
1558   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1559                                       &issue_handle->iss_pkey);
1560   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1561   issue_handle->nonce = ntohl (im->nonce);
1562   GNUNET_SERVICE_client_continue (client);
1563   issue_handle->client = client;
1564   issue_handle->scopes = GNUNET_strdup (scopes);
1565   issue_handle->token = token_create (&issue_handle->iss_pkey,
1566                                       &issue_handle->aud_key);
1567
1568   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1569                                                                &im->iss_key,
1570                                                                &find_existing_token_error,
1571                                                                issue_handle,
1572                                                                &find_existing_token,
1573                                                                issue_handle,
1574                                                                &find_existing_token_finished,
1575                                                                issue_handle);
1576 }
1577
1578
1579 /**
1580  * Main function that will be run
1581  *
1582  * @param cls closure
1583  * @param args remaining command-line arguments
1584  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1585  * @param c configuration
1586  */
1587 static void
1588 run (void *cls,
1589      const struct GNUNET_CONFIGURATION_Handle *c,
1590      struct GNUNET_SERVICE_Handle *server)
1591 {
1592   cfg = c;
1593
1594   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1595
1596   //Connect to identity and namestore services
1597   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1598   if (NULL == ns_handle)
1599   {
1600     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1601   }
1602
1603   gns_handle = GNUNET_GNS_connect (cfg);
1604   if (NULL == gns_handle)
1605   {
1606     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1607   }
1608
1609   identity_handle = GNUNET_IDENTITY_connect (cfg,
1610                                              &list_ego,
1611                                              NULL);
1612
1613   if (GNUNET_OK ==
1614       GNUNET_CONFIGURATION_get_value_time (cfg,
1615                                            "identity-provider",
1616                                            "TOKEN_EXPIRATION_INTERVAL",
1617                                            &token_expiration_interval))
1618   {
1619     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1620                 "Time window for zone iteration: %s\n",
1621                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1622                                                         GNUNET_YES));
1623   } else {
1624     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1625   }
1626
1627   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1628 }
1629
1630 /**
1631  * Called whenever a client is disconnected.
1632  *
1633  * @param cls closure
1634  * @param client identification of the client
1635  * @param app_ctx @a client
1636  */
1637 static void
1638 client_disconnect_cb (void *cls,
1639                       struct GNUNET_SERVICE_Client *client,
1640                       void *app_ctx)
1641 {
1642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643               "Client %p disconnected\n",
1644               client);
1645 }
1646
1647
1648 /**
1649  * Add a client to our list of active clients.
1650  *
1651  * @param cls NULL
1652  * @param client client to add
1653  * @param mq message queue for @a client
1654  * @return internal namestore client structure for this client
1655  */
1656 static void *
1657 client_connect_cb (void *cls,
1658                    struct GNUNET_SERVICE_Client *client,
1659                    struct GNUNET_MQ_Handle *mq)
1660 {
1661   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1662               "Client %p connected\n",
1663               client);
1664   return client;
1665 }
1666
1667
1668
1669 /**
1670  * Define "main" method using service macro.
1671  */
1672 GNUNET_SERVICE_MAIN
1673 ("identity-provider",
1674  GNUNET_SERVICE_OPTION_NONE,
1675  &run,
1676  &client_connect_cb,
1677  &client_disconnect_cb,
1678  NULL,
1679  GNUNET_MQ_hd_var_size (issue_message,
1680                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE,
1681                         struct IssueMessage,
1682                         NULL),
1683  GNUNET_MQ_hd_var_size (exchange_message,
1684                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE,
1685                         struct ExchangeMessage,
1686                         NULL),
1687  GNUNET_MQ_handler_end());
1688 /* end of gnunet-service-identity-provider.c */