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