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