-rps doxygen
[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   struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key;
601
602   //There should be only a single record for a token under a label
603   if (2 != rd_count)
604   {
605     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
606     return;
607   }
608
609   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
610   {
611     token_metadata_record = &rd[0];
612     token_record = &rd[1];
613   }
614   else
615   {
616     token_record = &rd[0];
617     token_metadata_record = &rd[1];
618   }
619   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
620   {
621     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
622     return;
623   }
624   if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
625   {
626     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
627     return;
628   }
629
630   //Get metadata and decrypt token
631   priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data;
632   ecdhe_privkey = *priv_key;
633   aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1];
634   scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
635
636   token_parse2 (token_record->data,
637                 &ecdhe_privkey,
638                 aud_key,
639                 &token);
640
641   label = GNUNET_strdup (lbl);
642   rd_exp = token_record->expiration_time;
643
644   GNUNET_SCHEDULER_add_now (&handle_token_update,
645                             ego_entry);
646 }
647
648
649 static void
650 attribute_collect_error_cb (void *cls)
651 {
652   struct EgoEntry *ego_entry = cls;
653
654   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
655               ">>> Updating Attributes failed!\n");
656   ego_entry->attributes_dirty = GNUNET_NO;
657   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
658                                           ego_entry);
659 }
660
661
662 static void
663 attribute_collect_finished_cb (void *cls)
664 {
665   struct EgoEntry *ego_entry = cls;
666
667   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668               ">>> Updating Attributes finished\n");
669   ego_entry->attributes_dirty = GNUNET_NO;
670   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
671                                           ego_entry);
672 }
673
674
675 /**
676  *
677  * Collect all ID_ATTR records for an identity and store them
678  *
679  * @param cls the identity entry
680  * @param zone the identity
681  * @param lbl the name of the record
682  * @param rd_count number of records
683  * @param rd record data
684  *
685  */
686 static void
687 attribute_collect (void *cls,
688                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
689                    const char *lbl,
690                    unsigned int rd_count,
691                    const struct GNUNET_GNSRECORD_Data *rd)
692 {
693   struct EgoEntry *ego_entry = cls;
694   struct GNUNET_HashCode key;
695   struct TokenAttr *attr;
696   struct TokenAttrValue *val;
697   char *val_str;
698   int i;
699
700   if (0 == rd_count)
701   {
702     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
703     return;
704   }
705   GNUNET_CRYPTO_hash (lbl,
706                       strlen (lbl),
707                       &key);
708   if (1 == rd_count)
709   {
710     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
711     {
712       val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
713                                                   rd->data,
714                                                   rd->data_size);
715       attr = GNUNET_malloc (sizeof (struct TokenAttr));
716       attr->name = GNUNET_strdup (lbl);
717       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
718       val->value = val_str;
719       GNUNET_CONTAINER_DLL_insert (attr->val_head,
720                                    attr->val_tail,
721                                    val);
722       GNUNET_assert (GNUNET_OK == 
723                      GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
724                                                         &key,
725                                                         attr,
726                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
727     }
728
729     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
730     return;
731   }
732
733   attr = GNUNET_malloc (sizeof (struct TokenAttr));
734   attr->name = GNUNET_strdup (lbl);
735   for (i = 0; i < rd_count; i++)
736   {
737     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
738     {
739       val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
740                                                   rd[i].data,
741                                                   rd[i].data_size);
742       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
743       val->value = val_str;
744       GNUNET_CONTAINER_DLL_insert (attr->val_head,
745                                    attr->val_tail,
746                                    val);
747     }
748   }
749   GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
750                                                                  &key,
751                                                                  attr,
752                                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
753   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
754 }
755
756 /**
757  *
758  * Update identity information for ego. If attribute map is
759  * dirty, first update the attributes.
760  *
761  * @param cls the ego to update
762  */
763 static void
764 update_identities(void *cls)
765 {
766   struct EgoEntry *next_ego = cls;
767   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
768
769   update_task = NULL;
770   if (NULL == next_ego)
771   {
772     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
773       min_rel_exp = MIN_WAIT_TIME;
774     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775                 ">>> Finished. Rescheduling in %"SCNu64"\n",
776                 min_rel_exp.rel_value_us);
777     ns_it = NULL;
778     //finished -> reschedule
779     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
780                                                 &update_identities,
781                                                 ego_head);
782     min_rel_exp.rel_value_us = 0;
783     return;
784   }
785   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
786   if (GNUNET_YES == next_ego->attributes_dirty)
787   {
788     //Starting over. We must update the Attributes for they might have changed.
789     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
790                                                    priv_key,
791                                                    &attribute_collect_error_cb,
792                                                    next_ego,
793                                                    &attribute_collect,
794                                                    next_ego,
795                                                    &attribute_collect_finished_cb,
796                                                    next_ego);
797
798   }
799   else
800   {
801     //Ego will be dirty next time
802     next_ego->attributes_dirty = GNUNET_YES;
803     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
804                                                    priv_key,
805                                                    &token_collect_error_cb,
806                                                    next_ego,
807                                                    &token_collect,
808                                                    next_ego,
809                                                    &token_collect_finished_cb,
810                                                    next_ego);
811   }
812 }
813
814
815 /**
816  * Function called initially to start update task
817  */
818 static void
819 init_cont ()
820 {
821   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
822   //Initially iterate all itenties and refresh all tokens
823   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
824                                           ego_head);
825 }
826
827
828 /**
829  * Initial ego collection function.
830  *
831  * @param cls NULL
832  * @param ego ego
833  * @param ctx context
834  * @param identifier ego name
835  */
836 static void
837 list_ego (void *cls,
838           struct GNUNET_IDENTITY_Ego *ego,
839           void **ctx,
840           const char *identifier)
841 {
842   struct EgoEntry *new_entry;
843   if ((NULL == ego) && (STATE_INIT == state))
844   {
845     state = STATE_POST_INIT;
846     init_cont ();
847     return;
848   }
849   if (STATE_INIT == state) {
850     new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
851     new_entry->ego = ego;
852     new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
853                                                                 GNUNET_NO);
854     new_entry->attributes_dirty = GNUNET_YES;
855     GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
856   }
857 }
858
859 /**
860  * Cleanup task
861  */
862 static void
863 cleanup()
864 {
865   struct EgoEntry *ego_entry;
866   struct EgoEntry *ego_tmp;
867
868   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869               "Cleaning up\n");
870   if (NULL != nc)
871   {
872     GNUNET_SERVER_notification_context_destroy (nc);
873     nc = NULL;
874   }
875   if (NULL != stats)
876   {
877     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
878     stats = NULL;
879   }
880
881   if (NULL != timeout_task)
882     GNUNET_SCHEDULER_cancel (timeout_task);
883   if (NULL != update_task)
884     GNUNET_SCHEDULER_cancel (update_task);
885   if (NULL != identity_handle)
886     GNUNET_IDENTITY_disconnect (identity_handle);
887   if (NULL != gns_handle)
888     GNUNET_GNS_disconnect (gns_handle);
889   if (NULL != ns_it)
890     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
891   if (NULL != ns_qe)
892     GNUNET_NAMESTORE_cancel (ns_qe);
893   if (NULL != ns_handle)
894     GNUNET_NAMESTORE_disconnect (ns_handle);
895   if (NULL != token)
896     GNUNET_free (token);
897   if (NULL != label)
898     GNUNET_free (label);
899
900   for (ego_entry = ego_head;
901        NULL != ego_entry;)
902   {
903     ego_tmp = ego_entry;
904     if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
905     {
906       GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
907                                              &clear_ego_attrs,
908                                              ego_tmp);
909
910     }
911     GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
912     ego_entry = ego_entry->next;
913     GNUNET_free (ego_tmp);
914   }
915 }
916
917 /**
918  * Shutdown task
919  *
920  * @param cls NULL
921  * @param tc task context
922  */
923 static void
924 do_shutdown (void *cls)
925 {
926   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
927               "Shutting down...\n");
928   cleanup();
929 }
930
931
932 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
933 create_exchange_result_message (const char* token,
934                                 const char* label,
935                                 uint64_t ticket_nonce)
936 {
937   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
938   uint16_t token_len = strlen (token) + 1;
939   erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
940                        + token_len);
941   erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
942   erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
943                             + token_len);
944   erm->ticket_nonce = htonl (ticket_nonce);
945   GNUNET_memcpy (&erm[1], token, token_len);
946   return erm;
947 }
948
949
950 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
951 create_issue_result_message (const char* label,
952                              const char* ticket,
953                              const char* token)
954 {
955   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
956   char *tmp_str;
957
958   irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
959                        + strlen (label) + 1
960                        + strlen (ticket) + 1
961                        + strlen (token) + 1);
962   irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
963   irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
964                             + strlen (label) + 1
965                             + strlen (ticket) + 1
966                             + strlen (token) + 1);
967   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
968   GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
969   GNUNET_free (tmp_str);
970   return irm;
971 }
972
973 static void
974 cleanup_issue_handle (struct IssueHandle *handle)
975 {
976   if (NULL != handle->attr_map)
977     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
978   if (NULL != handle->scopes)
979     GNUNET_free (handle->scopes);
980   if (NULL != handle->token)
981     token_destroy (handle->token);
982   if (NULL != handle->ticket)
983     ticket_destroy (handle->ticket);
984   if (NULL != handle->label)
985     GNUNET_free (handle->label);
986   GNUNET_free (handle);
987 }
988
989 static void
990 store_token_issue_cont (void *cls,
991                         int32_t success,
992                         const char *emsg)
993 {
994   struct IssueHandle *handle = cls;
995   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
996   char *ticket_str;
997   char *token_str;
998
999   handle->ns_qe = NULL;
1000   if (GNUNET_SYSERR == success)
1001   {
1002     cleanup_issue_handle (handle);
1003     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1004                 "Unknown Error\n");
1005     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1006     return;
1007   }
1008   if (GNUNET_OK != ticket_serialize (handle->ticket,
1009                                      &handle->iss_key,
1010                                      &ticket_str))
1011   {
1012     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1013                 "Error serializing ticket\n");
1014     cleanup_issue_handle (handle);
1015     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1016     return;
1017   }
1018   if (GNUNET_OK != token_to_string (handle->token,
1019                                     &handle->iss_key,
1020                                     &token_str))
1021   {
1022     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1023                 "Error serializing token\n");
1024     GNUNET_free (ticket_str);
1025     cleanup_issue_handle (handle);
1026     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1027     return;
1028   }
1029   irm = create_issue_result_message (handle->label,
1030                                      ticket_str,
1031                                      token_str);
1032   irm->id = handle->r_id;
1033   GNUNET_SERVER_notification_context_unicast (nc,
1034                                               handle->client,
1035                                               &irm->header,
1036                                               GNUNET_NO);
1037   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1038   cleanup_issue_handle (handle);
1039   GNUNET_free (irm);
1040   GNUNET_free (ticket_str);
1041   GNUNET_free (token_str);
1042 }
1043
1044
1045 /**
1046  * Build a token and store it
1047  *
1048  * @param cls the IssueHandle
1049  */
1050 static void
1051 sign_and_return_token (void *cls)
1052 {
1053   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1054   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1055   struct IssueHandle *handle = cls;
1056   struct GNUNET_GNSRECORD_Data token_record[2];
1057   char *nonce_str;
1058   char *enc_token_str;
1059   char *token_metadata;
1060   char* write_ptr;
1061   uint64_t time;
1062   uint64_t exp_time;
1063   size_t token_metadata_len;
1064
1065   //Remote nonce
1066   nonce_str = NULL;
1067   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1068   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1069
1070   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1071                                       &pub_key);
1072   handle->ticket = ticket_create (handle->nonce,
1073                                   &pub_key,
1074                                   handle->label,
1075                                   &handle->aud_key);
1076
1077   time = GNUNET_TIME_absolute_get().abs_value_us;
1078   exp_time = time + token_expiration_interval.rel_value_us;
1079
1080   token_add_attr_int (handle->token, "nbf", time);
1081   token_add_attr_int (handle->token, "iat", time);
1082   token_add_attr_int (handle->token, "exp", exp_time);
1083   token_add_attr (handle->token, "nonce", nonce_str);
1084
1085   //Token in a serialized encrypted format
1086   GNUNET_assert (token_serialize (handle->token,
1087                                   &handle->iss_key,
1088                                   &ecdhe_privkey,
1089                                   &enc_token_str));
1090
1091   //Token record E,E_K (Token)
1092   token_record[0].data = enc_token_str;
1093   token_record[0].data_size = strlen (enc_token_str) + 1;
1094   token_record[0].expiration_time = exp_time;
1095   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1096   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1097
1098
1099   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1100     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1101     + strlen (handle->scopes) + 1; //With 0-Terminator
1102   token_metadata = GNUNET_malloc (token_metadata_len);
1103   write_ptr = token_metadata;
1104   GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1105   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1106   GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1107   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1108   GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1109
1110   token_record[1].data = token_metadata;
1111   token_record[1].data_size = token_metadata_len;
1112   token_record[1].expiration_time = exp_time;
1113   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1114   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1115
1116   //Persist token
1117   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1118                                                   &handle->iss_key,
1119                                                   handle->label,
1120                                                   2,
1121                                                   token_record,
1122                                                   &store_token_issue_cont,
1123                                                   handle);
1124   GNUNET_free (ecdhe_privkey);
1125   GNUNET_free (nonce_str);
1126   GNUNET_free (enc_token_str);
1127   GNUNET_free (token_metadata);
1128 }
1129
1130
1131 static void
1132 attr_collect_error (void *cls)
1133 {
1134   struct IssueHandle *handle = cls;
1135
1136   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
1137   handle->ns_it = NULL;
1138   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1139 }
1140
1141
1142 static void
1143 attr_collect_finished (void *cls)
1144 {
1145   struct IssueHandle *handle = cls;
1146
1147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1148   handle->ns_it = NULL;
1149   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1150 }
1151
1152
1153 /**
1154  * Collect attributes for token
1155  */
1156 static void
1157 attr_collect (void *cls,
1158               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1159               const char *label,
1160               unsigned int rd_count,
1161               const struct GNUNET_GNSRECORD_Data *rd)
1162 {
1163   struct IssueHandle *handle = cls;
1164   int i;
1165   char* data;
1166   struct GNUNET_HashCode key;
1167
1168   GNUNET_CRYPTO_hash (label,
1169                       strlen (label),
1170                       &key);
1171
1172   if (0 == rd_count ||
1173       ( (NULL != handle->attr_map) &&
1174         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1175                                                                &key))
1176       )
1177      )
1178   {
1179     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1180     return;
1181   }
1182
1183   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1184
1185   if (1 == rd_count)
1186   {
1187     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1188     {
1189       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1190                                                rd->data,
1191                                                rd->data_size);
1192       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1193       token_add_attr (handle->token,
1194                       label,
1195                       data);
1196       GNUNET_free (data);
1197     }
1198     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1199     return;
1200   }
1201
1202   i = 0;
1203   for (; i < rd_count; i++)
1204   {
1205     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1206     {
1207       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1208                                                rd[i].data,
1209                                                rd[i].data_size);
1210       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1211       token_add_attr (handle->token, label, data);
1212       GNUNET_free (data);
1213     }
1214   }
1215
1216   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1217 }
1218
1219 static void
1220 cleanup_exchange_handle (struct ExchangeHandle *handle)
1221 {
1222   if (NULL != handle->ticket)
1223     ticket_destroy (handle->ticket);
1224   if (NULL != handle->token)
1225     token_destroy (handle->token);
1226   GNUNET_free (handle);
1227 }
1228
1229 static void
1230 process_lookup_result (void *cls, uint32_t rd_count,
1231                        const struct GNUNET_GNSRECORD_Data *rd)
1232 {
1233   struct ExchangeHandle *handle = cls;
1234   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1235   char* token_str;
1236   char* record_str;
1237
1238   handle->lookup_request = NULL;
1239   if (2 != rd_count)
1240   {
1241     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1242                 "Number of tokens %d != 2.",
1243                 rd_count);
1244     cleanup_exchange_handle (handle);
1245     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1246     return;
1247   }
1248
1249   record_str =
1250     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1251                                       rd->data,
1252                                       rd->data_size);
1253
1254   //Decrypt and parse
1255   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1256                                             &handle->aud_privkey,
1257                                             &handle->token));
1258
1259   //Readable
1260   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1261                                                &handle->aud_privkey,
1262                                                &token_str));
1263
1264   erm = create_exchange_result_message (token_str,
1265                                         handle->label,
1266                                         handle->ticket->payload->nonce);
1267   erm->id = handle->r_id;
1268   GNUNET_SERVER_notification_context_unicast (nc,
1269                                               handle->client,
1270                                               &erm->header,
1271                                               GNUNET_NO);
1272   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1273
1274   cleanup_exchange_handle (handle);
1275   GNUNET_free (record_str);
1276   GNUNET_free (token_str);
1277   GNUNET_free (erm);
1278
1279 }
1280
1281
1282
1283 /**
1284  *
1285  * Handler for exchange message
1286  *
1287  * @param cls unused
1288  * @param client who sent the message
1289  * @param message the message
1290  */
1291 static void
1292 handle_exchange_message (void *cls,
1293                          struct GNUNET_SERVER_Client *client,
1294                          const struct GNUNET_MessageHeader *message)
1295 {
1296   const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1297   struct ExchangeHandle *xchange_handle;
1298   uint16_t size;
1299   const char *ticket;
1300   char *lookup_query;
1301
1302   size = ntohs (message->size);
1303   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1304   {
1305     GNUNET_break (0);
1306     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1307     return;
1308   }
1309   em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1310   ticket = (const char *) &em[1];
1311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312               "Received EXCHANGE of `%s' from client\n",
1313               ticket);
1314   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1315   xchange_handle->aud_privkey = em->aud_privkey;
1316   xchange_handle->r_id = em->id;
1317   if (GNUNET_SYSERR == ticket_parse (ticket,
1318                                      &xchange_handle->aud_privkey,
1319                                      &xchange_handle->ticket))
1320   {
1321     GNUNET_free (xchange_handle);
1322     GNUNET_SERVER_receive_done (client,
1323                                 GNUNET_SYSERR);
1324     return;
1325   }
1326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1327               xchange_handle->ticket->payload->label);
1328   GNUNET_asprintf (&lookup_query,
1329                    "%s.gnu",
1330                    xchange_handle->ticket->payload->label);
1331   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1332   GNUNET_SERVER_notification_context_add (nc, client);
1333   GNUNET_SERVER_client_set_user_context (client,
1334                                          xchange_handle);
1335   xchange_handle->client = client;
1336   xchange_handle->lookup_request
1337     = GNUNET_GNS_lookup (gns_handle,
1338                          lookup_query,
1339                          &xchange_handle->ticket->payload->identity_key,
1340                          GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1341                          GNUNET_GNS_LO_LOCAL_MASTER,
1342                          NULL,
1343                          &process_lookup_result,
1344                          xchange_handle);
1345   GNUNET_free (lookup_query);
1346
1347 }
1348
1349
1350 static void
1351 find_existing_token_error (void *cls)
1352 {
1353   struct IssueHandle *handle = cls;
1354   cleanup_issue_handle (handle);
1355   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
1356   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1357 }
1358
1359
1360 static void
1361 find_existing_token_finished (void *cls)
1362 {
1363   struct IssueHandle *handle = cls;
1364   uint64_t rnd_key;
1365
1366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1367               ">>> No existing token found\n");
1368   rnd_key =
1369     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1370                               UINT64_MAX);
1371   GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1372                                 sizeof (uint64_t),
1373                                 &handle->label);
1374   handle->ns_it = NULL;
1375   handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1376                                                          &handle->iss_key,
1377                                                          &attr_collect_error,
1378                                                          handle,
1379                                                          &attr_collect,
1380                                                          handle,
1381                                                          &attr_collect_finished,
1382                                                          handle);
1383 }
1384
1385
1386 /**
1387  *
1388  * Look for existing token
1389  *
1390  * @param cls the identity entry
1391  * @param zone the identity
1392  * @param lbl the name of the record
1393  * @param rd_count number of records
1394  * @param rd record data
1395  *
1396  */
1397 static void
1398 find_existing_token (void *cls,
1399                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1400                      const char *lbl,
1401                      unsigned int rd_count,
1402                      const struct GNUNET_GNSRECORD_Data *rd)
1403 {
1404   struct IssueHandle *handle = cls;
1405   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1406   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1407   struct GNUNET_HashCode key;
1408   int scope_count_token;
1409   char *scope;
1410   char *tmp_scopes;
1411
1412   //There should be only a single record for a token under a label
1413   if (2 != rd_count)
1414   {
1415     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1416     return;
1417   }
1418
1419   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1420   {
1421     token_metadata_record = &rd[0];
1422   }
1423   else
1424   {
1425     token_metadata_record = &rd[1];
1426   }
1427   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1428   {
1429     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1430     return;
1431   }
1432   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1433   aud_key =
1434     (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1435   tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1436
1437   if (0 != memcmp (aud_key, &handle->aud_key,
1438                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1439   {
1440     char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1441                                                       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1442     //Audience does not match!
1443     char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1444                                                   token_metadata_record->data,
1445                                                   token_metadata_record->data_size);
1446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447                 "Token does not match audience %s vs %s. Moving on\n",
1448                 tmp2,
1449                 tmp);
1450     GNUNET_free (tmp_scopes);
1451     GNUNET_free (tmp2);
1452     GNUNET_free (tmp);
1453     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1454     return;
1455   }
1456
1457   scope = strtok (tmp_scopes, ",");
1458   scope_count_token = 0;
1459   while (NULL != scope)
1460   {
1461     GNUNET_CRYPTO_hash (scope,
1462                         strlen (scope),
1463                         &key);
1464
1465     if ((NULL != handle->attr_map) &&
1466         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1467     {
1468       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1469                   "Issued token does not include `%s'. Moving on\n", scope);
1470       GNUNET_free (tmp_scopes);
1471       GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1472       return;
1473     }
1474     scope_count_token++;
1475     scope = strtok (NULL, ",");
1476   }
1477   GNUNET_free (tmp_scopes);
1478   //All scopes in token are also in request. Now
1479   //Check length
1480   if ((NULL != handle->attr_map) &&
1481       (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
1482   {
1483     //We have an existing token
1484     handle->label = GNUNET_strdup (lbl);
1485     handle->ns_it = NULL;
1486     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1487                                                            &handle->iss_key,
1488                                                            &attr_collect_error,
1489                                                            handle,
1490                                                            &attr_collect,
1491                                                            handle,
1492                                                            &attr_collect_finished,
1493                                                            handle);
1494
1495     return;
1496   }
1497   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1498               "Nuber of attributes in token do not match request\n");
1499   //No luck
1500   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1501 }
1502
1503
1504 /**
1505  *
1506  * Handler for issue message
1507  *
1508  * @param cls unused
1509  * @param client who sent the message
1510  * @param message the message
1511  */
1512 static void
1513 handle_issue_message (void *cls,
1514                       struct GNUNET_SERVER_Client *client,
1515                       const struct GNUNET_MessageHeader *message)
1516 {
1517   const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1518   const char *scopes;
1519
1520   uint16_t size;
1521   char *scopes_tmp;
1522   char *scope;
1523   struct GNUNET_HashCode key;
1524   struct IssueHandle *issue_handle;
1525
1526   size = ntohs (message->size);
1527   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1528   {
1529     GNUNET_break (0);
1530     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1531     return;
1532   }
1533   im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1534   scopes = (const char *) &im[1];
1535   if ('\0' != scopes[size - sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage) - 1])
1536   {
1537     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1538                 "Malformed scopes received!\n");
1539     GNUNET_break (0);
1540     GNUNET_SERVER_receive_done (client,
1541                                 GNUNET_SYSERR);
1542     return;
1543   }
1544   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1545   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1546                                                                  GNUNET_NO);
1547   scopes_tmp = GNUNET_strdup (scopes);
1548
1549   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1550   {
1551     GNUNET_CRYPTO_hash (scope,
1552                         strlen (scope),
1553                         &key);
1554     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1555                                        &key,
1556                                        scope,
1557                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1558   }
1559   GNUNET_free (scopes_tmp);
1560   issue_handle->r_id = im->id;
1561   issue_handle->aud_key = im->aud_key;
1562   issue_handle->iss_key = im->iss_key;
1563   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1564                                       &issue_handle->iss_pkey);
1565   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1566   issue_handle->nonce = ntohl (im->nonce);
1567   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1568   GNUNET_SERVER_notification_context_add (nc, client);
1569   GNUNET_SERVER_client_set_user_context (client, issue_handle);
1570   issue_handle->client = client;
1571   issue_handle->scopes = GNUNET_strdup (scopes);
1572   issue_handle->token = token_create (&issue_handle->iss_pkey,
1573                                       &issue_handle->aud_key);
1574
1575   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1576                                                                &im->iss_key,
1577                                                                &find_existing_token_error,
1578                                                                issue_handle,
1579                                                                &find_existing_token,
1580                                                                issue_handle,
1581                                                                &find_existing_token_finished,
1582                                                                issue_handle);
1583 }
1584
1585
1586 /**
1587  * Main function that will be run
1588  *
1589  * @param cls closure
1590  * @param args remaining command-line arguments
1591  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1592  * @param c configuration
1593  */
1594 static void
1595 run (void *cls,
1596      struct GNUNET_SERVER_Handle *server,
1597      const struct GNUNET_CONFIGURATION_Handle *c)
1598 {
1599   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1600     {&handle_issue_message, NULL,
1601       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1602     {&handle_exchange_message, NULL,
1603       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1604     {NULL, NULL, 0, 0}
1605   };
1606
1607   cfg = c;
1608
1609   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1610   GNUNET_SERVER_add_handlers (server, handlers);
1611   nc = GNUNET_SERVER_notification_context_create (server, 1);
1612
1613   //Connect to identity and namestore services
1614   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1615   if (NULL == ns_handle)
1616   {
1617     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1618   }
1619
1620   gns_handle = GNUNET_GNS_connect (cfg);
1621   if (NULL == gns_handle)
1622   {
1623     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1624   }
1625
1626   identity_handle = GNUNET_IDENTITY_connect (cfg,
1627                                              &list_ego,
1628                                              NULL);
1629
1630   if (GNUNET_OK ==
1631       GNUNET_CONFIGURATION_get_value_time (cfg,
1632                                            "identity-provider",
1633                                            "TOKEN_EXPIRATION_INTERVAL",
1634                                            &token_expiration_interval))
1635   {
1636     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1637                 "Time window for zone iteration: %s\n",
1638                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1639                                                         GNUNET_YES));
1640   } else {
1641     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1642   }
1643
1644   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1645 }
1646
1647
1648 /**
1649  * The main function
1650  *
1651  * @param argc number of arguments from the cli
1652  * @param argv command line arguments
1653  * @return 0 ok, 1 on error
1654  */
1655 int
1656 main (int argc, char *const *argv)
1657 {
1658   return  (GNUNET_OK ==
1659            GNUNET_SERVICE_run (argc, argv, "identity-provider",
1660                                GNUNET_SERVICE_OPTION_NONE,
1661                                &run, NULL)) ? 0 : 1;
1662 }
1663
1664 /* end of gnunet-service-identity-provider.c */