- Add attribute store API to IdP service
[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  * Identity handle
63  */
64 static struct GNUNET_IDENTITY_Handle *identity_handle;
65
66 /**
67  * Token expiration interval
68  */
69 static struct GNUNET_TIME_Relative token_expiration_interval;
70
71 /**
72  * Namestore handle
73  */
74 static struct GNUNET_NAMESTORE_Handle *ns_handle;
75
76 /**
77  * GNS handle
78  */
79 static struct GNUNET_GNS_Handle *gns_handle;
80
81 /**
82  * Credential handle
83  */
84 static struct GNUNET_CREDENTIAL_Handle *credential_handle;
85
86 /**
87  * Namestore qe
88  */
89 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
90
91 /**
92  * Namestore iterator
93  */
94 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
95
96 /**
97  * Timeout task
98  */
99 static struct GNUNET_SCHEDULER_Task *timeout_task;
100
101 /**
102  * Update task
103  */
104 static struct GNUNET_SCHEDULER_Task *update_task;
105
106
107 /**
108  * Currently processed token
109  */
110 static struct IdentityToken *token;
111
112 /**
113  * Label for currently processed token
114  */
115 static char* label;
116
117 /**
118  * Scopes for processed token
119  */
120 static char* scopes;
121
122 /**
123  * Handle to the statistics service.
124  */
125 static struct GNUNET_STATISTICS_Handle *stats;
126
127 /**
128  * Our configuration.
129  */
130 static const struct GNUNET_CONFIGURATION_Handle *cfg;
131
132 struct AttributeStoreHandle
133 {
134
135   /**
136    * Client connection
137    */
138   struct GNUNET_SERVICE_Client *client;
139
140   /**
141    * Identity
142    */
143   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
144
145   /**
146    * Identity pubkey
147    */
148   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
149
150   /**
151    * The issuer egos ABE master key
152    */
153   struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
154
155   /**
156    * QueueEntry
157    */
158   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
159
160   /**
161    * The attribute name
162    */
163   char *name;
164
165   /**
166    * The attribute value
167    */
168   char *attribute_value;
169
170   /**
171    * Size of the attribute value
172    */
173   size_t attribute_value_len;
174
175   /**
176    * request id
177    */
178   uint32_t r_id;
179 };
180
181
182
183 struct VerifiedAttributeEntry
184 {
185   /**
186    * DLL
187    */
188   struct VerifiedAttributeEntry *prev;
189
190   /**
191    * DLL
192    */
193   struct VerifiedAttributeEntry *next;
194
195   /**
196    * Attribute Name
197    */
198   char* name;
199 };
200
201 struct ParallelLookups;
202
203 struct ExchangeHandle
204 {
205
206   /**
207    * Client connection
208    */
209   struct GNUNET_SERVICE_Client *client;
210
211   /**
212    * Ticket
213    */
214   struct TokenTicket *ticket;
215
216   /**
217    * Token returned
218    */
219   struct IdentityToken *token;
220
221   /**
222    * LookupRequest
223    */
224   struct GNUNET_GNS_LookupRequest *lookup_request;
225
226   /**
227    * Audience Key
228    */
229   struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
230   
231   /**
232    * ParallelLookups DLL
233    */
234   struct ParallelLookup *parallel_lookups_head;
235   struct ParallelLookup *parallel_lookups_tail;
236   
237   struct GNUNET_SCHEDULER_Task *kill_task;
238   struct GNUNET_CRYPTO_AbeKey *key;
239
240   /**
241    * Label to return
242    */
243   char *label;
244
245   /**
246    * request id
247    */
248   uint32_t r_id;
249 };
250
251 struct ParallelLookup
252 {
253   struct ParallelLookup *next;
254
255   struct ParallelLookup *prev;
256
257   struct GNUNET_GNS_LookupRequest *lookup_request;
258
259   struct ExchangeHandle *handle;
260
261   char *label;
262 };
263
264 struct IssueHandle
265 {
266
267   /**
268    * Client connection
269    */
270   struct GNUNET_SERVICE_Client *client;
271
272   /**
273    * Issuer Key
274    */
275   struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
276
277   /**
278    * Issue pubkey
279    */
280   struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
281
282   /**
283    * Audience Key
284    */
285   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
286
287   /**
288    * The issuer egos ABE master key
289    */
290   struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
291
292   /**
293    * Expiration
294    */
295   struct GNUNET_TIME_Absolute expiration;
296
297   /**
298    * Scopes
299    */
300   char *scopes;
301
302   /**
303    * DLL
304    */
305   struct VerifiedAttributeEntry *v_attr_head;
306
307   /**
308    * DLL
309    */
310   struct VerifiedAttributeEntry *v_attr_tail;
311
312   /**
313    * nonce
314    */
315   uint64_t nonce;
316
317   /**
318    * NS iterator
319    */
320   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
321
322   /**
323    * Cred request
324    */
325   struct GNUNET_CREDENTIAL_Request *credential_request;
326
327   /**
328    * Attribute map
329    */
330   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
331
332   /**
333    * Token
334    */
335   struct IdentityToken *token;
336
337   /**
338    * Ticket
339    */
340   struct TokenTicket *ticket;
341
342   /**
343    * QueueEntry
344    */
345   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
346
347   /**
348    * The label the token is stored under
349    */
350   char *label;
351
352   /**
353    * request id
354    */
355   uint32_t r_id;
356 };
357
358 /**
359  * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
360  *
361  */
362 struct EgoEntry
363 {
364   /**
365    * DLL
366    */
367   struct EgoEntry *next;
368
369   /**
370    * DLL
371    */
372   struct EgoEntry *prev;
373
374   /**
375    * Ego handle
376    */
377   struct GNUNET_IDENTITY_Ego *ego;
378
379   /**
380    * Attribute map. Contains the attributes as json_t
381    */
382   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
383
384 };
385
386 /**
387  * Cleanup task
388  */
389 static void
390 cleanup()
391 {
392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393               "Cleaning up\n");
394   if (NULL != stats)
395   {
396     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
397     stats = NULL;
398   }
399
400   if (NULL != timeout_task)
401     GNUNET_SCHEDULER_cancel (timeout_task);
402   if (NULL != update_task)
403     GNUNET_SCHEDULER_cancel (update_task);
404   if (NULL != identity_handle)
405     GNUNET_IDENTITY_disconnect (identity_handle);
406   if (NULL != gns_handle)
407     GNUNET_GNS_disconnect (gns_handle);
408   if (NULL != credential_handle)
409     GNUNET_CREDENTIAL_disconnect (credential_handle);
410   if (NULL != ns_it)
411     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
412   if (NULL != ns_qe)
413     GNUNET_NAMESTORE_cancel (ns_qe);
414   if (NULL != ns_handle)
415     GNUNET_NAMESTORE_disconnect (ns_handle);
416   if (NULL != token)
417     GNUNET_free (token);
418   if (NULL != label)
419     GNUNET_free (label);
420
421 }
422
423 /**
424  * Shutdown task
425  *
426  * @param cls NULL
427  * @param tc task context
428  */
429 static void
430 do_shutdown (void *cls)
431 {
432   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433               "Shutting down...\n");
434   cleanup();
435 }
436
437
438 static struct GNUNET_MQ_Envelope*
439 create_exchange_result_message (const char* token,
440                                 const char* label,
441                                 uint64_t ticket_nonce,
442                                 uint64_t id)
443 {
444   struct GNUNET_MQ_Envelope *env;
445   struct ExchangeResultMessage *erm;
446   uint16_t token_len = strlen (token) + 1;
447
448   env = GNUNET_MQ_msg_extra (erm,
449                              token_len,
450                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
451   erm->ticket_nonce = htonl (ticket_nonce);
452   erm->id = id;
453   GNUNET_memcpy (&erm[1], token, token_len);
454   return env;
455 }
456
457
458 static struct GNUNET_MQ_Envelope*
459 create_issue_result_message (const char* label,
460                              const char* ticket,
461                              const char* token,
462                              uint64_t id)
463 {
464   struct GNUNET_MQ_Envelope *env;
465   struct IssueResultMessage *irm;
466   char *tmp_str;
467   size_t len;
468
469   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
470   len = strlen (tmp_str) + 1;
471   env = GNUNET_MQ_msg_extra (irm,
472                              len,
473                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
474   irm->id = id;
475   GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
476   GNUNET_free (tmp_str);
477   return env;
478 }
479
480 static void
481 cleanup_issue_handle (struct IssueHandle *handle)
482 {
483   if (NULL != handle->attr_map)
484     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
485   if (NULL != handle->scopes)
486     GNUNET_free (handle->scopes);
487   if (NULL != handle->token)
488     token_destroy (handle->token);
489   if (NULL != handle->ticket)
490     ticket_destroy (handle->ticket);
491   if (NULL != handle->label)
492     GNUNET_free (handle->label);
493   if (NULL != handle->ns_it)
494     GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
495   if (NULL != handle->credential_request)
496     GNUNET_CREDENTIAL_request_cancel (handle->credential_request);
497   GNUNET_free (handle);
498 }
499
500 static void
501 store_record_issue_cont (void *cls,
502                         int32_t success,
503                         const char *emsg)
504 {
505   struct IssueHandle *handle = cls;
506   struct GNUNET_MQ_Envelope *env;
507   char *ticket_str;
508   char *token_str;
509
510   handle->ns_qe = NULL;
511   if (GNUNET_SYSERR == success)
512   {
513     cleanup_issue_handle (handle);
514     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
515                 "Unknown Error\n");
516     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
517     return;
518   }
519   if (GNUNET_OK != ticket_serialize (handle->ticket,
520                                      &handle->iss_key,
521                                      &ticket_str))
522   {
523     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
524                 "Error serializing ticket\n");
525     cleanup_issue_handle (handle);
526     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
527     return;
528   }
529   if (GNUNET_OK != token_to_string (handle->token,
530                                     &handle->iss_key,
531                                     &token_str))
532   {
533     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
534                 "Error serializing token\n");
535     GNUNET_free (ticket_str);
536     cleanup_issue_handle (handle);
537     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
538     return;
539   }
540   env = create_issue_result_message (handle->label,
541                                      ticket_str,
542                                      token_str,
543                                      handle->r_id);
544   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
545                   env);
546   cleanup_issue_handle (handle);
547   GNUNET_free (ticket_str);
548   GNUNET_free (token_str);
549 }
550
551 static int
552 create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
553                          struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
554                          struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
555 {
556   struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
557
558   GNUNET_CRYPTO_hash_to_enc (new_key_hash,
559                              &new_key_hash_str);
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
561   static const char ctx_key[] = "gnuid-aes-ctx-key";
562   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
563                      new_key_hash, sizeof (struct GNUNET_HashCode),
564                      ctx_key, strlen (ctx_key),
565                      NULL, 0);
566   static const char ctx_iv[] = "gnuid-aes-ctx-iv";
567   GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
568                      new_key_hash, sizeof (struct GNUNET_HashCode),
569                      ctx_iv, strlen (ctx_iv),
570                      NULL, 0);
571   return GNUNET_OK;
572 }
573
574 int
575 serialize_abe_keyinfo (const struct IssueHandle *handle,
576                  const struct GNUNET_CRYPTO_AbeKey *rp_key,
577                  struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
578                  char **result)
579 {
580   char *enc_keyinfo;
581   char *serialized_key;
582   char *buf;
583   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
584   ssize_t size;
585   
586   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
587   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
588   struct GNUNET_HashCode new_key_hash;
589   ssize_t enc_size;
590   
591   size = GNUNET_CRYPTO_cpabe_serialize_key (rp_key,
592                                             (void**)&serialized_key);
593   buf = GNUNET_malloc (strlen (handle->scopes) + 1 + size);
594   GNUNET_memcpy (buf,
595                  handle->scopes,
596                  strlen (handle->scopes) + 1);
597   GNUNET_memcpy (buf + strlen (handle->scopes) + 1,
598                  serialized_key,
599                  size);
600   // ECDH keypair E = eG
601   *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
602   GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
603                                       &ecdh_pubkey);
604   enc_keyinfo = GNUNET_malloc (size + strlen (handle->scopes) + 1);
605   // Derived key K = H(eB)
606   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
607                                                         &handle->aud_key,
608                                                         &new_key_hash));
609   create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
610   enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
611                                               size + strlen (handle->scopes) + 1,
612                                               &skey, &iv,
613                                               enc_keyinfo);
614   *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
615                            enc_size);
616   GNUNET_memcpy (*result,
617                  &ecdh_pubkey,
618                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
619   GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
620                  enc_keyinfo,
621                  enc_size);
622   GNUNET_free (enc_keyinfo);
623   return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
624 }
625
626 static void
627 cleanup_exchange_handle (struct ExchangeHandle *handle)
628 {
629   if (NULL != handle->ticket)
630     ticket_destroy (handle->ticket);
631   if (NULL != handle->token)
632     token_destroy (handle->token);
633   GNUNET_free (handle);
634 }
635
636
637 /**
638  * Build a token and store it
639  *
640  * @param cls the IssueHandle
641  */
642 static void
643 sign_and_return_token (void *cls)
644 {
645   struct ExchangeHandle *handle = cls;
646   struct GNUNET_MQ_Envelope *env;
647   char *token_str;
648   uint64_t time;
649   uint64_t exp_time;
650
651   time = GNUNET_TIME_absolute_get().abs_value_us;
652   exp_time = time + token_expiration_interval.rel_value_us;
653
654   token_add_attr_int (handle->token, "nbf", time);
655   token_add_attr_int (handle->token, "iat", time);
656   token_add_attr_int (handle->token, "exp", exp_time);
657   
658   //Readable
659   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
660                                                &handle->aud_privkey,
661                                                &token_str));
662
663   env = create_exchange_result_message (token_str,
664                                         handle->label,
665                                         handle->ticket->payload->nonce,
666                                         handle->r_id);
667   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
668                   env);
669   cleanup_exchange_handle (handle);
670   GNUNET_free (token_str);
671
672 }
673
674 /**
675  * Build an ABE key and store it
676  *
677  * @param cls the IssueHandle
678  */
679 static void
680 issue_ticket (void *cls)
681 {
682   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
683   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
684   struct IssueHandle *handle = cls;
685   struct GNUNET_GNSRECORD_Data code_record[1];
686   struct GNUNET_CRYPTO_AbeKey *rp_key;
687   char *nonce_str;
688   char *code_record_data;
689   char **attrs;
690   char *scope;
691   char *scopes_tmp;
692   int attrs_len;
693   int i;
694   uint64_t time;
695   uint64_t exp_time;
696   size_t code_record_len;
697
698   //Remote nonce
699   nonce_str = NULL;
700   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
701   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
702
703   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
704                                       &pub_key);
705   handle->ticket = ticket_create (handle->nonce,
706                                   &pub_key,
707                                   handle->label,
708                                   &handle->aud_key);
709
710   time = GNUNET_TIME_absolute_get().abs_value_us;
711   exp_time = time + token_expiration_interval.rel_value_us;
712
713   token_add_attr_int (handle->token, "nbf", time);
714   token_add_attr_int (handle->token, "iat", time);
715   token_add_attr_int (handle->token, "exp", exp_time);
716   token_add_attr (handle->token, "nonce", nonce_str);
717
718   //Create new ABE key for RP
719   attrs_len = (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) + 1) * sizeof (char*);
720   attrs = GNUNET_malloc (attrs_len);
721   i = 0;
722   scopes_tmp = GNUNET_strdup (handle->scopes);
723   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ",")) {
724     attrs[i] = scope;
725     i++;
726   }
727   rp_key = GNUNET_CRYPTO_cpabe_create_key (handle->abe_key,
728                                            attrs);
729   code_record_len = serialize_abe_keyinfo (handle,
730                                            rp_key,
731                                            &ecdhe_privkey,
732                                            &code_record_data);
733   code_record[0].data = code_record_data;
734   code_record[0].data_size = code_record_len;
735   code_record[0].expiration_time = exp_time;
736   code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
737   code_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
738
739
740   //Publish record
741   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
742                                                   &handle->iss_key,
743                                                   handle->label,
744                                                   1,
745                                                   code_record,
746                                                   &store_record_issue_cont,
747                                                   handle);
748   GNUNET_free (ecdhe_privkey);
749   GNUNET_free (nonce_str);
750   GNUNET_free (code_record_data);
751 }
752
753 /**
754  * Credential to JSON
755  * @param cred the credential
756  * @return the resulting json, NULL if failed
757  */
758 static json_t*
759 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
760 {
761   char *issuer;
762   char *subject;
763   char *signature;
764   char attribute[cred->issuer_attribute_len + 1];
765   json_t *cred_obj;
766
767   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
768   if (NULL == issuer)
769   {
770     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
771                 "Issuer in credential malformed\n");
772     return NULL;
773   }  
774   subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
775   if (NULL == subject)
776   {
777     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
778                 "Subject in credential malformed\n");
779     GNUNET_free (issuer);
780     return NULL;
781   }
782   GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
783                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
784                                 &signature);
785   memcpy (attribute,
786           cred->issuer_attribute,
787           cred->issuer_attribute_len);
788   attribute[cred->issuer_attribute_len] = '\0';
789   cred_obj = json_object ();
790   json_object_set_new (cred_obj, "issuer", json_string (issuer));
791   json_object_set_new (cred_obj, "subject", json_string (subject));
792   json_object_set_new (cred_obj, "attribute", json_string (attribute));
793   json_object_set_new (cred_obj, "signature", json_string (signature));
794   json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
795   GNUNET_free (issuer);
796   GNUNET_free (subject);
797   GNUNET_free (signature);
798   return cred_obj;
799 }
800
801
802 static void
803 handle_vattr_collection (void* cls,
804                          unsigned int d_count,
805                          struct GNUNET_CREDENTIAL_Delegation *dc,
806                          unsigned int c_count,
807                          struct GNUNET_CREDENTIAL_Credential *cred)
808 {
809   struct IssueHandle *handle = cls;
810   struct VerifiedAttributeEntry *vattr;
811   json_t *cred_json;
812   json_t *cred_array;
813   int i;
814   handle->credential_request = NULL;
815
816   if (NULL == cred)
817   {
818     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
819     return;
820   }
821   cred_array = json_array();
822   for (i=0;i<c_count;i++)
823   {
824     cred_json = credential_to_json (cred);
825     if (NULL == cred_json)
826       continue;
827     json_array_append (cred_array, cred_json);
828     token_add_attr_json (handle->token,
829                          handle->v_attr_head->name,
830                          cred_array);
831   }
832   json_decref (cred_array);
833   vattr = handle->v_attr_head;
834
835   GNUNET_CONTAINER_DLL_remove (handle->v_attr_head,
836                                handle->v_attr_tail,
837                                vattr);
838   GNUNET_free (vattr->name);
839   GNUNET_free (vattr);
840
841   if (NULL == handle->v_attr_head)
842   {
843     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
844     return;
845   }
846   handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
847                                                           &handle->aud_key,
848                                                           handle->v_attr_head->name,
849                                                           &handle->iss_key,
850                                                           &handle_vattr_collection,
851                                                           handle);
852
853 }
854
855
856 static void
857 attr_collect_error (void *cls)
858 {
859   struct IssueHandle *handle = cls;
860
861   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
862   handle->ns_it = NULL;
863   GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
864 }
865
866
867 static void
868 attr_collect_finished (void *cls)
869 {
870   struct IssueHandle *handle = cls;
871
872   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
873   handle->ns_it = NULL;
874
875   if (NULL == handle->v_attr_head)
876   {
877     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
878     return;
879   }
880   handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
881                                                           &handle->aud_key,
882                                                           handle->v_attr_head->name,
883                                                           &handle->iss_key,
884                                                           &handle_vattr_collection,
885                                                           handle);
886 }
887 /**
888  * Collect attributes for token
889  */
890 static void
891 attr_collect (void *cls,
892               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
893               const char *label,
894               unsigned int rd_count,
895               const struct GNUNET_GNSRECORD_Data *rd)
896 {
897   struct IssueHandle *handle = cls;
898   int i;
899   char* data;
900   struct GNUNET_HashCode key;
901
902   GNUNET_CRYPTO_hash (label,
903                       strlen (label),
904                       &key);
905
906   if (0 == rd_count ||
907       ( (NULL != handle->attr_map) &&
908         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
909                                                                &key))
910       )
911      )
912   {
913     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
914     return;
915   }
916
917   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
918
919   if (1 == rd_count)
920   {
921     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
922     {
923       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
924                                                rd->data,
925                                                rd->data_size);
926       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
927       token_add_attr (handle->token,
928                       label,
929                       data);
930       GNUNET_free (data);
931     }
932     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
933     return;
934   }
935
936   i = 0;
937   for (; i < rd_count; i++)
938   {
939     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
940     {
941       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
942                                                rd[i].data,
943                                                rd[i].data_size);
944       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
945       token_add_attr (handle->token, label, data);
946       GNUNET_free (data);
947     }
948   }
949
950   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
951 }
952
953 static void
954 process_parallel_lookup (void *cls, uint32_t rd_count,
955                          const struct GNUNET_GNSRECORD_Data *rd)
956 {
957   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
958               "Parallel lookup finished (count=%u)\n", rd_count);
959   struct ParallelLookup *parallel_lookup = cls;
960   struct ExchangeHandle *handle = parallel_lookup->handle;
961   char *data;
962   int i;
963
964   GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
965                                handle->parallel_lookups_tail,
966                                parallel_lookup);
967   GNUNET_free (parallel_lookup);
968   if (1 == rd_count)
969   {
970     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
971     {
972       GNUNET_CRYPTO_cpabe_decrypt (rd->data,
973                                    rd->data_size,
974                                    handle->key,
975                                    (void**)&data);
976       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Adding value: %s\n", data);
977       token_add_attr (handle->token,
978                       parallel_lookup->label,
979                       data);
980       GNUNET_free (data);
981     }
982   } else {
983     i = 0;
984     for (; i < rd_count; i++)
985     {
986       if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
987       {
988         data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
989                                                  rd[i].data,
990                                                  rd[i].data_size);
991         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Adding value: %s\n", data);
992         token_add_attr (handle->token, parallel_lookup->label, data);
993         GNUNET_free (data);
994       }
995     }
996   }
997   if (NULL != handle->parallel_lookups_head)
998     return; //Wait for more
999   //Else we are done
1000   GNUNET_SCHEDULER_cancel (handle->kill_task);
1001   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1002 }
1003
1004 void
1005 abort_parallel_lookups (void *cls)
1006 {
1007   struct ExchangeHandle *handle = cls;
1008   struct ParallelLookup *lu;
1009   struct ParallelLookup *tmp;
1010
1011   for (lu = handle->parallel_lookups_head;
1012        NULL != lu;) {
1013     GNUNET_GNS_lookup_cancel (lu->lookup_request);
1014     GNUNET_free (lu->label);
1015     tmp = lu->next;
1016     GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1017                                  handle->parallel_lookups_tail,
1018                                  lu);
1019       GNUNET_free (lu);
1020       lu = tmp;
1021   }
1022   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1023
1024 }
1025
1026 static void
1027 process_lookup_result (void *cls, uint32_t rd_count,
1028                        const struct GNUNET_GNSRECORD_Data *rd)
1029 {
1030   struct ExchangeHandle *handle = cls;
1031   struct GNUNET_HashCode new_key_hash;
1032   struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
1033   struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
1034   struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key;
1035   struct ParallelLookup *parallel_lookup;
1036   size_t size;
1037   char *buf;
1038   char *scope;
1039   char *lookup_query;
1040
1041   handle->lookup_request = NULL;
1042   if (1 != rd_count)
1043   {
1044     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1045                 "Number of keys %d != 1.",
1046                 rd_count);
1047     cleanup_exchange_handle (handle);
1048     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1049     return;
1050   }
1051
1052   //Decrypt
1053   ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data;
1054
1055   buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1056
1057   //Calculate symmetric key from ecdh parameters
1058   GNUNET_assert (GNUNET_OK == 
1059                  GNUNET_CRYPTO_ecdsa_ecdh (&handle->aud_privkey,
1060                                            ecdh_key,
1061                                            &new_key_hash));
1062   create_sym_key_from_ecdh (&new_key_hash,
1063                             &enc_key,
1064                             &enc_iv);
1065   size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1066                                           rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1067                                           &enc_key,
1068                                           &enc_iv,
1069                                           buf);
1070
1071   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072               "Decrypted bytes: %zd Expected bytes: %zd\n",
1073               size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1074
1075   scopes = GNUNET_strdup (buf);
1076   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1077               "Scopes %s\n", scopes);
1078   handle->key = GNUNET_CRYPTO_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1),
1079                                          rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)
1080                                          - strlen (scopes) - 1);
1081
1082   for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ","))
1083   {
1084     GNUNET_asprintf (&lookup_query,
1085                      "%s.gnu",
1086                      scope);
1087     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1088                 "Looking up %s\n", lookup_query);
1089     parallel_lookup = GNUNET_new (struct ParallelLookup);
1090     parallel_lookup->handle = handle;
1091     parallel_lookup->label = GNUNET_strdup (scope);
1092     parallel_lookup->lookup_request
1093       = GNUNET_GNS_lookup (gns_handle,
1094                            lookup_query,
1095                            &handle->ticket->payload->identity_key,
1096                            GNUNET_GNSRECORD_TYPE_ID_ATTR,
1097                            GNUNET_GNS_LO_LOCAL_MASTER,
1098                            &process_parallel_lookup,
1099                            parallel_lookup);
1100     GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head,
1101                                  handle->parallel_lookups_tail,
1102                                  parallel_lookup);
1103   }
1104   handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3),
1105                                 &abort_parallel_lookups,
1106                                 handle);
1107 }
1108
1109 /**
1110  * Checks a exchange message
1111  *
1112  * @param cls client sending the message
1113  * @param xm message of type `struct ExchangeMessage`
1114  * @return #GNUNET_OK if @a xm is well-formed
1115  */
1116 static int
1117 check_exchange_message (void *cls,
1118                         const struct ExchangeMessage *xm)
1119 {
1120   uint16_t size;
1121
1122   size = ntohs (xm->header.size);
1123   if (size <= sizeof (struct ExchangeMessage))
1124   {
1125     GNUNET_break (0);
1126     return GNUNET_SYSERR;
1127   }
1128   return GNUNET_OK;
1129 }
1130
1131 /**
1132  *
1133  * Handler for exchange message
1134  *
1135  * @param cls unused
1136  * @param client who sent the message
1137  * @param message the message
1138  */
1139 static void
1140 handle_exchange_message (void *cls,
1141                          const struct ExchangeMessage *xm)
1142 {
1143   struct ExchangeHandle *xchange_handle;
1144   struct GNUNET_SERVICE_Client *client = cls;
1145   const char *ticket;
1146   char *lookup_query;
1147
1148   ticket = (const char *) &xm[1];
1149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1150               "Received EXCHANGE of `%s' from client\n",
1151               ticket);
1152   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1153   xchange_handle->aud_privkey = xm->aud_privkey;
1154   xchange_handle->r_id = xm->id;
1155   if (GNUNET_SYSERR == ticket_parse (ticket,
1156                                      &xchange_handle->aud_privkey,
1157                                      &xchange_handle->ticket))
1158   {
1159     GNUNET_free (xchange_handle);
1160     GNUNET_SERVICE_client_drop (client);
1161     return;
1162   }
1163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for ABE key under %s\n",
1164               xchange_handle->ticket->payload->label);
1165   GNUNET_asprintf (&lookup_query,
1166                    "%s.gnu",
1167                    xchange_handle->ticket->payload->label);
1168   GNUNET_SERVICE_client_continue (client);
1169   xchange_handle->client = client;
1170   xchange_handle->token = token_create (&xchange_handle->ticket->payload->identity_key,
1171                                         &xchange_handle->ticket->payload->identity_key);
1172   xchange_handle->lookup_request
1173     = GNUNET_GNS_lookup (gns_handle,
1174                          lookup_query,
1175                          &xchange_handle->ticket->payload->identity_key,
1176                          GNUNET_GNSRECORD_TYPE_ABE_KEY,
1177                          GNUNET_GNS_LO_LOCAL_MASTER,
1178                          &process_lookup_result,
1179                          xchange_handle);
1180   GNUNET_free (lookup_query);
1181
1182 }
1183
1184 /**
1185  * Checks an issue message
1186  *
1187  * @param cls client sending the message
1188  * @param im message of type `struct IssueMessage`
1189  * @return #GNUNET_OK if @a im is well-formed
1190  */
1191 static int
1192 check_issue_message(void *cls,
1193                     const struct IssueMessage *im)
1194 {
1195   uint16_t size;
1196
1197   size = ntohs (im->header.size);
1198   if (size <= sizeof (struct IssueMessage))
1199   {
1200     GNUNET_break (0);
1201     return GNUNET_SYSERR;
1202   }
1203   scopes = (char *) &im[1];
1204   if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1])
1205   {
1206     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207                 "Malformed scopes received!\n");
1208     GNUNET_break (0);
1209     return GNUNET_SYSERR;
1210   }
1211   return GNUNET_OK;
1212 }
1213
1214 void
1215 attr_collect_task (void *cls)
1216 {
1217   struct IssueHandle *issue_handle = cls;
1218
1219   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1220                                                                &issue_handle->iss_key,
1221                                                                &attr_collect_error,
1222                                                                issue_handle,
1223                                                                &attr_collect,
1224                                                                issue_handle,
1225                                                                &attr_collect_finished,
1226                                                                issue_handle);
1227 }
1228
1229
1230
1231 void
1232 abe_key_lookup_error (void *cls)
1233 {
1234   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1235               "Error looking for ABE master!\n");
1236   GNUNET_SCHEDULER_add_now (&do_shutdown, cls);
1237 }
1238
1239 void
1240 abe_key_lookup_result (void *cls,
1241                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1242                        const char *label,
1243                        unsigned int rd_count,
1244                        const struct GNUNET_GNSRECORD_Data *rd)
1245 {
1246   struct IssueHandle *handle = cls;
1247   int i;
1248
1249   for (i=0;i<rd_count;i++) {
1250     if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type)
1251       continue;
1252     handle->abe_key = GNUNET_CRYPTO_cpabe_deserialize_master_key ((void**)rd[i].data,
1253                                                                   rd[i].data_size);
1254     GNUNET_SCHEDULER_add_now (&attr_collect_task, handle);
1255     return;
1256   }
1257   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1258               "No ABE master found!\n");
1259   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1260
1261 }
1262
1263 /**
1264  *
1265  * Handler for issue message
1266  *
1267  * @param cls unused
1268  * @param client who sent the message
1269  * @param message the message
1270  */
1271 static void
1272 handle_issue_message (void *cls,
1273                       const struct IssueMessage *im)
1274 {
1275   const char *scopes;
1276   char *scopes_tmp;
1277   char *scope;
1278   uint64_t rnd_key;
1279   struct GNUNET_HashCode key;
1280   struct IssueHandle *issue_handle;
1281   struct GNUNET_SERVICE_Client *client = cls;
1282
1283   scopes = (const char *) &im[1];
1284   //v_attrs = (const char *) &im[1] + ntohl(im->scope_len);
1285   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1286   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1287                                                                  GNUNET_NO);
1288   scopes_tmp = GNUNET_strdup (scopes);
1289
1290   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1291   {
1292     GNUNET_CRYPTO_hash (scope,
1293                         strlen (scope),
1294                         &key);
1295     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1296                                        &key,
1297                                        scope,
1298                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1299   }
1300   GNUNET_free (scopes_tmp);
1301   /*scopes_tmp = GNUNET_strdup (v_attrs);
1302
1303     for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1304     {
1305     vattr_entry = GNUNET_new (struct VerifiedAttributeEntry);
1306     vattr_entry->name = GNUNET_strdup (scope);
1307     GNUNET_CONTAINER_DLL_insert (issue_handle->v_attr_head,
1308     issue_handle->v_attr_tail,
1309     vattr_entry);
1310     }
1311     GNUNET_free (scopes_tmp);*/
1312
1313
1314
1315   issue_handle->r_id = im->id;
1316   issue_handle->aud_key = im->aud_key;
1317   issue_handle->iss_key = im->iss_key;
1318   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1319                                       &issue_handle->iss_pkey);
1320   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1321   issue_handle->nonce = ntohl (im->nonce);
1322   GNUNET_SERVICE_client_continue (client);
1323   issue_handle->client = client;
1324   issue_handle->scopes = GNUNET_strdup (scopes);
1325   issue_handle->token = token_create (&issue_handle->iss_pkey,
1326                                       &issue_handle->aud_key);
1327   rnd_key =
1328     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1329                               UINT64_MAX);
1330   GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1331                                 sizeof (uint64_t),
1332                                 &issue_handle->label);
1333   issue_handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
1334                                                          &issue_handle->iss_key,
1335                                                          "+",
1336                                                          &abe_key_lookup_error,
1337                                                          issue_handle,
1338                                                          &abe_key_lookup_result,
1339                                                          issue_handle);
1340 }
1341
1342 static void
1343 cleanup_as_handle (struct AttributeStoreHandle *handle)
1344 {
1345   if (NULL != handle->name)
1346     GNUNET_free (handle->name);
1347   if (NULL != handle->attribute_value)
1348     GNUNET_free (handle->attribute_value);
1349   GNUNET_free (handle);
1350 }
1351
1352
1353
1354 void
1355 attr_store_cont (void *cls,
1356                  int32_t success,
1357                  const char *emsg)
1358 {
1359   struct AttributeStoreHandle *as_handle = cls;
1360   struct GNUNET_MQ_Envelope *env;
1361   struct AttributeStoreResponseMessage *acr_msg;
1362
1363   if (GNUNET_SYSERR == success)
1364   {
1365     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1366                 "Failed to store attribute %s\n",
1367                 emsg);
1368     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1369     return;
1370   }
1371
1372   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1373               "Sending ATTRIBUTE_STORE_RESPONSE message\n");
1374   env = GNUNET_MQ_msg (acr_msg,
1375                        GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE);
1376   acr_msg->id = htonl (as_handle->r_id);
1377   acr_msg->op_result = htonl (GNUNET_OK);
1378   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(as_handle->client),
1379                   env);
1380   cleanup_as_handle (as_handle);
1381 }
1382
1383 void
1384 attr_store_task (void *cls)
1385 {
1386   struct AttributeStoreHandle *as_handle = cls;
1387   struct GNUNET_GNSRECORD_Data rd[1];
1388
1389   /**
1390    * Encrypt the attribute value and store in namestore
1391    */
1392   rd[0].data_size = GNUNET_CRYPTO_cpabe_encrypt (as_handle->attribute_value,
1393                                                  as_handle->attribute_value_len,
1394                                                  as_handle->name, //Policy
1395                                                  as_handle->abe_key,
1396                                                  (void**)&rd[0].data);
1397   rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR;
1398   rd[0].flags = GNUNET_GNSRECORD_RF_NONE;
1399   rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane?
1400   as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1401                                                      &as_handle->identity,
1402                                                      as_handle->name,
1403                                                      1,
1404                                                      rd,
1405                                                      &attr_store_cont,
1406                                                      as_handle);
1407
1408 }
1409
1410 void
1411 store_bootstrap_cont (void *cls,
1412                       int32_t success,
1413                       const char *emsg)
1414 {
1415   if (GNUNET_SYSERR == success)
1416   {
1417     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1418                 "Failed to bootstrap ABE master %s\n",
1419                 emsg);
1420     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1421     return;
1422   }
1423   GNUNET_SCHEDULER_add_now (&attr_store_task, cls);
1424 }
1425
1426 void
1427 store_bootstrap_task (void *cls)
1428 {
1429   struct AttributeStoreHandle *as_handle = cls;
1430   struct GNUNET_GNSRECORD_Data rd[1];
1431
1432   rd[0].data_size = GNUNET_CRYPTO_cpabe_serialize_master_key (as_handle->abe_key,
1433                                                               (void**)&rd[0].data);
1434   rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER;
1435   rd[0].flags = GNUNET_GNSRECORD_RF_NONE | GNUNET_GNSRECORD_RF_PRIVATE;
1436   rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane?
1437   as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1438                                                      &as_handle->identity,
1439                                                      "+",
1440                                                      1,
1441                                                      rd,
1442                                                      &store_bootstrap_cont,
1443                                                      as_handle);
1444 }
1445
1446 void
1447 store_cont_abe_error (void *cls)
1448 {
1449   GNUNET_SCHEDULER_add_now (&do_shutdown, cls);
1450 }
1451
1452 void
1453 store_cont_abe_result (void *cls,
1454                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1455                        const char *label,
1456                        unsigned int rd_count,
1457                        const struct GNUNET_GNSRECORD_Data *rd)
1458 {
1459   struct AttributeStoreHandle *handle = cls;
1460   int i;
1461
1462   for (i=0;i<rd_count;i++) {
1463     if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type)
1464       continue;
1465     handle->abe_key = GNUNET_CRYPTO_cpabe_deserialize_master_key ((void**)rd[i].data,
1466                                                                   rd[i].data_size);
1467     GNUNET_SCHEDULER_add_now (&attr_collect_task, handle);
1468     return;
1469   }
1470
1471   //No ABE master found, bootstrapping...
1472   handle->abe_key = GNUNET_CRYPTO_cpabe_create_master_key ();
1473   GNUNET_SCHEDULER_add_now (&store_bootstrap_task, handle);
1474 }
1475
1476
1477 /**
1478  * Checks a store message
1479  *
1480  * @param cls client sending the message
1481  * @param sam message of type `struct AttributeStoreMessage`
1482  * @return #GNUNET_OK if @a im is well-formed
1483  */
1484 static int
1485 check_attribute_store_message(void *cls,
1486                               const struct AttributeStoreMessage *sam)
1487 {
1488   uint16_t size;
1489   uint32_t name_len;
1490
1491   size = ntohs (sam->header.size);
1492   if (size <= sizeof (struct AttributeStoreMessage))
1493   {
1494     GNUNET_break (0);
1495     return GNUNET_SYSERR;
1496   }
1497   name_len = ntohs (sam->name_len);
1498   if (0 <= name_len)
1499   {
1500     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1501                 "Malformed store message received!\n");
1502     GNUNET_break (0);
1503     return GNUNET_SYSERR;
1504   }
1505   return GNUNET_OK;
1506 }
1507
1508 /**
1509  *
1510  * Handler for store message
1511  *
1512  * @param cls unused
1513  * @param client who sent the message
1514  * @param message the message
1515  */
1516 static void
1517 handle_attribute_store_message (void *cls,
1518                                 const struct AttributeStoreMessage *sam)
1519 {
1520   struct AttributeStoreHandle *as_handle;
1521   struct GNUNET_SERVICE_Client *client = cls;
1522   size_t name_len;
1523   size_t data_len;
1524   char *attribute_value;
1525
1526   name_len = ntohs (sam->name_len);
1527   data_len = ntohs (sam->attr_value_len);
1528
1529   as_handle = GNUNET_new (struct AttributeStoreHandle);
1530   as_handle->name = GNUNET_strndup ((char*)&sam[1], name_len);
1531   attribute_value = (char*)&sam[1] + name_len;
1532
1533   as_handle->r_id = sam->id;
1534   as_handle->identity = sam->identity;
1535   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity,
1536                                       &as_handle->identity_pkey);
1537   as_handle->attribute_value = GNUNET_malloc (data_len);
1538   GNUNET_memcpy (as_handle->attribute_value,
1539                  attribute_value,
1540                  data_len);
1541   as_handle->attribute_value_len = data_len;
1542
1543   GNUNET_SERVICE_client_continue (client);
1544   as_handle->client = client;
1545   as_handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
1546                                                       &as_handle->identity,
1547                                                       "+",
1548                                                       &store_cont_abe_error,
1549                                                       as_handle,
1550                                                       &store_cont_abe_result,
1551                                                       as_handle);
1552 }
1553
1554
1555 /**
1556  * Main function that will be run
1557  *
1558  * @param cls closure
1559  * @param args remaining command-line arguments
1560  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1561  * @param c configuration
1562  */
1563 static void
1564 run (void *cls,
1565      const struct GNUNET_CONFIGURATION_Handle *c,
1566      struct GNUNET_SERVICE_Handle *server)
1567 {
1568   cfg = c;
1569
1570   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1571
1572   //Connect to identity and namestore services
1573   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1574   if (NULL == ns_handle)
1575   {
1576     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1577   }
1578
1579   gns_handle = GNUNET_GNS_connect (cfg);
1580   if (NULL == gns_handle)
1581   {
1582     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1583   }
1584   credential_handle = GNUNET_CREDENTIAL_connect (cfg);
1585   if (NULL == credential_handle)
1586   {
1587     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
1588   }
1589   identity_handle = GNUNET_IDENTITY_connect (cfg,
1590                                              NULL,
1591                                              NULL);
1592
1593   if (GNUNET_OK ==
1594       GNUNET_CONFIGURATION_get_value_time (cfg,
1595                                            "identity-provider",
1596                                            "TOKEN_EXPIRATION_INTERVAL",
1597                                            &token_expiration_interval))
1598   {
1599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1600                 "Time window for zone iteration: %s\n",
1601                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1602                                                         GNUNET_YES));
1603   } else {
1604     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1605   }
1606
1607   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1608 }
1609
1610 /**
1611  * Called whenever a client is disconnected.
1612  *
1613  * @param cls closure
1614  * @param client identification of the client
1615  * @param app_ctx @a client
1616  */
1617 static void
1618 client_disconnect_cb (void *cls,
1619                       struct GNUNET_SERVICE_Client *client,
1620                       void *app_ctx)
1621 {
1622   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1623               "Client %p disconnected\n",
1624               client);
1625 }
1626
1627
1628 /**
1629  * Add a client to our list of active clients.
1630  *
1631  * @param cls NULL
1632  * @param client client to add
1633  * @param mq message queue for @a client
1634  * @return internal namestore client structure for this client
1635  */
1636 static void *
1637 client_connect_cb (void *cls,
1638                    struct GNUNET_SERVICE_Client *client,
1639                    struct GNUNET_MQ_Handle *mq)
1640 {
1641   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1642               "Client %p connected\n",
1643               client);
1644   return client;
1645 }
1646
1647
1648
1649 /**
1650  * Define "main" method using service macro.
1651  */
1652 GNUNET_SERVICE_MAIN
1653 ("identity-provider",
1654  GNUNET_SERVICE_OPTION_NONE,
1655  &run,
1656  &client_connect_cb,
1657  &client_disconnect_cb,
1658  NULL,
1659  GNUNET_MQ_hd_var_size (issue_message,
1660                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE,
1661                         struct IssueMessage,
1662                         NULL),
1663  GNUNET_MQ_hd_var_size (exchange_message,
1664                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE,
1665                         struct ExchangeMessage,
1666                         NULL),
1667  GNUNET_MQ_hd_var_size (attribute_store_message,
1668                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE,
1669                         struct AttributeStoreMessage,
1670                         NULL),
1671  GNUNET_MQ_handler_end());
1672 /* end of gnunet-service-identity-provider.c */