Merge remote-tracking branch 'origin/master' into credentials
[oweals/gnunet.git] / src / credential / gnunet-service-credential.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011-2013 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  * @file gns/gnunet-service-credential.c
22  * @brief GNU Credential Service (main service)
23  * @author Adnan Husain 
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_credential_service.h"
28 #include "gnunet_statistics_service.h"
29 #include "credential.h"
30 #include "credential_serialization.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_signatures.h"
33
34 #include <gnunet_dnsparser_lib.h>
35 #include <gnunet_identity_service.h>
36 #include <gnunet_gnsrecord_lib.h>
37 #include <gnunet_namestore_service.h>
38 #include <gnunet_gns_service.h>
39
40
41 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
42
43 struct VerifyRequestHandle;
44
45 struct DelegationSetQueueEntry;
46
47
48 struct DelegationChainEntry
49 {
50   /**
51    * DLL
52    */
53   struct DelegationChainEntry *next;
54
55   /**
56    * DLL
57    */
58   struct DelegationChainEntry *prev;
59
60   /**
61    * The issuer
62    */
63   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
64   
65   /**
66    * The subject
67    */
68   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
69   
70   /**
71    * The issued attribute
72    */
73   char *issuer_attribute;
74   
75   /**
76    * The delegated attribute
77    */
78   char *subject_attribute;
79 };
80
81 /**
82  * DLL for record
83  */
84 struct CredentialRecordEntry
85 {
86   /**
87    * DLL
88    */
89   struct CredentialRecordEntry *next;
90
91   /**
92    * DLL
93    */
94   struct CredentialRecordEntry *prev;
95   
96   /**
97    * Number of references in delegation chains
98    */
99   uint32_t refcount;
100
101   /**
102    * Payload
103    */
104   struct GNUNET_CREDENTIAL_Credential *credential;
105 };
106
107 /**
108  * DLL used for delegations
109  * Used for OR delegations
110  */
111 struct DelegationQueueEntry
112 {
113   /**
114    * DLL
115    */
116   struct DelegationQueueEntry *next;
117
118   /**
119    * DLL
120    */
121   struct DelegationQueueEntry *prev;
122
123   /**
124    * Sets under this Queue
125    */
126   struct DelegationSetQueueEntry *set_entries_head;
127
128   /**
129    * Sets under this Queue
130    */
131   struct DelegationSetQueueEntry *set_entries_tail;
132
133   /**
134    * Parent set
135    */
136   struct DelegationSetQueueEntry *parent_set;
137
138   /**
139    * Required solutions
140    */
141   uint32_t required_solutions;
142 };
143
144 /**
145  * DLL for delegation sets
146  * Used for AND delegation set
147  */
148 struct DelegationSetQueueEntry
149 {
150   /**
151    * DLL
152    */
153   struct DelegationSetQueueEntry *next;
154
155   /**
156    * DLL
157    */
158   struct DelegationSetQueueEntry *prev;
159
160     /**
161    * GNS handle
162    */
163   struct GNUNET_GNS_LookupRequest *lookup_request;
164
165   /**
166    * Verify handle
167    */
168   struct VerifyRequestHandle *handle;
169
170   /**
171    * Parent attribute delegation
172    */
173   struct DelegationQueueEntry *parent;
174
175   /**
176    * Issuer key
177    */
178   struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
179
180   /**
181    * Queue entries of this set
182    */
183   struct DelegationQueueEntry *queue_entries_head;
184
185   /**
186    * Queue entries of this set
187    */
188   struct DelegationQueueEntry *queue_entries_tail;
189
190   /**
191    * Parent QueueEntry
192    */
193   struct DelegationQueueEntry *parent_queue_entry;
194
195   /**
196    * Issuer attribute delegated to
197    */
198   char *issuer_attribute;
199
200   /**
201    * The current attribute to look up
202    */
203   char *lookup_attribute;
204
205   /**
206    * Trailing attribute context
207    */
208   char *attr_trailer;
209
210   /**
211    * Still to resolve delegation as string
212    */
213   char *unresolved_attribute_delegation;
214
215   /**
216    * The delegation chain entry
217    */
218   struct DelegationChainEntry *delegation_chain_entry;
219
220 };
221
222
223 /**
224  * Handle to a lookup operation from api
225  */
226 struct VerifyRequestHandle
227 {
228
229   /**
230    * We keep these in a DLL.
231    */
232   struct VerifyRequestHandle *next;
233
234   /**
235    * We keep these in a DLL.
236    */
237   struct VerifyRequestHandle *prev;
238
239   /**
240    * Handle to the requesting client
241    */
242   struct GNUNET_SERVICE_Client *client;
243
244   /**
245    * GNS handle
246    */
247   struct GNUNET_GNS_LookupRequest *lookup_request;
248
249   /**
250    * Size of delegation tree
251    */
252   uint32_t delegation_chain_size;
253
254   /**
255    * Children of this attribute
256    */
257   struct DelegationChainEntry *delegation_chain_head;
258
259   /**
260    * Children of this attribute
261    */
262   struct DelegationChainEntry *delegation_chain_tail;
263
264   /**
265    * Issuer public key
266    */
267   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
268
269   /**
270    * Issuer attribute
271    */
272   char *issuer_attribute;
273
274   /**
275    * Subject public key
276    */
277   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
278
279   /**
280    * Credential DLL
281    */
282   struct CredentialRecordEntry *cred_chain_head;
283
284   /**
285    * Credential DLL
286    */
287   struct CredentialRecordEntry *cred_chain_tail;
288
289   /**
290    * Credential DLL size
291    */
292   uint32_t cred_chain_size;
293
294   /**
295    * Root Delegation Set
296    */
297   struct DelegationSetQueueEntry *root_set;
298
299   /**
300    * Current Delegation Pointer
301    */
302   struct DelegationQueueEntry *current_delegation;
303
304   /**
305    * request id
306    */
307   uint32_t request_id;
308
309   /**
310    * Pending lookups
311    */
312   uint64_t pending_lookups;
313
314   /**
315    * Credential iterator
316    */
317   struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
318
319   /**
320    * Collect task
321    */
322   struct GNUNET_SCHEDULER_Task *collect_next_task;
323
324 };
325
326
327 /**
328  * Head of the DLL.
329  */
330 static struct VerifyRequestHandle *vrh_head;
331
332 /**
333  * Tail of the DLL.
334  */
335 static struct VerifyRequestHandle *vrh_tail;
336
337 /**
338  * Handle to the statistics service
339  */
340 static struct GNUNET_STATISTICS_Handle *statistics;
341
342 /**
343  * Handle to GNS service.
344  */
345 static struct GNUNET_GNS_Handle *gns;
346
347
348 /**
349  * Handle to namestore service
350  */
351 static struct GNUNET_NAMESTORE_Handle *namestore;
352
353 static void
354 cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
355 {
356   struct DelegationQueueEntry *dq_entry;
357   struct DelegationSetQueueEntry *child;
358
359   if (NULL == ds_entry)
360     return;
361
362   for (dq_entry = ds_entry->queue_entries_head;
363        NULL != dq_entry;
364        dq_entry = ds_entry->queue_entries_head)
365   {
366     GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
367                                  ds_entry->queue_entries_tail,
368                                  dq_entry);
369     for (child = dq_entry->set_entries_head;
370          NULL != child;
371          child = dq_entry->set_entries_head)
372     {
373       GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
374                                    dq_entry->set_entries_tail,
375                                    child);
376       cleanup_delegation_set (child);
377     }
378     GNUNET_free (dq_entry);
379   }
380   if (NULL != ds_entry->issuer_key)
381     GNUNET_free (ds_entry->issuer_key);
382   if (NULL != ds_entry->lookup_attribute)
383     GNUNET_free (ds_entry->lookup_attribute);
384   if (NULL != ds_entry->issuer_attribute)
385     GNUNET_free (ds_entry->issuer_attribute);
386   if (NULL != ds_entry->unresolved_attribute_delegation)
387     GNUNET_free (ds_entry->unresolved_attribute_delegation);
388   if (NULL != ds_entry->attr_trailer)
389     GNUNET_free (ds_entry->attr_trailer);
390   if (NULL != ds_entry->lookup_request)
391   {
392     GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
393     ds_entry->lookup_request = NULL;
394   }
395   if (NULL != ds_entry->delegation_chain_entry)
396   {
397     if (NULL != ds_entry->delegation_chain_entry->subject_attribute)
398       GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute);
399     if (NULL != ds_entry->delegation_chain_entry->issuer_attribute)
400       GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
401     GNUNET_free (ds_entry->delegation_chain_entry);
402   }
403   GNUNET_free (ds_entry);
404 }
405
406 static void
407 cleanup_handle (struct VerifyRequestHandle *vrh)
408 {
409   struct CredentialRecordEntry *cr_entry;
410   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411               "Cleaning up...\n");
412   if (NULL != vrh->lookup_request)
413   {
414     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
415     vrh->lookup_request = NULL;
416   }
417   cleanup_delegation_set (vrh->root_set);
418   if (NULL != vrh->issuer_attribute)
419     GNUNET_free (vrh->issuer_attribute);
420   for (cr_entry = vrh->cred_chain_head; 
421        NULL != vrh->cred_chain_head;
422        cr_entry = vrh->cred_chain_head)
423   {
424     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
425                                  vrh->cred_chain_tail,
426                                  cr_entry);
427     if (NULL != cr_entry->credential);
428       GNUNET_free (cr_entry->credential);
429     GNUNET_free (cr_entry);
430   }
431   GNUNET_free (vrh);
432 }
433
434 /**
435  * Task run during shutdown.
436  *
437  * @param cls unused
438  * @param tc unused
439  */
440 static void
441 shutdown_task (void *cls)
442 {
443   struct VerifyRequestHandle *vrh;
444
445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446               "Shutting down!\n");
447
448   while (NULL != (vrh = vrh_head))
449   {
450     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
451     GNUNET_CONTAINER_DLL_remove (vrh_head,
452                                  vrh_tail,
453                                  vrh);
454     cleanup_handle (vrh);
455   }
456
457   if (NULL != gns)
458   {
459     GNUNET_GNS_disconnect (gns);
460     gns = NULL;
461   }
462   if (NULL != namestore)
463   {
464     GNUNET_NAMESTORE_disconnect (namestore);
465     namestore = NULL;
466   }
467   if (NULL != statistics)
468   {
469     GNUNET_STATISTICS_destroy (statistics,
470                                GNUNET_NO);
471     statistics = NULL;
472   }
473
474 }
475
476
477
478 /**
479  * Send.
480  *
481  * @param handle the handle to the request
482  */
483 static void
484 send_lookup_response (struct VerifyRequestHandle *vrh)
485 {
486   struct GNUNET_MQ_Envelope *env;
487   struct DelegationChainResultMessage *rmsg;
488   struct DelegationChainEntry *dce;
489   struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
490   struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
491   struct CredentialRecordEntry *cd;
492   struct CredentialRecordEntry *tmp;
493   size_t size;
494   int i;
495
496   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497               "Sending response\n");
498   dce = vrh->delegation_chain_head;
499   for (i=0;i<vrh->delegation_chain_size;i++)
500   {
501     dd[i].issuer_key = dce->issuer_key;
502     dd[i].subject_key = dce->subject_key;
503     dd[i].issuer_attribute = dce->issuer_attribute;
504     dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
505     dd[i].subject_attribute_len = 0;
506     dd[i].subject_attribute = NULL;
507     if (NULL != dce->subject_attribute)
508     {
509       dd[i].subject_attribute = dce->subject_attribute;
510       dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
511     }
512     dce = dce->next;
513   }
514
515   /**
516    * Remove all credentials not needed
517    */
518   for (cd = vrh->cred_chain_head; NULL != cd;)
519   {
520     if (cd->refcount > 0)
521     {
522       cd = cd->next;
523       continue;
524     }
525     tmp = cd;
526     cd = cd->next;
527     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
528                                  vrh->cred_chain_tail,
529                                  tmp);
530     GNUNET_free (tmp->credential);
531     GNUNET_free (tmp);
532     vrh->cred_chain_size--;
533   }
534
535   /**
536    * Get serialized record data
537    * Append at the end of rmsg
538    */
539   cd = vrh->cred_chain_head;
540   for (i=0;i<vrh->cred_chain_size;i++)
541   {
542     cred[i].issuer_key = cd->credential->issuer_key;
543     cred[i].subject_key = cd->credential->subject_key;
544     cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
545     cred[i].issuer_attribute = cd->credential->issuer_attribute;
546     cred[i].expiration = cd->credential->expiration;
547     cred[i].signature = cd->credential->signature;
548     cd = cd->next;
549   }
550   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
551                                                       dd,
552                                                       vrh->cred_chain_size,
553                                                       cred);
554   env = GNUNET_MQ_msg_extra (rmsg,
555                              size,
556                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
557   //Assign id so that client can find associated request
558   rmsg->id = vrh->request_id;
559   rmsg->d_count = htonl (vrh->delegation_chain_size);
560   rmsg->c_count = htonl (vrh->cred_chain_size);
561
562   if (0 < vrh->cred_chain_size)
563     rmsg->cred_found = htonl (GNUNET_YES);
564   else
565     rmsg->cred_found = htonl (GNUNET_NO);
566
567   GNUNET_assert (-1 != 
568                  GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
569                                                                dd,
570                                                                vrh->cred_chain_size,
571                                                                cred,
572                                                                size,
573                                                                (char*)&rmsg[1]));
574
575   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
576                   env);
577   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
578   cleanup_handle(vrh);
579
580   GNUNET_STATISTICS_update (statistics,
581                             "Completed verifications", 1,
582                             GNUNET_NO);
583 }
584
585
586 static void
587 backward_resolution (void* cls,
588                      uint32_t rd_count,
589                      const struct GNUNET_GNSRECORD_Data *rd)
590 {
591
592   struct VerifyRequestHandle *vrh;
593   const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
594   struct CredentialRecordEntry *cred_pointer;
595   struct DelegationSetQueueEntry *current_set;
596   struct DelegationSetQueueEntry *ds_entry;
597   struct DelegationSetQueueEntry *tmp_set;
598   struct DelegationQueueEntry *dq_entry;
599   char *expanded_attr;
600   char *lookup_attribute;
601   int i;
602   int j;
603
604
605   current_set = cls;
606   current_set->lookup_request = NULL;
607   vrh = current_set->handle;
608   vrh->pending_lookups--;
609   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610               "Got %d attrs\n", rd_count);
611
612   // Each OR
613   for (i=0; i < rd_count; i++) 
614   {
615     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
616       continue;
617
618     sets = rd[i].data;
619     struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
620     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
621                 "Found new attribute delegation with %d sets. Creating new Job...\n",
622                 ntohl (sets->set_count));
623
624     if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
625                                                                   (const char*)&sets[1],
626                                                                   ntohl(sets->set_count),
627                                                                   set))
628     {
629       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630                   "Failed to deserialize!\n");
631       continue;
632     }
633     dq_entry = GNUNET_new (struct DelegationQueueEntry);
634     dq_entry->required_solutions = ntohl(sets->set_count);
635     dq_entry->parent_set = current_set;
636     GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
637                                  current_set->queue_entries_tail,
638                                  dq_entry);
639     // Each AND
640     for (j=0; j<ntohl(sets->set_count); j++)
641     {
642       ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
643       if (NULL != current_set->attr_trailer)
644       {
645         if (0 == set[j].subject_attribute_len)
646         {
647           GNUNET_asprintf (&expanded_attr,
648                            "%s",
649                            current_set->attr_trailer);
650
651         } else {
652           GNUNET_asprintf (&expanded_attr,
653                            "%s.%s",
654                            set[j].subject_attribute,
655                            current_set->attr_trailer);
656         }
657         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658                     "Expanded to %s\n", expanded_attr);
659         ds_entry->unresolved_attribute_delegation = expanded_attr;
660       } else {
661         if (0 != set[j].subject_attribute_len)
662         {
663           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664                       "Not Expanding %s\n", set[j].subject_attribute);
665           ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
666         }
667       }
668
669       //Add a credential chain entry
670       ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
671       ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
672       ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
673       GNUNET_memcpy (ds_entry->issuer_key,
674                      &set[j].subject_key,
675                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
676       if (0 < set[j].subject_attribute_len)
677         ds_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup (set[j].subject_attribute);
678       ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
679       ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
680
681       ds_entry->parent_queue_entry = dq_entry; //current_delegation;
682       GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
683                                    dq_entry->set_entries_tail,
684                                    ds_entry);
685
686       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687                   "Checking for cred match\n");
688       /**
689        * Check if this delegation already matches one of our credentials
690        */
691       for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
692           cred_pointer = cred_pointer->next)
693       {
694         if(0 != memcmp (&set->subject_key, 
695                         &cred_pointer->credential->issuer_key,
696                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
697           continue;
698         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699                     "Checking if %s matches %s\n",
700                     ds_entry->unresolved_attribute_delegation,
701                     cred_pointer->credential->issuer_attribute);
702
703         if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
704                          cred_pointer->credential->issuer_attribute))
705           continue;
706
707         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708                     "Found issuer\n");
709         cred_pointer->refcount++;
710         //Backtrack
711         for (tmp_set = ds_entry;
712              NULL != tmp_set->parent_queue_entry;
713              tmp_set = tmp_set->parent_queue_entry->parent_set)
714         {
715           tmp_set->parent_queue_entry->required_solutions--;
716           if (NULL != tmp_set->delegation_chain_entry)
717           {
718             vrh->delegation_chain_size++;
719             GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
720                                          vrh->delegation_chain_tail,
721                                          tmp_set->delegation_chain_entry);
722           }
723           if (0 < tmp_set->parent_queue_entry->required_solutions)
724             break;
725         }
726
727         if (NULL == tmp_set->parent_queue_entry)
728         {
729           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730                       "All solutions found\n");
731           //Found match
732           send_lookup_response (vrh);
733           return;
734         }
735         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736                     "Not all solutions found yet.\n");
737         continue;
738
739       }
740       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741                   "Building new lookup request from %s\n",
742                   ds_entry->unresolved_attribute_delegation);
743       //Continue with backward resolution
744       char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
745       strcpy (issuer_attribute_name,
746               ds_entry->unresolved_attribute_delegation);
747       char *next_attr = strtok (issuer_attribute_name, ".");
748       GNUNET_asprintf (&lookup_attribute,
749                        "%s.gnu",
750                        next_attr);
751       GNUNET_asprintf (&ds_entry->lookup_attribute,
752                        "%s",
753                        next_attr);
754       if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
755       {
756         ds_entry->attr_trailer = NULL;
757       } else {
758         next_attr += strlen (next_attr) + 1;
759         ds_entry->attr_trailer = GNUNET_strdup (next_attr);
760       }
761
762       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763                   "Looking up %s\n", ds_entry->lookup_attribute);
764       if (NULL != ds_entry->attr_trailer)
765         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
766                     "%s still to go...\n", ds_entry->attr_trailer);
767
768       vrh->pending_lookups++;
769       ds_entry->handle = vrh;
770       ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
771                                                     lookup_attribute,
772                                                     ds_entry->issuer_key, //issuer_key,
773                                                     GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
774                                                     GNUNET_GNS_LO_DEFAULT,
775                                                     &backward_resolution,
776                                                     ds_entry);
777       GNUNET_free (lookup_attribute);
778     }
779   }
780
781   if(0 == vrh->pending_lookups)
782   {
783     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
784                 "We are all out of attributes...\n");
785     send_lookup_response (vrh);
786     return;
787
788   }
789
790
791
792 /**
793  * Result from GNS lookup.
794  *
795  * @param cls the closure (our client lookup handle)
796  * @param rd_count the number of records in @a rd
797  * @param rd the record data
798  */
799 static void
800 delegation_chain_resolution_start (void* cls)
801 {
802   struct VerifyRequestHandle *vrh = cls;
803   struct DelegationSetQueueEntry *ds_entry;
804   struct CredentialRecordEntry *cr_entry;
805   vrh->lookup_request = NULL;
806
807   if (0 == vrh->cred_chain_size)
808   {
809     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
810                 "No credentials found\n");
811     send_lookup_response (vrh);
812     return;
813   }
814
815   for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next)
816   {
817     if (0 != memcmp (&cr_entry->credential->issuer_key,
818                      &vrh->issuer_key,
819                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
820       continue;
821     if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute))
822       continue;
823     cr_entry->refcount++;
824     //Found match prematurely
825     send_lookup_response (vrh);
826     return;
827
828   }
829
830   /**
831    * Check for attributes from the issuer and follow the chain 
832    * till you get the required subject's attributes
833    */
834   char issuer_attribute_name[strlen (vrh->issuer_attribute)];
835   strcpy (issuer_attribute_name,
836           vrh->issuer_attribute);
837   strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
838           ".gnu");
839   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840               "Looking up %s\n", issuer_attribute_name);
841   ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
842   ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
843   memcpy (ds_entry->issuer_key,
844           &vrh->issuer_key,
845           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
846   ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
847   ds_entry->handle = vrh;
848   ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
849   vrh->root_set = ds_entry;
850   vrh->pending_lookups = 1;
851   //Start with backward resolution
852   ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
853                                                 issuer_attribute_name,
854                                                 &vrh->issuer_key, //issuer_key,
855                                                 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
856                                                 GNUNET_GNS_LO_DEFAULT,
857                                                 &backward_resolution,
858                                                 ds_entry);
859 }
860
861 /**
862  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
863  *
864  * @param cls client sending the message
865  * @param v_msg message of type `struct VerifyMessage`
866  * @return #GNUNET_OK if @a v_msg is well-formed
867  */
868 static int
869 check_verify (void *cls,
870               const struct VerifyMessage *v_msg)
871 {
872   size_t msg_size;
873   const char* attr;
874
875   msg_size = ntohs (v_msg->header.size);
876   if (msg_size < sizeof (struct VerifyMessage))
877   {
878     GNUNET_break (0);
879     return GNUNET_SYSERR;
880   }
881   if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
882   {
883     GNUNET_break (0);
884     return GNUNET_SYSERR;
885   }
886   attr = (const char *) &v_msg[1];
887
888   if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
889   {
890     GNUNET_break (0);
891     return GNUNET_SYSERR;
892   }
893   return GNUNET_OK;
894 }
895
896 /**
897  * Handle Credential verification requests from client
898  *
899  * @param cls the closure
900  * @param client the client
901  * @param message the message
902  */
903 static void
904 handle_verify (void *cls,
905                const struct VerifyMessage *v_msg) 
906 {
907   struct VerifyRequestHandle *vrh;
908   struct GNUNET_SERVICE_Client *client = cls;
909   struct CredentialRecordEntry *cr_entry;
910   uint32_t credentials_count;
911   uint32_t credential_data_size;
912   int i;
913   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
914   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
915   char *attrptr = attr;
916   char *credential_data;
917   const char *utf_in;
918
919   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920               "Received VERIFY message\n");
921   utf_in = (const char *) &v_msg[1];
922   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
923   GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
924   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
925   vrh = GNUNET_new (struct VerifyRequestHandle);
926   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
927   vrh->client = client;
928   vrh->request_id = v_msg->id;
929   vrh->issuer_key = v_msg->issuer_key;
930   vrh->subject_key = v_msg->subject_key;
931   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
932   if (NULL == issuer_attribute)
933   {
934     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
935                 "No issuer attribute provided!\n");
936     send_lookup_response (vrh);
937     return;
938   }
939   /**
940    * First, collect credentials
941    * TODO: cleanup!
942    */
943   credentials_count = ntohl(v_msg->c_count);
944   credential_data_size = ntohs (v_msg->header.size) 
945     - sizeof (struct VerifyMessage)
946     - ntohs (v_msg->issuer_attribute_len)
947     - 1;
948   struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
949   credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
950   if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
951                                                               credential_data,
952                                                               credentials_count,
953                                                               credentials))
954   {
955     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
956                 "Cannot deserialize credentials!\n");
957     send_lookup_response (vrh);
958     return;
959   }
960
961   for (i=0;i<credentials_count;i++) {
962     cr_entry = GNUNET_new (struct CredentialRecordEntry);
963     cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
964                                           credentials[i].issuer_attribute_len);
965     GNUNET_memcpy (cr_entry->credential,
966                    &credentials[i],
967                    sizeof (struct GNUNET_CREDENTIAL_Credential));
968     GNUNET_memcpy (&cr_entry->credential[1],
969                    credentials[i].issuer_attribute,
970                    credentials[i].issuer_attribute_len);
971     cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
972     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
973                                       vrh->cred_chain_tail,
974                                       cr_entry);
975     vrh->cred_chain_size++;
976   }
977
978   delegation_chain_resolution_start (vrh);
979
980 }
981
982 /**
983  * We encountered an error while collecting
984  */
985 static void
986 handle_cred_collection_error_cb (void *cls)
987 {
988   struct VerifyRequestHandle *vrh = cls;
989   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990               "Got disconnected from namestore database.\n");
991   vrh->cred_collection_iter = NULL;
992   send_lookup_response (vrh);
993 }
994
995 static void
996 collect_next (void *cls)
997 {
998   struct VerifyRequestHandle *vrh = cls;
999   vrh->collect_next_task = NULL;
1000   GNUNET_assert (NULL != vrh->cred_collection_iter);
1001   GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
1002 }
1003
1004 /**
1005  * Store credential
1006  */
1007 static void
1008 handle_cred_collection_cb (void *cls,
1009                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
1010                            const char *label,
1011                            unsigned int rd_count,
1012                            const struct GNUNET_GNSRECORD_Data *rd)
1013 {
1014   struct VerifyRequestHandle *vrh = cls;
1015   struct GNUNET_CREDENTIAL_Credential *crd;
1016   struct CredentialRecordEntry *cr_entry;
1017   int cred_record_count;
1018   int i;
1019
1020   cred_record_count = 0;
1021   for (i=0; i < rd_count; i++)
1022   {
1023     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
1024       continue;
1025     cred_record_count++;
1026     crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
1027                                                     rd[i].data_size);
1028     if (NULL == crd)
1029     {
1030       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1031                   "Invalid credential found\n");
1032       continue;
1033     }
1034     cr_entry = GNUNET_new (struct CredentialRecordEntry);
1035     cr_entry->credential = crd;
1036     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
1037                                       vrh->cred_chain_tail,
1038                                       cr_entry);
1039     vrh->cred_chain_size++;
1040   }
1041   vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
1042                                                      vrh);
1043 }
1044
1045 /**
1046  * We encountered an error while collecting
1047  */
1048 static void
1049 handle_cred_collection_finished_cb (void *cls)
1050 {
1051   struct VerifyRequestHandle *vrh = cls;
1052   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053               "Done collecting credentials.\n");
1054   vrh->cred_collection_iter = NULL;
1055   delegation_chain_resolution_start (vrh);
1056 }
1057
1058 /**
1059  * Handle Credential collection requests from client
1060  *
1061  * @param cls the closure
1062  * @param client the client
1063  * @param message the message
1064  */
1065 static void
1066 handle_collect (void *cls,
1067                 const struct CollectMessage *c_msg) 
1068 {
1069   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1070   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1071   struct VerifyRequestHandle *vrh;
1072   struct GNUNET_SERVICE_Client *client = cls;
1073   char *attrptr = attr;
1074   const char *utf_in;
1075
1076   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077               "Received COLLECT message\n");
1078
1079   utf_in = (const char *) &c_msg[1];
1080   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
1081
1082   GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
1083   issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
1084   vrh = GNUNET_new (struct VerifyRequestHandle);
1085   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
1086   vrh->client = client;
1087   vrh->request_id = c_msg->id;
1088   vrh->issuer_key = c_msg->issuer_key;
1089   GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
1090                                       &vrh->subject_key);
1091   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
1092
1093   if (NULL == issuer_attribute)
1094   {
1095     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1096                 "No issuer attribute provided!\n");
1097     send_lookup_response (vrh);
1098     return;
1099   }
1100   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101               "Getting credentials for subject\n");
1102   /**
1103    * First, get attribute from subject
1104    */
1105   vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
1106                                                                      &c_msg->subject_key,
1107                                                                      &handle_cred_collection_error_cb,
1108                                                                      vrh,
1109                                                                      &handle_cred_collection_cb,
1110                                                                      vrh,
1111                                                                      &handle_cred_collection_finished_cb,
1112                                                                      vrh);
1113 }
1114
1115
1116 /**
1117  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT message
1118  *
1119  * @param cls client sending the message
1120  * @param v_msg message of type `struct CollectMessage`
1121  * @return #GNUNET_OK if @a v_msg is well-formed
1122  */
1123 static int
1124 check_collect (void *cls,
1125                const struct CollectMessage *c_msg)
1126 {
1127   size_t msg_size;
1128   const char* attr;
1129
1130   msg_size = ntohs (c_msg->header.size);
1131   if (msg_size < sizeof (struct CollectMessage))
1132   {
1133     GNUNET_break (0);
1134     return GNUNET_SYSERR;
1135   }
1136   if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
1137   {
1138     GNUNET_break (0);
1139     return GNUNET_SYSERR;
1140   }
1141   attr = (const char *) &c_msg[1];
1142
1143   if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
1144        (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
1145   {
1146     GNUNET_break (0);
1147     return GNUNET_SYSERR;
1148   }
1149   return GNUNET_OK;
1150 }
1151
1152 /**
1153  * One of our clients disconnected, clean up after it.
1154  *
1155  * @param cls NULL
1156  * @param client the client that disconnected
1157  */
1158 static void
1159 client_disconnect_cb (void *cls,
1160                       struct GNUNET_SERVICE_Client *client,
1161                       void *app_ctx)
1162 {
1163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164               "Client %p disconnected\n",
1165               client);
1166 }
1167
1168 /**
1169  * Add a client to our list of active clients.
1170  *
1171  * @param cls NULL
1172  * @param client client to add
1173  * @param mq message queue for @a client
1174  * @return this client
1175  */
1176 static void *
1177 client_connect_cb (void *cls,
1178                    struct GNUNET_SERVICE_Client *client,
1179                    struct GNUNET_MQ_Handle *mq)
1180 {
1181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1182               "Client %p connected\n",
1183               client);
1184   return client;
1185 }
1186
1187 /**
1188  * Process Credential requests.
1189  *
1190  * @param cls closure
1191  * @param server the initialized server
1192  * @param c configuration to use
1193  */
1194 static void
1195 run (void *cls,
1196      const struct GNUNET_CONFIGURATION_Handle *c,
1197      struct GNUNET_SERVICE_Handle *handle)
1198 {
1199
1200   gns = GNUNET_GNS_connect (c);
1201   if (NULL == gns)
1202   {
1203     fprintf (stderr,
1204              _("Failed to connect to GNS\n"));
1205   }
1206   namestore = GNUNET_NAMESTORE_connect (c);
1207   if (NULL == namestore)
1208   {
1209     fprintf (stderr,
1210              _("Failed to connect to namestore\n"));
1211   }
1212
1213   statistics = GNUNET_STATISTICS_create ("credential", c);
1214   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1215 }
1216
1217
1218 /**
1219  * Define "main" method using service macro
1220  */
1221 GNUNET_SERVICE_MAIN
1222 ("credential",
1223  GNUNET_SERVICE_OPTION_NONE,
1224  &run,
1225  &client_connect_cb,
1226  &client_disconnect_cb,
1227  NULL,
1228  GNUNET_MQ_hd_var_size (verify,
1229                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1230                         struct VerifyMessage,
1231                         NULL),
1232  GNUNET_MQ_hd_var_size (collect,
1233                         GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
1234                         struct CollectMessage,
1235                         NULL),
1236  GNUNET_MQ_handler_end());
1237
1238 /* end of gnunet-service-credential.c */