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