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