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