- More heavy refactoring. Probably lots of broken things to see here.
[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     GNUNET_SCHEDULER_add_now (&update_identities, ego_entry->next);
539     return;
540   }
541
542   //There should be only a single record for a token under a label
543   if (2 != rd_count)
544   {
545     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
546     return;
547   }
548
549   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
550   {
551     token_metadata_record = &rd[0];
552     token_record = &rd[1];
553   } else {
554     token_record = &rd[0];
555     token_metadata_record = &rd[1];
556   }
557   GNUNET_assert (token_metadata_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA);
558   GNUNET_assert (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN);
559
560   //Get metadata and decrypt token
561   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
562   aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
563   scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
564
565   token_parse2 (token_record->data,
566                 &ecdhe_privkey,
567                 aud_key,
568                 &token);
569
570   //token = GNUNET_GNSRECORD_value_to_string (rd->record_type,
571   //                                          rd->data,
572   //                                          rd->data_size);
573   label = GNUNET_strdup (lbl); 
574   rd_exp = token_record->expiration_time;
575
576   GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
577 }
578
579
580 /**
581  *
582  * Collect all ID_ATTR records for an identity and store them
583  *
584  * @param cls the identity entry
585  * @param zone the identity
586  * @param lbl the name of the record
587  * @param rd_count number of records
588  * @param rd record data
589  *
590  */
591 static void
592 attribute_collect (void *cls,
593                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
594                    const char *lbl,
595                    unsigned int rd_count,
596                    const struct GNUNET_GNSRECORD_Data *rd)
597 {
598   struct EgoEntry *ego_entry = cls;
599   json_t *attr_value;
600   struct GNUNET_HashCode key;
601   char* attr;
602   int i;
603
604   if (NULL == lbl)
605   {
606     //Done
607     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608                 ">>> Updating Attributes finished\n");
609     ego_entry->attributes_dirty = GNUNET_NO;
610     GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
611     return;
612   }
613
614   if (0 == rd_count)
615   {
616     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
617     return;
618   }
619   GNUNET_CRYPTO_hash (lbl,
620                       strlen (lbl),
621                       &key);
622   if (1 == rd_count)
623   {
624     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
625     {
626       attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
627                                                rd->data,
628                                                rd->data_size);
629       attr_value = json_string (attr);
630       GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
631                                          &key,
632                                          attr_value,
633                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
634       GNUNET_free (attr);
635     }
636
637     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
638     return;
639   }
640
641   attr_value = json_array();
642   for (i = 0; i < rd_count; i++)
643   {
644     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
645     {
646       attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
647                                                rd[i].data,
648                                                rd[i].data_size);
649       json_array_append_new (attr_value, json_string (attr));
650       GNUNET_free (attr);
651     }
652
653   }
654   GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
655                                      &key,
656                                      attr_value,
657                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
658   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
659   return;
660 }
661
662 /**
663  *
664  * Update identity information for ego. If attribute map is
665  * dirty, first update the attributes.
666  *
667  * @param cls the ego to update
668  * param tc task context
669  *
670  */
671 static void
672 update_identities(void *cls,
673                   const struct GNUNET_SCHEDULER_TaskContext *tc)
674 {
675   struct EgoEntry *next_ego = cls;
676   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
677   if (NULL == next_ego)
678   {
679     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
680       min_rel_exp = MIN_WAIT_TIME;
681     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682                 ">>> Finished. Rescheduling in %d\n",
683                 min_rel_exp.rel_value_us);
684     ns_it = NULL;
685     //finished -> TODO reschedule
686     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
687                                                 &update_identities,
688                                                 ego_head);
689     min_rel_exp.rel_value_us = 0;
690     return;
691   }
692   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
693   if (GNUNET_YES == next_ego->attributes_dirty)
694   {
695     //Starting over. We must update the Attributes for they might have changed.
696     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
697                                                    priv_key,
698                                                    &attribute_collect,
699                                                    next_ego);
700
701   }
702   else
703   {
704     //Ego will be dirty next time
705     next_ego->attributes_dirty = GNUNET_YES;
706     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
707                                                    priv_key,
708                                                    &token_collect,
709                                                    next_ego);
710   }
711 }
712
713
714
715 /**
716  * Function called initially to start update task
717  */
718 static void
719 init_cont ()
720 {
721   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
722   //Initially iterate all itenties and refresh all tokens
723   update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
724 }
725
726 /**
727  * Initial ego collection function.
728  *
729  * @param cls NULL
730  * @param ego ego
731  * @param ctx context
732  * @param identifier ego name
733  */
734 static void
735 list_ego (void *cls,
736           struct GNUNET_IDENTITY_Ego *ego,
737           void **ctx,
738           const char *identifier)
739 {
740   struct EgoEntry *new_entry;
741   if ((NULL == ego) && (STATE_INIT == state))
742   {
743     state = STATE_POST_INIT;
744     init_cont ();
745     return;
746   }
747   if (STATE_INIT == state) {
748     new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
749     new_entry->ego = ego;
750     new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
751                                                                 GNUNET_NO);
752     new_entry->attributes_dirty = GNUNET_YES;
753     GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
754   }
755 }
756
757 /**
758  * Cleanup task
759  */
760 static void
761 cleanup()
762 {
763   struct EgoEntry *ego_entry;
764   struct EgoEntry *ego_tmp;
765
766   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
767               "Cleaning up\n");
768   if (NULL != nc)
769   {
770     GNUNET_SERVER_notification_context_destroy (nc);
771     nc = NULL;
772   }
773   if (NULL != stats)
774   {
775     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
776     stats = NULL;
777   }
778
779   if (NULL != timeout_task)
780     GNUNET_SCHEDULER_cancel (timeout_task);
781   if (NULL != update_task)
782     GNUNET_SCHEDULER_cancel (update_task);
783   if (NULL != identity_handle)
784     GNUNET_IDENTITY_disconnect (identity_handle);
785   if (NULL != gns_handle)
786     GNUNET_GNS_disconnect (gns_handle);
787   if (NULL != ns_it)
788     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
789   if (NULL != ns_qe)
790     GNUNET_NAMESTORE_cancel (ns_qe);
791   if (NULL != ns_handle)
792     GNUNET_NAMESTORE_disconnect (ns_handle);
793   if (NULL != token)
794     GNUNET_free (token);
795   if (NULL != label)
796     GNUNET_free (label);
797
798   for (ego_entry = ego_head;
799        NULL != ego_entry;)
800   {
801     ego_tmp = ego_entry;
802     if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
803     {
804       GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
805                                              &clear_ego_attrs,
806                                              ego_tmp);
807
808     }
809     GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
810     ego_entry = ego_entry->next;
811     GNUNET_free (ego_tmp);
812   }
813 }
814
815 /**
816  * Shutdown task
817  *
818  * @param cls NULL
819  * @param tc task context
820  */
821 static void
822 do_shutdown (void *cls,
823              const struct GNUNET_SCHEDULER_TaskContext *tc)
824 {
825   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
826               "Shutting down...\n");
827   cleanup();
828 }
829
830
831 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
832 create_exchange_result_message (const char* token,
833                                 const char* label)
834 {
835   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
836   uint16_t token_len = strlen (token) + 1;
837   erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
838                        + token_len);
839   erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
840   erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
841                             + token_len);
842   memcpy (&erm[1], token, token_len);
843   return erm;
844 }
845
846
847 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
848 create_issue_result_message (const char* ticket)
849 {
850   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
851
852   irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen(ticket) + 1);
853   irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
854   irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) + strlen (ticket) + 1);
855   memcpy (&irm[1], ticket, strlen (ticket) + 1);
856   return irm;
857 }
858
859 void
860 store_token_issue_cont (void *cls,
861                         int32_t success,
862                         const char *emsg)
863 {
864   struct IssueHandle *handle = cls;
865   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
866   char* token_ticket_str;
867   handle->ns_qe = NULL;
868   if (GNUNET_SYSERR == success)
869   {
870     //TODO err msg
871     return;
872   }
873   if (GNUNET_OK != ticket_serialize (handle->ticket,
874                                      &handle->iss_key,
875                                      &token_ticket_str))
876   {
877     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
878     ticket_destroy (handle->ticket);
879     GNUNET_free (handle);
880     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 
881     return;
882   }
883   irm = create_issue_result_message (token_ticket_str);
884   GNUNET_SERVER_notification_context_unicast (nc,
885                                               handle->client,
886                                               &irm->header,
887                                               GNUNET_NO);
888   GNUNET_free (irm);
889   GNUNET_free (token_ticket_str);
890   GNUNET_SERVER_receive_done (handle->client, GNUNET_OK);
891 }
892
893 /**
894  * Build a GNUid token for identity
895  * @param handle the handle
896  * @param ego_entry the ego to build the token for
897  * @param name name of the ego
898  * @param token_aud token audience
899  * @param token the resulting gnuid token
900  * @return identifier string of token (label)
901  */
902 static void
903 sign_and_return_token (void *cls,
904                        const struct GNUNET_SCHEDULER_TaskContext *tc)
905 {
906   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
907   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
908   struct GNUNET_CRYPTO_EcdsaPublicKey aud_pkey;
909   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
910   struct IssueHandle *handle = cls;
911   struct GNUNET_GNSRECORD_Data token_record[2];
912   struct GNUNET_TIME_Relative etime_rel;
913   char *lbl_str;
914   char *nonce_str;
915   char *enc_token_str;
916   char *token_metadata;
917   char *scopes;
918   char* write_ptr;
919   uint64_t time;
920   uint64_t exp_time;
921   uint64_t rnd_key;
922   size_t token_metadata_len;
923
924   //Remote nonce 
925   nonce_str = NULL;
926   GNUNET_asprintf (&nonce_str, "%d", handle->nonce);
927   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
928
929   //Label
930   rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
931   GNUNET_STRINGS_base64_encode ((char*)&rnd_key, sizeof (uint64_t), &lbl_str);
932   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
933                                       &pub_key);
934
935   handle->ticket = ticket_create (nonce_str,
936                                   &pub_key,
937                                   lbl_str,
938                                   &aud_pkey);
939
940
941
942   if (GNUNET_OK !=
943       GNUNET_STRINGS_fancy_time_to_relative ("1d", //TODO
944                                              &etime_rel))
945   {
946     ticket_destroy (handle->ticket);
947     GNUNET_free (handle);
948     GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
949     return;
950   }
951   time = GNUNET_TIME_absolute_get().abs_value_us;
952   exp_time = time + etime_rel.rel_value_us;
953
954   token_add_json (handle->token, "nbf", json_integer (time));
955   token_add_json (handle->token, "iat", json_integer (time));
956   token_add_json (handle->token, "exp", json_integer (exp_time));
957   token_add_attr (handle->token, "nonce", nonce_str);
958
959
960   //Token in a serialized encrypted format 
961   GNUNET_assert (token_serialize (handle->token,
962                                   &handle->iss_key,
963                                   &ecdhe_privkey,
964                                   &enc_token_str));
965
966   //Token record E,E_K (Token)
967   token_record[0].data = enc_token_str;
968   token_record[0].data_size = strlen (enc_token_str) + 1;
969   token_record[0].expiration_time = exp_time;
970   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
971   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
972
973
974   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
975     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
976     + strlen (handle->scopes) + 1; //With 0-Terminator
977   token_metadata = GNUNET_malloc (token_metadata_len);
978   write_ptr = token_metadata;
979   memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
980   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
981   memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
982   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
983   memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
984
985   GNUNET_free (ecdhe_privkey);
986
987   token_record[1].data = token_metadata;
988   token_record[1].data_size = token_metadata_len;
989   token_record[1].expiration_time = exp_time;
990   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
991   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
992
993   //Persist token
994   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
995                                                   priv_key,
996                                                   lbl_str,
997                                                   2,
998                                                   token_record,
999                                                   &store_token_issue_cont,
1000                                                   handle);
1001   GNUNET_free (lbl_str);
1002   GNUNET_free (enc_token_str);
1003 }
1004
1005 /**
1006  * Collect attributes for token
1007  */
1008 static void
1009 attr_collect (void *cls,
1010               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1011               const char *label,
1012               unsigned int rd_count,
1013               const struct GNUNET_GNSRECORD_Data *rd)
1014 {
1015   int i;
1016   char* data;
1017   json_t *attr_arr;
1018   struct IssueHandle *handle = cls;
1019   struct GNUNET_HashCode key;
1020
1021   if (NULL == label)
1022   {
1023     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1024     handle->ns_it = NULL;
1025     GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1026     return;
1027   }
1028
1029   GNUNET_CRYPTO_hash (label,
1030                       strlen (label),
1031                       &key);
1032
1033   if (0 == rd_count ||
1034       ( (NULL != handle->attr_map) &&
1035         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1036                                                                &key))
1037       )
1038      )
1039   {
1040     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1041     return;
1042   }
1043
1044   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1045
1046   if (1 == rd_count)
1047   {
1048     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1049     {
1050       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1051                                                rd->data,
1052                                                rd->data_size);
1053       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1054       token_add_json (handle->token,
1055                       label,
1056                       json_string (data));
1057       GNUNET_free (data);
1058     }
1059     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1060     return;
1061   }
1062
1063   i = 0;
1064   attr_arr = json_array();
1065   for (; i < rd_count; i++)
1066   {
1067     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1068     {
1069       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1070                                                rd[i].data,
1071                                                rd[i].data_size);
1072       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1073       json_array_append_new (attr_arr, json_string (data));
1074       GNUNET_free (data);
1075     }
1076   }
1077
1078   if (0 < json_array_size (attr_arr))
1079   {
1080     token_add_json (handle->token, label, attr_arr);
1081   }
1082   json_decref (attr_arr);
1083   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1084 }
1085
1086 static void
1087 process_lookup_result (void *cls, uint32_t rd_count,
1088                        const struct GNUNET_GNSRECORD_Data *rd)
1089 {
1090   struct ExchangeHandle *handle = cls;
1091   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1092   char* token_str;
1093   char* record_str;
1094
1095   handle->lookup_request = NULL;
1096   if (2 != rd_count)
1097   {
1098     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1099                 "Number of tokens %d != 2.",
1100                 rd_count);
1101     GNUNET_free (handle->label);
1102     GNUNET_free (handle);
1103     GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1104     return;
1105   }
1106
1107   record_str = 
1108     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1109                                       rd->data,
1110                                       rd->data_size);
1111
1112   //Decrypt and parse
1113   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1114                                             &handle->aud_privkey,
1115                                             &handle->token));
1116
1117   //Readable
1118   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1119                                                &handle->aud_privkey,
1120                                                &token_str));
1121
1122   erm = create_exchange_result_message (token_str,
1123                                         handle->label);
1124   GNUNET_SERVER_notification_context_unicast (nc,
1125                                               handle->client,
1126                                               &erm->header,
1127                                               GNUNET_NO);
1128   GNUNET_free (erm);
1129   GNUNET_SERVER_receive_done (handle->client, GNUNET_OK);
1130
1131 }
1132
1133 /**
1134  *
1135  * Handler for exchange message
1136  *
1137  * @param cls unused
1138  * @param client who sent the message
1139  * @param message the message
1140  */
1141 static void
1142 handle_exchange_message (void *cls,
1143                          struct GNUNET_SERVER_Client *client,
1144                          const struct GNUNET_MessageHeader *message)
1145 {
1146   const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1147   struct ExchangeHandle *xchange_handle;
1148   uint16_t size;
1149   const char *ticket;
1150   char *lookup_query;
1151
1152   size = ntohs (message->size);
1153   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1154   {
1155     GNUNET_break (0);
1156     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1157     return;
1158   }
1159   em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1160   ticket = (const char *) &em[1];
1161   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1162               "Received EXCHANGE of `%s' from client\n",
1163               ticket);
1164   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1165   xchange_handle->aud_privkey = em->aud_privkey;
1166   if (GNUNET_SYSERR == ticket_parse (ticket,
1167                                      &xchange_handle->aud_privkey,
1168                                      &xchange_handle->ticket))
1169   {
1170     GNUNET_free (xchange_handle);
1171     GNUNET_break (0);
1172     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1173     return;
1174   }
1175   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
1176               xchange_handle->ticket->payload->label);
1177   GNUNET_asprintf (&lookup_query,
1178                    "%s.gnu",
1179                    xchange_handle->ticket->payload->label);
1180   xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1181                                                       lookup_query,
1182                                                       &xchange_handle->ticket->payload->identity_key,
1183                                                       GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1184                                                       GNUNET_GNS_LO_LOCAL_MASTER,
1185                                                       NULL,
1186                                                       &process_lookup_result,
1187                                                       xchange_handle);
1188   GNUNET_free (lookup_query);
1189
1190 }
1191
1192 /**
1193  *
1194  * Handler for issue message
1195  *
1196  * @param cls unused
1197  * @param client who sent the message
1198  * @param message the message
1199  */
1200 static void
1201 handle_issue_message (void *cls,
1202                       struct GNUNET_SERVER_Client *client,
1203                       const struct GNUNET_MessageHeader *message)
1204 {
1205   const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1206   uint16_t size;
1207   const char *scopes;
1208   char *scopes_tmp;
1209   char *scope;
1210   char *attr_list_tmp;
1211   struct GNUNET_HashCode key;
1212   struct IssueHandle *issue_handle;
1213
1214   size = ntohs (message->size);
1215   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1216   {
1217     GNUNET_break (0);
1218     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1219     return;
1220   }
1221   im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1222   scopes = (const char *) &im[1];
1223   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224               "Received ISSUE of `%s' from client\n",
1225               scope);
1226   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1227   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1228                                                                  GNUNET_NO);
1229   scopes_tmp = GNUNET_strdup (scopes);
1230   scope = strtok(attr_list_tmp, ",");
1231   for (; NULL != scope; scope = strtok (NULL, ","))
1232   {
1233     GNUNET_CRYPTO_hash (scope,
1234                         strlen (scope),
1235                         &key);
1236     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1237                                        &key,
1238                                        scope,
1239                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1240   }
1241   GNUNET_free (scopes_tmp);
1242
1243   issue_handle->aud_key = im->aud_key;
1244   issue_handle->iss_key = im->iss_key;
1245   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1246   issue_handle->nonce = im->nonce;
1247   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1248                                       &issue_handle->iss_pkey);
1249   issue_handle->token = token_create (&issue_handle->iss_pkey,
1250                                       &im->aud_key);
1251
1252   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1253                                                                &im->iss_key,
1254                                                                &attr_collect,
1255                                                                issue_handle);
1256   GNUNET_SERVER_receive_done (client, GNUNET_OK); //TODO here?
1257
1258
1259 }
1260
1261 /**
1262  * Main function that will be run
1263  *
1264  * @param cls closure
1265  * @param args remaining command-line arguments
1266  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1267  * @param c configuration
1268  */
1269 static void
1270 run (void *cls, 
1271      struct GNUNET_SERVER_Handle *server,
1272      const struct GNUNET_CONFIGURATION_Handle *c)
1273 {
1274   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1275     {&handle_issue_message, NULL,
1276       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1277     {&handle_exchange_message, NULL,
1278       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1279     {NULL, NULL, 0, 0}
1280   };
1281
1282   cfg = c;
1283
1284   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1285   GNUNET_SERVER_add_handlers (server, handlers);
1286   nc = GNUNET_SERVER_notification_context_create (server, 1);
1287
1288   //Connect to identity and namestore services
1289   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1290   if (NULL == ns_handle)
1291   {
1292     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1293   }
1294
1295   gns_handle = GNUNET_GNS_connect (cfg);
1296   if (NULL == gns_handle)
1297   {
1298     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1299   }
1300
1301   identity_handle = GNUNET_IDENTITY_connect (cfg,
1302                                              &list_ego,
1303                                              NULL);
1304
1305   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1306                                 &do_shutdown, NULL);
1307 }
1308
1309
1310 /**
1311  *
1312  * The main function
1313  *
1314  * @param argc number of arguments from the cli
1315  * @param argv command line arguments
1316  * @return 0 ok, 1 on error
1317  *
1318  */
1319 int
1320 main (int argc, char *const *argv)
1321 {
1322   return  (GNUNET_OK ==
1323            GNUNET_SERVICE_run (argc, argv, "identity-provider",
1324                                GNUNET_SERVICE_OPTION_NONE,
1325                                &run, NULL)) ? 0 : 1;
1326 }
1327
1328 /* end of gnunet-rest-server.c */