-add config
[oweals/gnunet.git] / src / identity-provider / gnunet-service-identity-provider.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
4
5    GNUnet is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; either version 3, or (at your
8    option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GNUnet; see the file COPYING.  If not, write to the
17    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file src/identity-provider/gnunet-service-identity-provider.c
23  * @brief Identity Token Service
24  *
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_gns_service.h"
35 #include <jansson.h>
36 #include "gnunet_signatures.h"
37 #include "identity_provider.h"
38 #include "identity_token.h"
39
40 /**
41  * First pass state
42  */
43 #define STATE_INIT 0
44
45 /**
46  * Normal operation state
47  */
48 #define STATE_POST_INIT 1
49
50 /**
51  * Minimum interval between updates
52  */
53 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
54
55 /**
56  * Standard token expiration time
57  */
58 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
59
60 /**
61  * Service state (to detect initial update pass)
62  */
63 static int state;
64
65 /**
66  * Head of ego entry DLL
67  */
68 static struct EgoEntry *ego_head;
69
70 /**
71  * Tail of ego entry DLL
72  */
73 static struct EgoEntry *ego_tail;
74
75 /**
76  * Identity handle
77  */
78 static struct GNUNET_IDENTITY_Handle *identity_handle;
79
80 /**
81  * Token expiration interval
82  */
83 static struct GNUNET_TIME_Relative token_expiration_interval;
84
85 /**
86  * Namestore handle
87  */
88 static struct GNUNET_NAMESTORE_Handle *ns_handle;
89
90 /**
91  * GNS handle
92  */
93 static struct GNUNET_GNS_Handle *gns_handle;
94
95 /**
96  * Namestore qe
97  */
98 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
99
100 /**
101  * Namestore iterator
102  */
103 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
104
105 /**
106  * Timeout task
107  */
108 static struct GNUNET_SCHEDULER_Task * timeout_task;
109
110
111 /**
112  * Update task
113  */
114 static struct GNUNET_SCHEDULER_Task * update_task;
115
116 /**
117  * Timeout for next update pass
118  */
119 static struct GNUNET_TIME_Relative min_rel_exp;
120
121
122 /**
123  * Currently processed token
124  */
125 static struct IdentityToken *token;
126
127 /**
128  * Label for currently processed token
129  */
130 static char* label;
131
132 /**
133  * Scopes for processed token
134  */
135 static char* scopes;
136
137 /**
138  * Expiration for processed token
139  */
140 static uint64_t rd_exp;
141
142 /**
143  * ECDHE Privkey for processed token metadata
144  */
145 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
146
147 /**
148  * Handle to the statistics service.
149  */
150 static struct GNUNET_STATISTICS_Handle *stats;
151
152 /**
153  * Notification context, simplifies client broadcasts.
154  */
155 static struct GNUNET_SERVER_NotificationContext *nc;
156
157 /**
158  * Our configuration.
159  */
160 static const struct GNUNET_CONFIGURATION_Handle *cfg;
161
162
163 struct ExchangeHandle
164 {
165
166   /**
167    * Client connection
168    */
169   struct GNUNET_SERVER_Client *client;
170
171   /**
172    * Ticket
173    */
174   struct TokenTicket *ticket;
175
176   /**
177    * Token returned
178    */
179   struct IdentityToken *token;
180
181   /**
182    * LookupRequest
183    */
184   struct GNUNET_GNS_LookupRequest *lookup_request;
185   
186   /**
187    * Audience Key
188    */
189   struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
190
191   /**
192    * Label to return
193    */
194   char *label;
195 };
196
197 struct IssueHandle
198 {
199
200   /**
201    * Client connection
202    */
203   struct GNUNET_SERVER_Client *client;
204
205   /**
206    * Issuer Key
207    */
208   struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
209
210   /**
211    * Issue pubkey
212    */
213   struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
214
215   /**
216    * Audience Key
217    */
218   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
219
220   /**
221    * Expiration
222    */
223   struct GNUNET_TIME_Absolute expiration;
224
225   /**
226    * Scopes
227    */
228   char *scopes;
229
230   /**
231    * nonce
232    */
233   uint64_t nonce;
234
235   /**
236    * NS iterator
237    */
238   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
239
240   /**
241    * Attribute map
242    */
243   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
244
245   /**
246    * Token
247    */
248   struct IdentityToken *token;
249
250   /**
251    * Ticket
252    */
253   struct TokenTicket *ticket;
254
255   /**
256    * QueueEntry
257    */
258   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
259 };
260
261 /**
262  * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
263  *
264  */
265 struct EgoEntry
266 {
267   /**
268    * DLL
269    */
270   struct EgoEntry *next;
271
272   /**
273    * DLL
274    */
275   struct EgoEntry *prev;
276
277   /**
278    * Ego handle
279    */
280   struct GNUNET_IDENTITY_Ego *ego;
281
282   /**
283    * Attribute map. Contains the attributes as json_t
284    */
285   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
286
287   /**
288    * Attributes are old and should be updated if GNUNET_YES
289    */
290   int attributes_dirty;
291 };
292
293 /**
294  * Continuation for token store call
295  *
296  * @param cls NULL
297  * @param success error code
298  * @param emsg error message
299  */
300 static void
301 store_token_cont (void *cls,
302                   int32_t success,
303                   const char *emsg)
304 {
305   ns_qe = NULL;
306   if (GNUNET_SYSERR == success)
307   {
308     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
309                 "Failed to update token: %s\n",
310                 emsg);
311     return;
312   }
313   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
314 }
315
316
317 /**
318  * This function updates the old token with new attributes,
319  * removes deleted attributes and expiration times.
320  *
321  * @param cls the ego entry
322  * @param tc task context
323  */
324 static void
325 handle_token_update (void *cls,
326                      const struct GNUNET_SCHEDULER_TaskContext *tc)
327 {
328   char *token_metadata;
329   char *write_ptr;
330   char *enc_token_str;
331   const char *key;
332   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
333   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
334   struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
335   struct EgoEntry *ego_entry = cls;
336   struct GNUNET_GNSRECORD_Data token_record[2];
337   struct GNUNET_HashCode key_hash;
338   struct GNUNET_TIME_Relative token_rel_exp;
339   struct GNUNET_TIME_Relative token_ttl;
340   struct GNUNET_TIME_Absolute token_exp;
341   struct GNUNET_TIME_Absolute token_nbf;
342   struct GNUNET_TIME_Absolute new_exp;
343   struct GNUNET_TIME_Absolute new_iat;
344   struct GNUNET_TIME_Absolute new_nbf;
345   struct IdentityToken *new_token;
346   json_t *payload_json;
347   json_t *value;
348   json_t *cur_value;
349   json_t *token_nbf_json;
350   json_t *token_exp_json;
351   size_t token_metadata_len;
352
353   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
354   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
355                                       &pub_key);
356
357   //Note: We need the token expiration time here. Not the record expiration
358   //time.
359   //There are two types of tokens: Token that expire on GNS level with
360   //an absolute expiration time. Those are basically tokens that will
361   //be automatically revoked on (record)expiration.
362   //Tokens stored with relative expiration times will expire on the token level (token expiration)
363   //but this service will reissue new tokens that can be retrieved from GNS
364   //automatically.
365
366   payload_json = token->payload;
367
368   token_exp_json = json_object_get (payload_json, "exp");
369   token_nbf_json = json_object_get (payload_json, "nbf");
370   token_exp.abs_value_us = json_integer_value(token_exp_json);
371   token_nbf.abs_value_us = json_integer_value(token_nbf_json);
372   token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
373
374   token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
375   if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
376   {
377     //This token is not yet expired! Save and skip
378     if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
379     {
380       min_rel_exp = token_ttl;
381     }
382     json_decref (payload_json);
383     GNUNET_free (token);
384     token = NULL;
385     GNUNET_free (label);
386     label = NULL;
387     GNUNET_free (scopes);
388     scopes = NULL;
389     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
390     return;
391   }
392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393               "Token is expired. Create a new one\n");
394   new_token = token_create (&pub_key,
395                             &token->aud_key);
396   new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
397   new_nbf = GNUNET_TIME_absolute_get ();
398   new_iat = new_nbf;
399
400   json_object_foreach(payload_json, key, value) {
401     if (0 == strcmp (key, "exp"))
402     {
403       token_add_json (new_token, key, json_integer (new_exp.abs_value_us));
404     }
405     else if (0 == strcmp (key, "nbf"))
406     {
407       token_add_json (new_token, key, json_integer (new_nbf.abs_value_us));
408     }
409     else if (0 == strcmp (key, "iat"))
410     {
411       token_add_json (new_token, key, json_integer (new_iat.abs_value_us));
412     }
413     else if ((0 == strcmp (key, "iss"))
414              || (0 == strcmp (key, "aud")))
415     {
416       //Omit
417     }
418     else if ((0 == strcmp (key, "sub"))
419              || (0 == strcmp (key, "rnl")))
420     {
421       token_add_json (new_token, key, value);
422     }
423     else {
424       GNUNET_CRYPTO_hash (key,
425                           strlen (key),
426                           &key_hash);
427       //Check if attr still exists. omit of not
428       if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
429                                                                &key_hash))
430       {
431         cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
432                                                        &key_hash);
433         token_add_json (new_token, key, cur_value);
434       }
435     }
436   }
437
438   // reassemble and set
439   GNUNET_assert (token_serialize (new_token,
440                                   priv_key,
441                                   &new_ecdhe_privkey,
442                                   &enc_token_str));
443
444   json_decref (payload_json);
445
446   token_record[0].data = enc_token_str;
447   token_record[0].data_size = strlen (enc_token_str) + 1;
448   token_record[0].expiration_time = rd_exp; //Old expiration time
449   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
450   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
451
452   //Meta
453   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
454     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
455     + strlen (scopes) + 1; //With 0-Terminator
456   token_metadata = GNUNET_malloc (token_metadata_len);
457   write_ptr = token_metadata;
458   memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
459   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
460   memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
461   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
462   memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
463
464   token_record[1].data = token_metadata;
465   token_record[1].data_size = token_metadata_len;
466   token_record[1].expiration_time = rd_exp;
467   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
468   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
469
470   ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
471                                           priv_key,
472                                           label,
473                                           2,
474                                           token_record,
475                                           &store_token_cont,
476                                           ego_entry);
477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
478   token_destroy (new_token);
479   token_destroy (token);
480   GNUNET_free (new_ecdhe_privkey);
481   GNUNET_free (enc_token_str);
482   token = NULL;
483   GNUNET_free (label);
484   label = NULL;
485   GNUNET_free (scopes);
486   scopes = NULL;
487 }
488
489 static void
490 update_identities(void *cls,
491                   const struct GNUNET_SCHEDULER_TaskContext *tc);
492
493 /**
494  *
495  * Cleanup attr_map
496  *
497  * @param cls NULL
498  * @param key the key
499  * @param value the json_t attribute value
500  * @return GNUNET_YES
501  */
502 static int
503 clear_ego_attrs (void *cls,
504                  const struct GNUNET_HashCode *key,
505                  void *value)
506 {
507   json_t *attr_value = value;
508
509   json_decref (attr_value);
510
511   return GNUNET_YES;
512 }
513
514
515 /**
516  *
517  * Update all ID_TOKEN records for an identity and store them
518  *
519  * @param cls the identity entry
520  * @param zone the identity
521  * @param lbl the name of the record
522  * @param rd_count number of records
523  * @param rd record data
524  *
525  */
526 static void
527 token_collect (void *cls,
528                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
529                const char *lbl,
530                unsigned int rd_count,
531                const struct GNUNET_GNSRECORD_Data *rd)
532 {
533   struct EgoEntry *ego_entry = cls;
534   const struct GNUNET_GNSRECORD_Data *token_record;
535   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
536   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
537
538   if (NULL == lbl)
539   {
540     //Done
541     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542                 ">>> Updating Ego finished\n");
543     //Clear attribute map for ego
544     GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
545                                            &clear_ego_attrs,
546                                            ego_entry);
547     GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
548     update_task = GNUNET_SCHEDULER_add_now (&update_identities,
549                                             ego_entry->next);
550     return; 
551   }
552
553   //There should be only a single record for a token under a label
554   if (2 != rd_count)
555   {
556     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
557     return;
558   }
559
560   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
561   {
562     token_metadata_record = &rd[0];
563     token_record = &rd[1];
564   } else {
565     token_record = &rd[0];
566     token_metadata_record = &rd[1];
567   }
568   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
569   {
570     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
571     return;
572   }
573   if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
574   {
575     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
576     return;
577   }
578
579   //Get metadata and decrypt token
580   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
581   aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
582   scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
583
584   token_parse2 (token_record->data,
585                 &ecdhe_privkey,
586                 aud_key,
587                 &token);
588
589   label = GNUNET_strdup (lbl); 
590   rd_exp = token_record->expiration_time;
591
592   GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
593 }
594
595
596 /**
597  *
598  * Collect all ID_ATTR records for an identity and store them
599  *
600  * @param cls the identity entry
601  * @param zone the identity
602  * @param lbl the name of the record
603  * @param rd_count number of records
604  * @param rd record data
605  *
606  */
607 static void
608 attribute_collect (void *cls,
609                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
610                    const char *lbl,
611                    unsigned int rd_count,
612                    const struct GNUNET_GNSRECORD_Data *rd)
613 {
614   struct EgoEntry *ego_entry = cls;
615   json_t *attr_value;
616   struct GNUNET_HashCode key;
617   char* attr;
618   int i;
619
620   if (NULL == lbl)
621   {
622     //Done
623     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624                 ">>> Updating Attributes finished\n");
625     ego_entry->attributes_dirty = GNUNET_NO;
626     update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
627     return;
628   }
629
630   if (0 == rd_count)
631   {
632     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
633     return;
634   }
635   GNUNET_CRYPTO_hash (lbl,
636                       strlen (lbl),
637                       &key);
638   if (1 == rd_count)
639   {
640     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
641     {
642       attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
643                                                rd->data,
644                                                rd->data_size);
645       attr_value = json_string (attr);
646       GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
647                                          &key,
648                                          attr_value,
649                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
650       GNUNET_free (attr);
651     }
652
653     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
654     return;
655   }
656
657   attr_value = json_array();
658   for (i = 0; i < rd_count; i++)
659   {
660     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
661     {
662       attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
663                                                rd[i].data,
664                                                rd[i].data_size);
665       json_array_append_new (attr_value, json_string (attr));
666       GNUNET_free (attr);
667     }
668
669   }
670   GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
671                                      &key,
672                                      attr_value,
673                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
674   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
675   return;
676 }
677
678 /**
679  *
680  * Update identity information for ego. If attribute map is
681  * dirty, first update the attributes.
682  *
683  * @param cls the ego to update
684  * param tc task context
685  *
686  */
687 static void
688 update_identities(void *cls,
689                   const struct GNUNET_SCHEDULER_TaskContext *tc)
690 {
691   struct EgoEntry *next_ego = cls;
692   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
693   update_task = NULL;
694   if (NULL == next_ego)
695   {
696     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
697       min_rel_exp = MIN_WAIT_TIME;
698     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699                 ">>> Finished. Rescheduling in %d\n",
700                 min_rel_exp.rel_value_us);
701     ns_it = NULL;
702     //finished -> reschedule
703     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
704                                                 &update_identities,
705                                                 ego_head);
706     min_rel_exp.rel_value_us = 0;
707     return;
708   }
709   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
710   if (GNUNET_YES == next_ego->attributes_dirty)
711   {
712     //Starting over. We must update the Attributes for they might have changed.
713     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
714                                                    priv_key,
715                                                    &attribute_collect,
716                                                    next_ego);
717
718   }
719   else
720   {
721     //Ego will be dirty next time
722     next_ego->attributes_dirty = GNUNET_YES;
723     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
724                                                    priv_key,
725                                                    &token_collect,
726                                                    next_ego);
727   }
728 }
729
730
731
732 /**
733  * Function called initially to start update task
734  */
735 static void
736 init_cont ()
737 {
738   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
739   //Initially iterate all itenties and refresh all tokens
740   update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
741 }
742
743 /**
744  * Initial ego collection function.
745  *
746  * @param cls NULL
747  * @param ego ego
748  * @param ctx context
749  * @param identifier ego name
750  */
751 static void
752 list_ego (void *cls,
753           struct GNUNET_IDENTITY_Ego *ego,
754           void **ctx,
755           const char *identifier)
756 {
757   struct EgoEntry *new_entry;
758   if ((NULL == ego) && (STATE_INIT == state))
759   {
760     state = STATE_POST_INIT;
761     init_cont ();
762     return;
763   }
764   if (STATE_INIT == state) {
765     new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
766     new_entry->ego = ego;
767     new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
768                                                                 GNUNET_NO);
769     new_entry->attributes_dirty = GNUNET_YES;
770     GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
771   }
772 }
773
774 /**
775  * Cleanup task
776  */
777 static void
778 cleanup()
779 {
780   struct EgoEntry *ego_entry;
781   struct EgoEntry *ego_tmp;
782
783   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784               "Cleaning up\n");
785   if (NULL != nc)
786   {
787     GNUNET_SERVER_notification_context_destroy (nc);
788     nc = NULL;
789   }
790   if (NULL != stats)
791   {
792     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
793     stats = NULL;
794   }
795
796   if (NULL != timeout_task)
797     GNUNET_SCHEDULER_cancel (timeout_task);
798   if (NULL != update_task)
799     GNUNET_SCHEDULER_cancel (update_task);
800   if (NULL != identity_handle)
801     GNUNET_IDENTITY_disconnect (identity_handle);
802   if (NULL != gns_handle)
803     GNUNET_GNS_disconnect (gns_handle);
804   if (NULL != ns_it)
805     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
806   if (NULL != ns_qe)
807     GNUNET_NAMESTORE_cancel (ns_qe);
808   if (NULL != ns_handle)
809     GNUNET_NAMESTORE_disconnect (ns_handle);
810   if (NULL != token)
811     GNUNET_free (token);
812   if (NULL != label)
813     GNUNET_free (label);
814
815   for (ego_entry = ego_head;
816        NULL != ego_entry;)
817   {
818     ego_tmp = ego_entry;
819     if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
820     {
821       GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
822                                              &clear_ego_attrs,
823                                              ego_tmp);
824
825     }
826     GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
827     ego_entry = ego_entry->next;
828     GNUNET_free (ego_tmp);
829   }
830 }
831
832 /**
833  * Shutdown task
834  *
835  * @param cls NULL
836  * @param tc task context
837  */
838 static void
839 do_shutdown (void *cls,
840              const struct GNUNET_SCHEDULER_TaskContext *tc)
841 {
842   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
843               "Shutting down...\n");
844   cleanup();
845 }
846
847
848 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
849 create_exchange_result_message (const char* token,
850                                 const char* label)
851 {
852   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
853   uint16_t token_len = strlen (token) + 1;
854   erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
855                        + token_len);
856   erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
857   erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
858                             + token_len);
859   memcpy (&erm[1], token, token_len);
860   return erm;
861 }
862
863
864 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
865 create_issue_result_message (const char* ticket)
866 {
867   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
868
869   irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen(ticket) + 1);
870   irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
871   irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen (ticket) + 1);
872   memcpy (&irm[1], ticket, strlen (ticket) + 1);
873   return irm;
874 }
875
876 static void
877 cleanup_issue_handle (struct IssueHandle *handle)
878 {
879   if (NULL != handle->attr_map)
880     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
881   if (NULL != handle->scopes)
882     GNUNET_free (handle->scopes);
883   if (NULL != handle->token)
884     token_destroy (handle->token);
885   if (NULL != handle->ticket)
886     ticket_destroy (handle->ticket);
887   GNUNET_free (handle);
888 }
889
890 static void
891 store_token_issue_cont (void *cls,
892                         int32_t success,
893                         const char *emsg)
894 {
895   struct IssueHandle *handle = cls;
896   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
897   char* token_ticket_str;
898   handle->ns_qe = NULL;
899   if (GNUNET_SYSERR == success)
900   {
901     cleanup_issue_handle (handle);
902     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
903                 "Unknown Error\n");
904     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
905     return;
906   }
907   if (GNUNET_OK != ticket_serialize (handle->ticket,
908                                      &handle->iss_key,
909                                      &token_ticket_str))
910   {
911     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
912                 "Error serializing ticket\n");
913     cleanup_issue_handle (handle);
914     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 
915     return;
916   }
917   irm = create_issue_result_message (token_ticket_str);
918   GNUNET_SERVER_notification_context_unicast (nc,
919                                               handle->client,
920                                               &irm->header,
921                                               GNUNET_NO);
922   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
923   cleanup_issue_handle (handle);
924   GNUNET_free (irm);
925   GNUNET_free (token_ticket_str);
926 }
927
928 /**
929  * Build a GNUid token for identity
930  * @param handle the handle
931  * @param ego_entry the ego to build the token for
932  * @param name name of the ego
933  * @param token_aud token audience
934  * @param token the resulting gnuid token
935  * @return identifier string of token (label)
936  */
937 static void
938 sign_and_return_token (void *cls,
939                        const struct GNUNET_SCHEDULER_TaskContext *tc)
940 {
941   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
942   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
943   struct IssueHandle *handle = cls;
944   struct GNUNET_GNSRECORD_Data token_record[2];
945   char *lbl_str;
946   char *nonce_str;
947   char *enc_token_str;
948   char *token_metadata;
949   char* write_ptr;
950   uint64_t time;
951   uint64_t exp_time;
952   uint64_t rnd_key;
953   size_t token_metadata_len;
954
955   //Remote nonce 
956   nonce_str = NULL;
957   GNUNET_asprintf (&nonce_str, "%d", handle->nonce);
958   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
959
960   //Label
961   rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
962                                       UINT64_MAX);
963   GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
964                                 sizeof (uint64_t),
965                                 &lbl_str);
966   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
967                                       &pub_key);
968   handle->ticket = ticket_create (nonce_str,
969                                   &pub_key,
970                                   lbl_str,
971                                   &handle->aud_key);
972
973   time = GNUNET_TIME_absolute_get().abs_value_us;
974   exp_time = time + token_expiration_interval.rel_value_us;
975
976   token_add_json (handle->token, "nbf", json_integer (time));
977   token_add_json (handle->token, "iat", json_integer (time));
978   token_add_json (handle->token, "exp", json_integer (exp_time));
979   token_add_attr (handle->token, "nonce", nonce_str);
980
981   //Token in a serialized encrypted format 
982   GNUNET_assert (token_serialize (handle->token,
983                                   &handle->iss_key,
984                                   &ecdhe_privkey,
985                                   &enc_token_str));
986
987   //Token record E,E_K (Token)
988   token_record[0].data = enc_token_str;
989   token_record[0].data_size = strlen (enc_token_str) + 1;
990   token_record[0].expiration_time = exp_time;
991   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
992   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
993
994
995   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
996     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
997     + strlen (handle->scopes) + 1; //With 0-Terminator
998   token_metadata = GNUNET_malloc (token_metadata_len);
999   write_ptr = token_metadata;
1000   memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1001   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1002   memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1003   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1004   memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1005
1006   token_record[1].data = token_metadata;
1007   token_record[1].data_size = token_metadata_len;
1008   token_record[1].expiration_time = exp_time;
1009   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1010   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1011
1012   //Persist token
1013   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1014                                                   &handle->iss_key,
1015                                                   lbl_str,
1016                                                   2,
1017                                                   token_record,
1018                                                   &store_token_issue_cont,
1019                                                   handle);
1020   GNUNET_free (ecdhe_privkey);
1021   GNUNET_free (lbl_str);
1022   GNUNET_free (nonce_str);
1023   GNUNET_free (enc_token_str);
1024   GNUNET_free (token_metadata);
1025 }
1026
1027 /**
1028  * Collect attributes for token
1029  */
1030 static void
1031 attr_collect (void *cls,
1032               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1033               const char *label,
1034               unsigned int rd_count,
1035               const struct GNUNET_GNSRECORD_Data *rd)
1036 {
1037   int i;
1038   char* data;
1039   json_t *attr_arr;
1040   struct IssueHandle *handle = cls;
1041   struct GNUNET_HashCode key;
1042
1043   if (NULL == label)
1044   {
1045     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1046     handle->ns_it = NULL;
1047     GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1048     return;
1049   }
1050
1051   GNUNET_CRYPTO_hash (label,
1052                       strlen (label),
1053                       &key);
1054
1055   if (0 == rd_count ||
1056       ( (NULL != handle->attr_map) &&
1057         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1058                                                                &key))
1059       )
1060      )
1061   {
1062     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1063     return;
1064   }
1065
1066   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1067
1068   if (1 == rd_count)
1069   {
1070     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1071     {
1072       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1073                                                rd->data,
1074                                                rd->data_size);
1075       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1076       token_add_json (handle->token,
1077                       label,
1078                       json_string (data));
1079       GNUNET_free (data);
1080     }
1081     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1082     return;
1083   }
1084
1085   i = 0;
1086   attr_arr = json_array();
1087   for (; i < rd_count; i++)
1088   {
1089     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1090     {
1091       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1092                                                rd[i].data,
1093                                                rd[i].data_size);
1094       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1095       json_array_append_new (attr_arr, json_string (data));
1096       GNUNET_free (data);
1097     }
1098   }
1099
1100   if (0 < json_array_size (attr_arr))
1101   {
1102     token_add_json (handle->token, label, attr_arr);
1103   }
1104   json_decref (attr_arr);
1105   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1106 }
1107
1108 static void
1109 cleanup_exchange_handle (struct ExchangeHandle *handle)
1110 {
1111   if (NULL != handle->ticket) 
1112     ticket_destroy (handle->ticket);
1113   if (NULL != handle->token)
1114     token_destroy (handle->token);
1115   GNUNET_free (handle);
1116 }
1117
1118 static void
1119 process_lookup_result (void *cls, uint32_t rd_count,
1120                        const struct GNUNET_GNSRECORD_Data *rd)
1121 {
1122   struct ExchangeHandle *handle = cls;
1123   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1124   char* token_str;
1125   char* record_str;
1126
1127   handle->lookup_request = NULL;
1128   if (2 != rd_count)
1129   {
1130     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131                 "Number of tokens %d != 2.",
1132                 rd_count);
1133     cleanup_exchange_handle (handle);
1134     GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1135     return;
1136   }
1137
1138   record_str = 
1139     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1140                                       rd->data,
1141                                       rd->data_size);
1142
1143   //Decrypt and parse
1144   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1145                                             &handle->aud_privkey,
1146                                             &handle->token));
1147
1148   //Readable
1149   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1150                                                &handle->aud_privkey,
1151                                                &token_str));
1152
1153   erm = create_exchange_result_message (token_str,
1154                                         handle->label);
1155   GNUNET_SERVER_notification_context_unicast (nc,
1156                                               handle->client,
1157                                               &erm->header,
1158                                               GNUNET_NO);
1159   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1160
1161   cleanup_exchange_handle (handle);
1162   GNUNET_free (record_str);
1163   GNUNET_free (token_str);
1164   GNUNET_free (erm);
1165
1166 }
1167
1168 /**
1169  *
1170  * Handler for exchange message
1171  *
1172  * @param cls unused
1173  * @param client who sent the message
1174  * @param message the message
1175  */
1176 static void
1177 handle_exchange_message (void *cls,
1178                          struct GNUNET_SERVER_Client *client,
1179                          const struct GNUNET_MessageHeader *message)
1180 {
1181   const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1182   struct ExchangeHandle *xchange_handle;
1183   uint16_t size;
1184   const char *ticket;
1185   char *lookup_query;
1186
1187   size = ntohs (message->size);
1188   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1189   {
1190     GNUNET_break (0);
1191     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1192     return;
1193   }
1194   em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1195   ticket = (const char *) &em[1];
1196   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197               "Received EXCHANGE of `%s' from client\n",
1198               ticket);
1199   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1200   xchange_handle->aud_privkey = em->aud_privkey;
1201
1202   if (GNUNET_SYSERR == ticket_parse (ticket,
1203                                      &xchange_handle->aud_privkey,
1204                                      &xchange_handle->ticket))
1205   {
1206     GNUNET_free (xchange_handle);
1207     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1208     return;
1209   }
1210   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
1211               xchange_handle->ticket->payload->label);
1212   GNUNET_asprintf (&lookup_query,
1213                    "%s.gnu",
1214                    xchange_handle->ticket->payload->label);
1215   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1216   GNUNET_SERVER_notification_context_add (nc, client);
1217   GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1218   xchange_handle->client = client;
1219   xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1220                                                       lookup_query,
1221                                                       &xchange_handle->ticket->payload->identity_key,
1222                                                       GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1223                                                       GNUNET_GNS_LO_LOCAL_MASTER,
1224                                                       NULL,
1225                                                       &process_lookup_result,
1226                                                       xchange_handle);
1227   GNUNET_free (lookup_query);
1228
1229 }
1230
1231 /**
1232  *
1233  * Handler for issue message
1234  *
1235  * @param cls unused
1236  * @param client who sent the message
1237  * @param message the message
1238  */
1239 static void
1240 handle_issue_message (void *cls,
1241                       struct GNUNET_SERVER_Client *client,
1242                       const struct GNUNET_MessageHeader *message)
1243 {
1244   const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1245   const char *scopes;
1246
1247   uint16_t size;
1248   char *scopes_tmp;
1249   char *scope;
1250   struct GNUNET_HashCode key;
1251   struct IssueHandle *issue_handle;
1252
1253   size = ntohs (message->size);
1254   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1255   {
1256     GNUNET_break (0);
1257     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1258     return;
1259   }
1260   im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1261   scopes = (const char *) &im[1];
1262   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263               "Received ISSUE of `%s' from client\n",
1264               scope);
1265   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1266   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1267                                                                  GNUNET_NO);
1268   scopes_tmp = GNUNET_strdup (scopes);
1269   scope = strtok(scopes_tmp, ",");
1270   for (; NULL != scope; scope = strtok (NULL, ","))
1271   {
1272     GNUNET_CRYPTO_hash (scope,
1273                         strlen (scope),
1274                         &key);
1275     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1276                                        &key,
1277                                        scope,
1278                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1279   }
1280   GNUNET_free (scopes_tmp);
1281
1282   issue_handle->aud_key = im->aud_key;
1283   issue_handle->iss_key = im->iss_key;
1284   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1285   issue_handle->nonce = im->nonce;
1286   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1287   GNUNET_SERVER_notification_context_add (nc, client);
1288   GNUNET_SERVER_client_set_user_context (client, issue_handle);
1289   issue_handle->client = client;
1290   issue_handle->scopes = GNUNET_strdup (scopes);
1291   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1292                                       &issue_handle->iss_pkey);
1293   issue_handle->token = token_create (&issue_handle->iss_pkey,
1294                                       &im->aud_key);
1295
1296   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1297                                                                &im->iss_key,
1298                                                                &attr_collect,
1299                                                                issue_handle);
1300 }
1301
1302 /**
1303  * Main function that will be run
1304  *
1305  * @param cls closure
1306  * @param args remaining command-line arguments
1307  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1308  * @param c configuration
1309  */
1310 static void
1311 run (void *cls, 
1312      struct GNUNET_SERVER_Handle *server,
1313      const struct GNUNET_CONFIGURATION_Handle *c)
1314 {
1315   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1316     {&handle_issue_message, NULL,
1317       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1318     {&handle_exchange_message, NULL,
1319       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1320     {NULL, NULL, 0, 0}
1321   };
1322
1323   cfg = c;
1324
1325   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1326   GNUNET_SERVER_add_handlers (server, handlers);
1327   nc = GNUNET_SERVER_notification_context_create (server, 1);
1328
1329   //Connect to identity and namestore services
1330   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1331   if (NULL == ns_handle)
1332   {
1333     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1334   }
1335
1336   gns_handle = GNUNET_GNS_connect (cfg);
1337   if (NULL == gns_handle)
1338   {
1339     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1340   }
1341
1342   identity_handle = GNUNET_IDENTITY_connect (cfg,
1343                                              &list_ego,
1344                                              NULL);
1345   
1346   if (GNUNET_OK == 
1347       GNUNET_CONFIGURATION_get_value_time (cfg,
1348                                              "identity-provider",
1349                                             "TOKEN_EXPIRATION_INTERVAL",
1350                                             &token_expiration_interval))
1351   {
1352     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353                 "Time window for zone iteration: %s\n",
1354                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1355                                                                      GNUNET_YES));
1356   } else {
1357     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1358   }
1359
1360   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1361                                 &do_shutdown, NULL);
1362 }
1363
1364
1365 /**
1366  *
1367  * The main function
1368  *
1369  * @param argc number of arguments from the cli
1370  * @param argv command line arguments
1371  * @return 0 ok, 1 on error
1372  *
1373  */
1374 int
1375 main (int argc, char *const *argv)
1376 {
1377   return  (GNUNET_OK ==
1378            GNUNET_SERVICE_run (argc, argv, "identity-provider",
1379                                GNUNET_SERVICE_OPTION_NONE,
1380                                &run, NULL)) ? 0 : 1;
1381 }
1382
1383 /* end of gnunet-rest-server.c */