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