55907e0d79946ee750bfd585663c1d9bbb817b35
[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 // For Looking up GNS request
35 #include <gnunet_dnsparser_lib.h>
36 #include <gnunet_identity_service.h>
37 #include <gnunet_gnsrecord_lib.h>
38 #include <gnunet_namestore_service.h>
39 #include <gnunet_gns_service.h>
40 #include "gnunet_gns_service.h"
41
42
43
44
45 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
46
47 struct VerifyRequestHandle;
48
49 struct DelegationSetQueueEntry;
50
51
52 struct DelegationChainEntry
53 {
54   /**
55    * DLL
56    */
57   struct DelegationChainEntry *next;
58
59   /**
60    * DLL
61    */
62   struct DelegationChainEntry *prev;
63
64   /**
65    * The issuer
66    */
67   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
68   
69   /**
70    * The subject
71    */
72   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
73   
74   /**
75    * The issued attribute
76    */
77   char *issuer_attribute;
78   
79   /**
80    * The delegated attribute
81    */
82   char *subject_attribute;
83 };
84
85 /**
86  * DLL for record
87  */
88 struct CredentialRecordEntry
89 {
90   /**
91    * DLL
92    */
93   struct CredentialRecordEntry *next;
94
95   /**
96    * DLL
97    */
98   struct CredentialRecordEntry *prev;
99
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
316
317 /**
318  * Head of the DLL.
319  */
320 static struct VerifyRequestHandle *vrh_head;
321
322 /**
323  * Tail of the DLL.
324  */
325 static struct VerifyRequestHandle *vrh_tail;
326
327 /**
328  * Handle to the statistics service
329  */
330 static struct GNUNET_STATISTICS_Handle *statistics;
331
332 /**
333  * Handle to GNS service.
334  */
335 static struct GNUNET_GNS_Handle *gns;
336
337
338 static void
339 cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
340 {
341   struct DelegationQueueEntry *dq_entry;
342   struct DelegationSetQueueEntry *child;
343
344   if (NULL == ds_entry)
345     return;
346
347   for (dq_entry = ds_entry->queue_entries_head;
348        NULL != dq_entry;
349        dq_entry = ds_entry->queue_entries_head)
350   {
351     GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
352                                  ds_entry->queue_entries_tail,
353                                  dq_entry);
354     for (child = dq_entry->set_entries_head;
355          NULL != child;
356          child = dq_entry->set_entries_head)
357     {
358       GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
359                                    dq_entry->set_entries_tail,
360                                    child);
361       cleanup_delegation_set (child);
362     }
363     GNUNET_free (dq_entry);
364   }
365   if (NULL != ds_entry->issuer_key)
366     GNUNET_free (ds_entry->issuer_key);
367   if (NULL != ds_entry->lookup_attribute)
368     GNUNET_free (ds_entry->lookup_attribute);
369   if (NULL != ds_entry->issuer_attribute)
370     GNUNET_free (ds_entry->issuer_attribute);
371   if (NULL != ds_entry->unresolved_attribute_delegation)
372     GNUNET_free (ds_entry->unresolved_attribute_delegation);
373   if (NULL != ds_entry->attr_trailer)
374     GNUNET_free (ds_entry->attr_trailer);
375   if (NULL != ds_entry->lookup_request)
376   {
377     GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
378     ds_entry->lookup_request = NULL;
379   }
380   if (NULL != ds_entry->delegation_chain_entry)
381   {
382     if (NULL != ds_entry->delegation_chain_entry->subject_attribute)
383       GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute);
384     if (NULL != ds_entry->delegation_chain_entry->issuer_attribute)
385       GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
386     GNUNET_free (ds_entry->delegation_chain_entry);
387   }
388   GNUNET_free (ds_entry);
389 }
390
391 static void
392 cleanup_handle (struct VerifyRequestHandle *vrh)
393 {
394   struct CredentialRecordEntry *cr_entry;
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396               "Cleaning up...\n");
397   if (NULL != vrh->lookup_request)
398   {
399     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
400     vrh->lookup_request = NULL;
401   }
402   cleanup_delegation_set (vrh->root_set);
403   if (NULL != vrh->issuer_attribute)
404     GNUNET_free (vrh->issuer_attribute);
405   for (cr_entry = vrh->cred_chain_head; 
406        NULL != vrh->cred_chain_head;
407        cr_entry = vrh->cred_chain_head)
408   {
409     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
410                                  vrh->cred_chain_tail,
411                                  cr_entry);
412     if (NULL != cr_entry->credential);
413       GNUNET_free (cr_entry->credential);
414     GNUNET_free (cr_entry);
415   }
416   GNUNET_free (vrh);
417 }
418
419 /**
420  * Task run during shutdown.
421  *
422  * @param cls unused
423  * @param tc unused
424  */
425 static void
426 shutdown_task (void *cls)
427 {
428   struct VerifyRequestHandle *vrh;
429
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431               "Shutting down!\n");
432
433   while (NULL != (vrh = vrh_head))
434   {
435     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
436     GNUNET_CONTAINER_DLL_remove (vrh_head,
437                                  vrh_tail,
438                                  vrh);
439     cleanup_handle (vrh);
440   }
441
442   if (NULL != gns)
443   {
444     GNUNET_GNS_disconnect (gns);
445     gns = NULL;
446   }
447   if (NULL != statistics)
448   {
449     GNUNET_STATISTICS_destroy (statistics,
450                                GNUNET_NO);
451     statistics = NULL;
452   }
453
454 }
455
456 /**
457  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
458  *
459  * @param cls client sending the message
460  * @param v_msg message of type `struct VerifyMessage`
461  * @return #GNUNET_OK if @a v_msg is well-formed
462  */
463 static int
464 check_verify (void *cls,
465               const struct VerifyMessage *v_msg)
466 {
467   size_t msg_size;
468   const char* attrs;
469
470   msg_size = ntohs (v_msg->header.size);
471   if (msg_size < sizeof (struct VerifyMessage))
472   {
473     GNUNET_break (0);
474     return GNUNET_SYSERR;
475   }
476   if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
477       (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
478   {
479     GNUNET_break (0);
480     return GNUNET_SYSERR;
481   }
482   attrs = (const char *) &v_msg[1];
483
484   if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
485        (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
486   {
487     GNUNET_break (0);
488     return GNUNET_SYSERR;
489   }
490   return GNUNET_OK;
491 }
492
493 /**
494  * Send.
495  *
496  * @param handle the handle to the request
497  */
498 static void
499 send_lookup_response (struct VerifyRequestHandle *vrh)
500 {
501   struct GNUNET_MQ_Envelope *env;
502   struct VerifyResultMessage *rmsg;
503   struct DelegationChainEntry *dce;
504   struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
505   struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
506   struct CredentialRecordEntry *cd;
507   size_t size;
508   int i;
509
510   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511               "Sending response\n");
512   dce = vrh->delegation_chain_head;
513   for (i=0;i<vrh->delegation_chain_size;i++)
514   {
515     dd[i].issuer_key = dce->issuer_key;
516     dd[i].subject_key = dce->subject_key;
517     dd[i].issuer_attribute = dce->issuer_attribute;
518     dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
519     dd[i].subject_attribute_len = 0;
520     dd[i].subject_attribute = NULL;
521     if (NULL != dce->subject_attribute)
522     {
523       dd[i].subject_attribute = dce->subject_attribute;
524       dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
525     }
526     dce = dce->next;
527   }
528
529   /**
530    * Get serialized record data
531    * Append at the end of rmsg
532    */
533   cd = vrh->cred_chain_head;
534   for (i=0;i<vrh->cred_chain_size;i++)
535   {
536     cred[i].issuer_key = cd->credential->issuer_key;
537     cred[i].subject_key = cd->credential->subject_key;
538     cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
539     cred[i].issuer_attribute = cd->credential->issuer_attribute;
540     cred[i].expiration = cd->credential->expiration;
541     cred[i].signature = cd->credential->signature;
542     cd = cd->next;
543   }
544   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
545                                                       dd,
546                                                       vrh->cred_chain_size,
547                                                       cred);
548   env = GNUNET_MQ_msg_extra (rmsg,
549                              size,
550                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
551   //Assign id so that client can find associated request
552   rmsg->id = vrh->request_id;
553   rmsg->d_count = htonl (vrh->delegation_chain_size);
554   rmsg->c_count = htonl (vrh->cred_chain_size);
555
556   if (0 < vrh->cred_chain_size)
557     rmsg->cred_found = htonl (GNUNET_YES);
558   else
559     rmsg->cred_found = htonl (GNUNET_NO);
560
561   GNUNET_assert (-1 != 
562                  GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
563                                                                dd,
564                                                                vrh->cred_chain_size,
565                                                                cred,
566                                                                size,
567                                                                (char*)&rmsg[1]));
568
569   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
570                   env);
571   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
572   cleanup_handle(vrh);
573
574   GNUNET_STATISTICS_update (statistics,
575                             "Completed verifications", 1,
576                             GNUNET_NO);
577 }
578
579
580 static void
581 backward_resolution (void* cls,
582                      uint32_t rd_count,
583                      const struct GNUNET_GNSRECORD_Data *rd)
584 {
585
586   struct VerifyRequestHandle *vrh;
587   const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
588   struct CredentialRecordEntry *cred_pointer;
589   struct DelegationSetQueueEntry *current_set;
590   struct DelegationSetQueueEntry *ds_entry;
591   struct DelegationSetQueueEntry *tmp_set;
592   struct DelegationQueueEntry *dq_entry;
593   char *expanded_attr;
594   char *lookup_attribute;
595   int i;
596   int j;
597
598
599   current_set = cls;
600   current_set->lookup_request = NULL;
601   vrh = current_set->handle;
602   vrh->pending_lookups--;
603   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604               "Got %d attrs\n", rd_count);
605
606   // Each OR
607   for (i=0; i < rd_count; i++) 
608   {
609     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
610       continue;
611
612     sets = rd[i].data;
613     struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
614     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615                 "Found new attribute delegation with %d sets. Creating new Job...\n",
616                 ntohl (sets->set_count));
617
618     if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
619                                                                   (const char*)&sets[1],
620                                                                   ntohl(sets->set_count),
621                                                                   set))
622     {
623       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
624                   "Failed to deserialize!\n");
625       continue;
626     }
627     dq_entry = GNUNET_new (struct DelegationQueueEntry);
628     dq_entry->required_solutions = ntohl(sets->set_count);
629     dq_entry->parent_set = current_set;
630     GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
631                                  current_set->queue_entries_tail,
632                                  dq_entry);
633     // Each AND
634     for (j=0; j<ntohl(sets->set_count); j++)
635     {
636       ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
637       if (NULL != current_set->attr_trailer)
638       {
639         if (0 == set[j].subject_attribute_len)
640         {
641           GNUNET_asprintf (&expanded_attr,
642                            "%s",
643                            current_set->attr_trailer);
644
645         } else {
646           GNUNET_asprintf (&expanded_attr,
647                            "%s.%s",
648                            set[j].subject_attribute,
649                            current_set->attr_trailer);
650         }
651         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652                     "Expanded to %s\n", expanded_attr);
653         ds_entry->unresolved_attribute_delegation = expanded_attr;
654       } else {
655         if (0 != set[j].subject_attribute_len)
656         {
657           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658                       "Not Expanding %s\n", set[j].subject_attribute);
659           ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
660         }
661       }
662
663       //Add a credential chain entry
664       ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
665       ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
666       ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
667       GNUNET_memcpy (ds_entry->issuer_key,
668                      &set[j].subject_key,
669                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
670       if (0 < set[j].subject_attribute_len)
671         ds_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup (set[j].subject_attribute);
672       ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
673       ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
674
675       ds_entry->parent_queue_entry = dq_entry; //current_delegation;
676       GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
677                                    dq_entry->set_entries_tail,
678                                    ds_entry);
679
680       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681                   "Checking for cred match\n");
682       /**
683        * Check if this delegation already matches one of our credentials
684        */
685       for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
686           cred_pointer = cred_pointer->next)
687       {
688         if(0 != memcmp (&set->subject_key, 
689                         &cred_pointer->credential->issuer_key,
690                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
691           continue;
692         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693                     "Checking if %s matches %s\n",
694                     ds_entry->unresolved_attribute_delegation,
695                     cred_pointer->credential->issuer_attribute);
696
697         if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
698                          cred_pointer->credential->issuer_attribute))
699           continue;
700
701         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702                     "Found issuer\n");
703
704         //Backtrack
705         for (tmp_set = ds_entry;
706              NULL != tmp_set->parent_queue_entry;
707              tmp_set = tmp_set->parent_queue_entry->parent_set)
708         {
709           tmp_set->parent_queue_entry->required_solutions--;
710           if (NULL != tmp_set->delegation_chain_entry)
711           {
712             vrh->delegation_chain_size++;
713             GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
714                                          vrh->delegation_chain_tail,
715                                          tmp_set->delegation_chain_entry);
716           }
717           if (0 < tmp_set->parent_queue_entry->required_solutions)
718             break;
719         }
720
721         if (NULL == tmp_set->parent_queue_entry)
722         {
723           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724                       "All solutions found\n");
725           //Found match
726           send_lookup_response (vrh);
727           return;
728         }
729         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730                     "Not all solutions found yet.\n");
731         continue;
732
733       }
734       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
735                   "Building new lookup request from %s\n",
736                   ds_entry->unresolved_attribute_delegation);
737       //Continue with backward resolution
738       char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
739       strcpy (issuer_attribute_name,
740               ds_entry->unresolved_attribute_delegation);
741       char *next_attr = strtok (issuer_attribute_name, ".");
742       GNUNET_asprintf (&lookup_attribute,
743                        "%s.gnu",
744                        next_attr);
745       GNUNET_asprintf (&ds_entry->lookup_attribute,
746                        "%s",
747                        next_attr);
748       if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
749       {
750         ds_entry->attr_trailer = NULL;
751       } else {
752         next_attr += strlen (next_attr) + 1;
753         ds_entry->attr_trailer = GNUNET_strdup (next_attr);
754       }
755
756       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757                   "Looking up %s\n", ds_entry->lookup_attribute);
758       if (NULL != ds_entry->attr_trailer)
759         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760                     "%s still to go...\n", ds_entry->attr_trailer);
761
762       vrh->pending_lookups++;
763       ds_entry->handle = vrh;
764       ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
765                                                     lookup_attribute,
766                                                     ds_entry->issuer_key, //issuer_key,
767                                                     GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
768                                                     GNUNET_GNS_LO_DEFAULT,
769                                                     NULL, //shorten_key, always NULL
770                                                     &backward_resolution,
771                                                     ds_entry);
772       GNUNET_free (lookup_attribute);
773     }
774   }
775
776   if(0 == vrh->pending_lookups)
777   {
778     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779                 "We are all out of attributes...\n");
780     send_lookup_response (vrh);
781     return;
782
783   }
784
785
786
787 /**
788  * Result from GNS lookup.
789  *
790  * @param cls the closure (our client lookup handle)
791  * @param rd_count the number of records in @a rd
792  * @param rd the record data
793  */
794 static void
795 handle_credential_query (void* cls,
796                          uint32_t rd_count,
797                          const struct GNUNET_GNSRECORD_Data *rd)
798 {
799   struct VerifyRequestHandle *vrh = cls;
800   struct DelegationSetQueueEntry *ds_entry;
801   struct GNUNET_CREDENTIAL_Credential *crd;
802   struct CredentialRecordEntry *cr_entry;
803   int cred_record_count;
804   int i;
805
806   vrh->lookup_request = NULL;
807   cred_record_count = 0;
808   for (i=0; i < rd_count; i++)
809   {
810     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
811       continue;
812     cred_record_count++;
813     crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
814                                                     rd[i].data_size);
815     if (NULL == crd)
816     {
817       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
818                   "Invalid credential found\n");
819       continue;
820     }
821     cr_entry = GNUNET_new (struct CredentialRecordEntry);
822     cr_entry->credential = crd;
823     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
824                                       vrh->cred_chain_tail,
825                                       cr_entry);
826     vrh->cred_chain_size++;
827
828     if (0 != memcmp (&crd->issuer_key,
829                      &vrh->issuer_key,
830                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
831       continue;
832     if (0 != strcmp (crd->issuer_attribute, vrh->issuer_attribute))
833       continue;
834     //Found match prematurely
835     send_lookup_response (vrh);
836     return;
837
838   }
839
840   /**
841    * Check for attributes from the issuer and follow the chain 
842    * till you get the required subject's attributes
843    */
844   char issuer_attribute_name[strlen (vrh->issuer_attribute)];
845   strcpy (issuer_attribute_name,
846           vrh->issuer_attribute);
847   strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
848           ".gnu");
849   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
850               "Looking up %s\n", issuer_attribute_name);
851   ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
852   ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
853   memcpy (ds_entry->issuer_key,
854           &vrh->issuer_key,
855           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
856   ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
857   ds_entry->handle = vrh;
858   ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
859   vrh->root_set = ds_entry;
860   vrh->pending_lookups = 1;
861   //Start with backward resolution
862   ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
863                                                 issuer_attribute_name,
864                                                 &vrh->issuer_key, //issuer_key,
865                                                 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
866                                                 GNUNET_GNS_LO_DEFAULT,
867                                                 NULL, //shorten_key, always NULL
868                                                 &backward_resolution,
869                                                 ds_entry);
870 }
871
872
873 /**
874  * Handle Credential verification requests from client
875  *
876  * @param cls the closure
877  * @param client the client
878  * @param message the message
879  */
880 static void
881 handle_verify (void *cls,
882                const struct VerifyMessage *v_msg) 
883 {
884   char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
885   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
886   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1 + 4];
887   struct VerifyRequestHandle *vrh;
888   struct GNUNET_SERVICE_Client *client = cls;
889   char *attrptr = attrs;
890   const char *utf_in;
891
892   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893               "Received VERIFY message\n");
894
895   utf_in = (const char *) &v_msg[1];
896   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
897
898   GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
899   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
900   GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
901   strcpy (subject_attribute+ntohs (v_msg->subject_attribute_len),
902           ".gnu");
903   subject_attribute[ntohs (v_msg->subject_attribute_len)+4] = '\0';
904   vrh = GNUNET_new (struct VerifyRequestHandle);
905   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
906   vrh->client = client;
907   vrh->request_id = v_msg->id;
908   vrh->issuer_key = v_msg->issuer_key;
909   vrh->subject_key = v_msg->subject_key;
910   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
911
912   if (NULL == subject_attribute)
913   {
914     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
915                 "No subject attribute provided!\n");
916     send_lookup_response (vrh);
917     return;
918   }
919   if (NULL == issuer_attribute)
920   {
921     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
922                 "No issuer attribute provided!\n");
923     send_lookup_response (vrh);
924     return;
925   }
926   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927               "Looking up %s\n",
928               subject_attribute);
929   /**
930    * First, get attribute from subject
931    */
932   vrh->lookup_request = GNUNET_GNS_lookup (gns,
933                                            subject_attribute,
934                                            &v_msg->subject_key, //subject_pkey,
935                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
936                                            GNUNET_GNS_LO_DEFAULT,
937                                            NULL, //shorten_key, always NULL
938                                            &handle_credential_query,
939                                            vrh);
940 }
941
942
943 /**
944  * One of our clients disconnected, clean up after it.
945  *
946  * @param cls NULL
947  * @param client the client that disconnected
948  */
949 static void
950 client_disconnect_cb (void *cls,
951                       struct GNUNET_SERVICE_Client *client,
952                       void *app_ctx)
953 {
954   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
955               "Client %p disconnected\n",
956               client);
957 }
958
959 /**
960  * Add a client to our list of active clients.
961  *
962  * @param cls NULL
963  * @param client client to add
964  * @param mq message queue for @a client
965  * @return this client
966  */
967 static void *
968 client_connect_cb (void *cls,
969                    struct GNUNET_SERVICE_Client *client,
970                    struct GNUNET_MQ_Handle *mq)
971 {
972   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
973               "Client %p connected\n",
974               client);
975   return client;
976 }
977
978 /**
979  * Process Credential requests.
980  *
981  * @param cls closure
982  * @param server the initialized server
983  * @param c configuration to use
984  */
985 static void
986 run (void *cls,
987      const struct GNUNET_CONFIGURATION_Handle *c,
988      struct GNUNET_SERVICE_Handle *handle)
989 {
990
991   gns = GNUNET_GNS_connect (c);
992   if (NULL == gns)
993   {
994     fprintf (stderr,
995              _("Failed to connect to GNS\n"));
996   }
997
998   statistics = GNUNET_STATISTICS_create ("credential", c);
999   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1000 }
1001
1002
1003 /**
1004  * Define "main" method using service macro
1005  */
1006 GNUNET_SERVICE_MAIN
1007 ("credential",
1008  GNUNET_SERVICE_OPTION_NONE,
1009  &run,
1010  &client_connect_cb,
1011  &client_disconnect_cb,
1012  NULL,
1013  GNUNET_MQ_hd_var_size (verify,
1014                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1015                         struct VerifyMessage,
1016                         NULL),
1017  GNUNET_MQ_handler_end());
1018
1019 /* end of gnunet-service-credential.c */