8f7d71b28773e4907ecb6c2a4eb2200eff9d7bfa
[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 GNUNET_CREDENTIAL_DelegationChainEntry
50 {
51   /**
52    * The issuer
53    */
54   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
55   
56   /**
57    * The subject
58    */
59   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
60   
61   /**
62    * The issued attribute
63    */
64   char *issuer_attribute;
65   
66   /**
67    * The delegated attribute
68    */
69   char *subject_attribute;
70 };
71
72 /**
73  * DLL for record
74  */
75 struct CredentialRecordEntry
76 {
77   /**
78    * DLL
79    */
80   struct CredentialRecordEntry *next;
81
82   /**
83    * DLL
84    */
85   struct CredentialRecordEntry *prev;
86
87
88   /**
89    * Payload
90    */
91   struct GNUNET_CREDENTIAL_CredentialRecordData *data;
92
93   /**
94    * Size
95    */
96   uint64_t data_size;
97 };
98
99 /**
100  * DLL for delegations - Used as a queue
101  * Insert tail - Pop head
102  */
103 struct DelegationQueueEntry
104 {
105   /**
106    * DLL
107    */
108   struct DelegationQueueEntry *next;
109
110   /**
111    * DLL
112    */
113   struct DelegationQueueEntry *prev;
114
115   /**
116    * Children of this attribute
117    */
118   struct DelegationQueueEntry *children_head;
119
120   /**
121    * Children of this attribute
122    */
123   struct DelegationQueueEntry *children_tail;
124
125   /**
126    * GNS handle
127    */
128   struct GNUNET_GNS_LookupRequest *lookup_request;
129
130   /**
131    * Verify handle
132    */
133   struct VerifyRequestHandle *handle;
134
135   /**
136    * Parent attribute delegation
137    */
138   struct DelegationQueueEntry *parent;
139
140   /**
141    * Issuer key
142    */
143   struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
144
145   /**
146    * Issuer attribute delegated to
147    */
148   char *issuer_attribute;
149
150   /**
151    * The current attribute to look up
152    */
153   char *lookup_attribute;
154
155   /**
156    * Trailing attribute context
157    */
158   char *attr_trailer;
159
160   /**
161    * Still to resolve delegation as string
162    */
163   char *unresolved_attribute_delegation;
164   
165   /**
166    * The delegation chain entry
167    */
168   struct GNUNET_CREDENTIAL_DelegationChainEntry *delegation_chain_entry;
169
170   /**
171    * Delegation chain length until now
172    */
173   uint32_t d_count;
174 };
175
176
177 /**
178  * Handle to a lookup operation from api
179  */
180 struct VerifyRequestHandle
181 {
182
183   /**
184    * We keep these in a DLL.
185    */
186   struct VerifyRequestHandle *next;
187
188   /**
189    * We keep these in a DLL.
190    */
191   struct VerifyRequestHandle *prev;
192
193   /**
194    * Handle to the requesting client
195    */
196   struct GNUNET_SERVICE_Client *client;
197   
198   /**
199    * GNS handle
200    */
201   struct GNUNET_GNS_LookupRequest *lookup_request;
202
203
204   /**
205    * Issuer public key
206    */
207   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
208   
209   /**
210    * Issuer attribute
211    */
212   char *issuer_attribute;
213
214   /**
215    * Subject public key
216    */
217   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
218
219   /**
220    * Credential Chain
221    */
222   struct CredentialRecordEntry *cred_chain_head;
223
224   /**
225    * Credential Chain
226    */
227   struct CredentialRecordEntry *cred_chain_tail;
228
229   /**
230    * Delegation Queue
231    */
232   struct DelegationQueueEntry *chain_start;
233   
234   /**
235    * Delegation Queue
236    */
237   struct DelegationQueueEntry *chain_end;
238   
239   /**
240    * Current Delegation Pointer
241    */
242   struct DelegationQueueEntry *current_delegation;
243
244   /**
245    * The found credential
246    */
247   struct GNUNET_CREDENTIAL_CredentialRecordData *credential;
248
249   /**
250    * Length of the credential
251    */
252   uint32_t credential_size;
253
254   /**
255    * Length of found delegation chain
256    */
257   uint32_t d_count;
258
259   /**
260    * request id
261    */
262   uint32_t request_id;
263
264   /**
265    * Pending lookups
266    */
267   uint64_t pending_lookups;
268
269 };
270
271
272 /**
273  * Head of the DLL.
274  */
275 static struct VerifyRequestHandle *vrh_head;
276
277 /**
278  * Tail of the DLL.
279  */
280 static struct VerifyRequestHandle *vrh_tail;
281
282 /**
283  * Handle to the statistics service
284  */
285 static struct GNUNET_STATISTICS_Handle *statistics;
286
287 /**
288  * Handle to GNS service.
289  */
290 static struct GNUNET_GNS_Handle *gns;
291
292
293 static void
294 cleanup_delegation_queue (struct DelegationQueueEntry *dq_entry)
295 {
296   struct DelegationQueueEntry *child;
297   if (NULL == dq_entry)
298     return;
299
300   for (child = dq_entry->children_head; NULL != child; child = dq_entry->children_head)
301   {
302     GNUNET_CONTAINER_DLL_remove (dq_entry->children_head,
303                                  dq_entry->children_tail,
304                                  child);
305     cleanup_delegation_queue (child);
306   }
307   if (NULL != dq_entry->issuer_key)
308     GNUNET_free (dq_entry->issuer_key);
309   if (NULL != dq_entry->lookup_attribute)
310     GNUNET_free (dq_entry->lookup_attribute);
311   if (NULL != dq_entry->issuer_attribute)
312     GNUNET_free (dq_entry->issuer_attribute);
313   if (NULL != dq_entry->unresolved_attribute_delegation)
314     GNUNET_free (dq_entry->unresolved_attribute_delegation);
315   if (NULL != dq_entry->attr_trailer)
316     GNUNET_free (dq_entry->attr_trailer);
317   if (NULL != dq_entry->lookup_request)
318   {
319     GNUNET_GNS_lookup_cancel (dq_entry->lookup_request);
320     dq_entry->lookup_request = NULL;
321   }
322   if (NULL != dq_entry->delegation_chain_entry)
323   {
324     if (NULL != dq_entry->delegation_chain_entry->subject_attribute)
325       GNUNET_free (dq_entry->delegation_chain_entry->subject_attribute);
326     if (NULL != dq_entry->delegation_chain_entry->issuer_attribute)
327       GNUNET_free (dq_entry->delegation_chain_entry->issuer_attribute);
328     GNUNET_free (dq_entry->delegation_chain_entry);
329   }
330   GNUNET_free (dq_entry);
331 }
332
333 static void
334 cleanup_handle (struct VerifyRequestHandle *vrh)
335 {
336   struct CredentialRecordEntry *cr_entry;
337   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
338               "Cleaning up...\n");
339   if (NULL != vrh->lookup_request)
340   {
341     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
342     vrh->lookup_request = NULL;
343   }
344   if (NULL != vrh->credential)
345     GNUNET_free (vrh->credential);
346   cleanup_delegation_queue (vrh->chain_start);
347   if (NULL != vrh->issuer_attribute)
348     GNUNET_free (vrh->issuer_attribute);
349   for (cr_entry = vrh->cred_chain_head; 
350        NULL != vrh->cred_chain_head;
351        cr_entry = vrh->cred_chain_head)
352   {
353     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
354                                  vrh->cred_chain_tail,
355                                  cr_entry);
356     if (NULL != cr_entry->data)
357       GNUNET_free (cr_entry->data);
358     GNUNET_free (cr_entry);
359   }
360   GNUNET_free (vrh);
361 }
362
363 /**
364  * Task run during shutdown.
365  *
366  * @param cls unused
367  * @param tc unused
368  */
369 static void
370 shutdown_task (void *cls)
371 {
372   struct VerifyRequestHandle *vrh;
373
374   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
375               "Shutting down!\n");
376
377   while (NULL != (vrh = vrh_head))
378   {
379     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
380     GNUNET_CONTAINER_DLL_remove (vrh_head,
381                                  vrh_tail,
382                                  vrh);
383     cleanup_handle (vrh);
384   }
385
386   if (NULL != gns)
387   {
388     GNUNET_GNS_disconnect (gns);
389     gns = NULL;
390   }
391   if (NULL != statistics)
392   {
393     GNUNET_STATISTICS_destroy (statistics,
394                                GNUNET_NO);
395     statistics = NULL;
396   }
397
398 }
399
400 /**
401  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
402  *
403  * @param cls client sending the message
404  * @param v_msg message of type `struct VerifyMessage`
405  * @return #GNUNET_OK if @a v_msg is well-formed
406  */
407 static int
408 check_verify (void *cls,
409               const struct VerifyMessage *v_msg)
410 {
411   size_t msg_size;
412   const char* attrs;
413
414   msg_size = ntohs (v_msg->header.size);
415   if (msg_size < sizeof (struct VerifyMessage))
416   {
417     GNUNET_break (0);
418     return GNUNET_SYSERR;
419   }
420   if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
421       (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
422   {
423     GNUNET_break (0);
424     return GNUNET_SYSERR;
425   }
426   attrs = (const char *) &v_msg[1];
427
428   if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
429        (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
430   {
431     GNUNET_break (0);
432     return GNUNET_SYSERR;
433   }
434   return GNUNET_OK;
435 }
436
437 /**
438  * Send.
439  *
440  * @param handle the handle to the request
441  */
442 static void
443 send_lookup_response (struct VerifyRequestHandle *vrh)
444 {
445   struct GNUNET_MQ_Envelope *env;
446   struct VerifyResultMessage *rmsg;
447   struct DelegationQueueEntry *dq_entry;
448   size_t size = vrh->credential_size;
449   struct GNUNET_CREDENTIAL_Delegation dd[vrh->d_count];
450   struct GNUNET_CREDENTIAL_Credential cred;
451
452   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
453               "Sending response\n");
454   dq_entry = vrh->chain_end;
455   for (int i=0; i<vrh->d_count; i++)
456   {
457     dd[i].issuer_key = dq_entry->delegation_chain_entry->issuer_key;
458     dd[i].subject_key = dq_entry->delegation_chain_entry->subject_key;
459     dd[i].issuer_attribute = dq_entry->delegation_chain_entry->issuer_attribute;
460     dd[i].issuer_attribute_len = strlen (dq_entry->delegation_chain_entry->issuer_attribute)+1;
461     dd[i].subject_attribute_len = 0;
462     if (NULL != dq_entry->delegation_chain_entry->subject_attribute)
463     {
464       dd[i].subject_attribute = dq_entry->delegation_chain_entry->subject_attribute;
465       dd[i].subject_attribute_len = strlen(dq_entry->delegation_chain_entry->subject_attribute)+1;
466     }
467     dq_entry = dq_entry->parent;
468   }
469
470     /**
471    * Get serialized record data
472    * Append at the end of rmsg
473    */
474   cred.issuer_key = vrh->credential->issuer_key;
475   cred.subject_key = vrh->credential->subject_key;
476   cred.issuer_attribute_len = strlen((char*)&vrh->credential[1]);
477   cred.issuer_attribute = (char*)&vrh->credential[1];
478   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->d_count,
479                                                       dd,
480                                                       &cred);
481   env = GNUNET_MQ_msg_extra (rmsg,
482                              size,
483                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
484   //Assign id so that client can find associated request
485   rmsg->id = vrh->request_id;
486   rmsg->d_count = htonl (vrh->d_count);
487
488   if (NULL != vrh->credential)
489     rmsg->cred_found = htonl (GNUNET_YES);
490   else
491     rmsg->cred_found = htonl (GNUNET_NO);
492
493   GNUNET_assert (-1 != GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->d_count,
494                                                 dd,
495                                                 &cred,
496                                                 size,
497                                                 (char*)&rmsg[1]));
498
499   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
500                   env);
501   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
502   cleanup_handle(vrh);
503
504   GNUNET_STATISTICS_update (statistics,
505                             "Completed verifications", 1,
506                             GNUNET_NO);
507 }
508
509
510 static void
511 backward_resolution (void* cls,
512                      uint32_t rd_count,
513                      const struct GNUNET_GNSRECORD_Data *rd)
514 {
515
516   struct VerifyRequestHandle *vrh;
517   struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
518   const struct GNUNET_CREDENTIAL_AttributeRecordData *attr;
519   struct CredentialRecordEntry *cred_pointer;
520   struct DelegationQueueEntry *current_delegation;
521   struct DelegationQueueEntry *dq_entry;
522   char *expanded_attr;
523   char *lookup_attribute;
524   int i;
525
526
527   current_delegation = cls;
528   current_delegation->lookup_request = NULL;
529   vrh = current_delegation->handle;
530   vrh->pending_lookups--;
531   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532               "Got %d attrs\n", rd_count);
533
534   for (i=0; i < rd_count; i++) 
535   {
536     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
537       continue;
538
539     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
540                 "Found new attribute delegation. Creating new Job...\n");
541     attr = rd[i].data;
542     dq_entry = GNUNET_new (struct DelegationQueueEntry);
543     if (NULL != current_delegation->attr_trailer)
544     {
545       if (rd[i].data_size == sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData))
546       {
547         GNUNET_asprintf (&expanded_attr,
548                          "%s",
549                          current_delegation->attr_trailer);
550
551       } else {
552         GNUNET_asprintf (&expanded_attr,
553                          "%s.%s",
554                          (char*)&attr[1],
555                          current_delegation->attr_trailer);
556       }
557       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
558                   "Expanded to %s\n", expanded_attr);
559       dq_entry->unresolved_attribute_delegation = expanded_attr;
560     } else {
561       if (rd[i].data_size > sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData))
562       {
563         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
564                     "Not Expanding %s\n", (char*)&attr[1]);
565         dq_entry->unresolved_attribute_delegation = GNUNET_strdup ((char*)&attr[1]);
566       }
567     }
568
569     //Add a credential chain entry
570     dq_entry->delegation_chain_entry = GNUNET_new (struct GNUNET_CREDENTIAL_DelegationChainEntry);
571     dq_entry->delegation_chain_entry->subject_key = attr->subject_key;
572     dq_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
573     GNUNET_memcpy (dq_entry->issuer_key,
574                    &attr->subject_key,
575                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
576     if (rd[i].data_size > sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData))
577       dq_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup ((char*)&attr[1]);
578     dq_entry->delegation_chain_entry->issuer_key = *current_delegation->issuer_key;
579     dq_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_delegation->lookup_attribute);
580
581     dq_entry->parent = current_delegation;
582     dq_entry->d_count = current_delegation->d_count + 1;
583     GNUNET_CONTAINER_DLL_insert (current_delegation->children_head,
584                                  current_delegation->children_tail,
585                                  dq_entry);
586     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
587                 "Checking for cred match\n");
588     /**
589      * Check if this delegation already matches one of our credentials
590      */
591     for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
592         cred_pointer = cred_pointer->next)
593     {
594       cred = cred_pointer->data;
595       if(0 != memcmp (&attr->subject_key, 
596                       &cred_pointer->data->issuer_key,
597                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
598         continue;
599       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
600                   "Checking if %s matches %s\n",
601                   dq_entry->unresolved_attribute_delegation, (char*)&cred[1]);
602
603       if (0 != strcmp (dq_entry->unresolved_attribute_delegation, (char*)&cred[1]))
604         continue;
605
606       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
607                   "Found issuer\n");
608       vrh->credential = GNUNET_malloc (cred_pointer->data_size);
609       memcpy (vrh->credential,
610               cred,
611               cred_pointer->data_size);
612       vrh->credential_size = cred_pointer->data_size;
613       vrh->chain_end = dq_entry;
614       vrh->d_count = dq_entry->d_count;
615       //Found match
616       send_lookup_response (vrh);
617       return;
618
619     }
620     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
621                 "Building new lookup request\n");
622     //Continue with backward resolution
623     char issuer_attribute_name[strlen (dq_entry->unresolved_attribute_delegation)+1];
624     strcpy (issuer_attribute_name,
625             dq_entry->unresolved_attribute_delegation);
626     char *next_attr = strtok (issuer_attribute_name, ".");
627     GNUNET_asprintf (&lookup_attribute,
628                      "%s.gnu",
629                      next_attr);
630     GNUNET_asprintf (&dq_entry->lookup_attribute,
631                      "%s",
632                      next_attr);
633     if (strlen (next_attr) == strlen (dq_entry->unresolved_attribute_delegation))
634     {
635       dq_entry->attr_trailer = NULL;
636     } else {
637       next_attr += strlen (next_attr) + 1;
638       dq_entry->attr_trailer = GNUNET_strdup (next_attr);
639     }
640
641     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
642                 "Looking up %s\n", dq_entry->lookup_attribute);
643     if (NULL != dq_entry->attr_trailer)
644       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
645                   "%s still to go...\n", dq_entry->attr_trailer);
646
647     vrh->pending_lookups++;
648     dq_entry->handle = vrh;
649     dq_entry->lookup_request = GNUNET_GNS_lookup (gns,
650                                                   lookup_attribute,
651                                                   dq_entry->issuer_key, //issuer_key,
652                                                   GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
653                                                   GNUNET_GNS_LO_DEFAULT,
654                                                   NULL, //shorten_key, always NULL
655                                                   &backward_resolution,
656                                                   dq_entry);
657     GNUNET_free (lookup_attribute);
658   }
659
660   if(0 == vrh->pending_lookups)
661   {
662     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663                 "We are all out of attributes...\n");
664     send_lookup_response (vrh);
665     return;
666
667   }
668
669
670
671 /**
672  * Result from GNS lookup.
673  *
674  * @param cls the closure (our client lookup handle)
675  * @param rd_count the number of records in @a rd
676  * @param rd the record data
677  */
678 static void
679 handle_credential_query (void* cls,
680                          uint32_t rd_count,
681                          const struct GNUNET_GNSRECORD_Data *rd)
682 {
683   struct VerifyRequestHandle *vrh = cls;
684   struct DelegationQueueEntry *dq_entry;
685   const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
686   struct CredentialRecordEntry *cr_entry;
687   int cred_record_count;
688   int i;
689
690   vrh->lookup_request = NULL;
691   cred_record_count = 0;
692   for (i=0; i < rd_count; i++)
693   {
694     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
695       continue;
696     cred_record_count++;
697     crd = rd[i].data;
698     if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
699                                                &crd->purpose,
700                                                &crd->signature,
701                                                &crd->issuer_key))
702     {
703       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
704                   "Invalid credential found\n");
705       continue;
706     }
707     cr_entry = GNUNET_new (struct CredentialRecordEntry);
708     cr_entry->data = GNUNET_malloc (rd[i].data_size);
709     memcpy (cr_entry->data,
710             crd,
711             rd[i].data_size);
712     cr_entry->data_size = rd[i].data_size;
713     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
714                                       vrh->cred_chain_tail,
715                                       cr_entry);
716
717     if (0 != memcmp (&crd->issuer_key,
718                      &vrh->issuer_key,
719                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
720       continue;
721     if (0 != strcmp ((char*)&crd[1], vrh->issuer_attribute))
722       continue;
723     vrh->credential = GNUNET_malloc (rd[i].data_size);
724     memcpy (vrh->credential,
725             rd[i].data,
726             rd[i].data_size);
727     vrh->credential_size = rd[i].data_size;
728     vrh->chain_end = NULL;
729     //Found match prematurely
730     send_lookup_response (vrh);
731     return;
732
733   }
734
735   /**
736    * Check for attributes from the issuer and follow the chain 
737    * till you get the required subject's attributes
738    */
739   char issuer_attribute_name[strlen (vrh->issuer_attribute)];
740   strcpy (issuer_attribute_name,
741           vrh->issuer_attribute);
742   strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
743           ".gnu");
744   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
745               "Looking up %s\n", issuer_attribute_name);
746   dq_entry = GNUNET_new (struct DelegationQueueEntry);
747   dq_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
748   memcpy (dq_entry->issuer_key,
749           &vrh->issuer_key,
750           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
751   dq_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
752   dq_entry->handle = vrh;
753   dq_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
754   dq_entry->d_count = 0;
755   vrh->chain_start = dq_entry;
756   vrh->pending_lookups = 1;
757   //Start with backward resolution
758   dq_entry->lookup_request = GNUNET_GNS_lookup (gns,
759                                                 issuer_attribute_name,
760                                                 &vrh->issuer_key, //issuer_key,
761                                                 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
762                                                 GNUNET_GNS_LO_DEFAULT,
763                                                 NULL, //shorten_key, always NULL
764                                                 &backward_resolution,
765                                                 dq_entry);
766 }
767
768
769 /**
770  * Handle Credential verification requests from client
771  *
772  * @param cls the closure
773  * @param client the client
774  * @param message the message
775  */
776 static void
777 handle_verify (void *cls,
778                const struct VerifyMessage *v_msg) 
779 {
780   char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
781   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
782   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1 + 4];
783   struct VerifyRequestHandle *vrh;
784   struct GNUNET_SERVICE_Client *client = cls;
785   char *attrptr = attrs;
786   const char *utf_in;
787
788   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
789               "Received VERIFY message\n");
790
791   utf_in = (const char *) &v_msg[1];
792   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
793
794   GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
795   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
796   GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
797   strcpy (subject_attribute+ntohs (v_msg->subject_attribute_len),
798           ".gnu");
799   subject_attribute[ntohs (v_msg->subject_attribute_len)+4] = '\0';
800   vrh = GNUNET_new (struct VerifyRequestHandle);
801   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
802   vrh->client = client;
803   vrh->request_id = v_msg->id;
804   vrh->issuer_key = v_msg->issuer_key;
805   vrh->subject_key = v_msg->subject_key;
806   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
807
808   if (NULL == subject_attribute)
809   {
810     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
811                 "No subject attribute provided!\n");
812     send_lookup_response (vrh);
813     return;
814   }
815   if (NULL == issuer_attribute)
816   {
817     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
818                 "No issuer attribute provided!\n");
819     send_lookup_response (vrh);
820     return;
821   }
822   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823               "Looking up %s\n",
824               subject_attribute);
825   /**
826    * First, get attribute from subject
827    */
828   vrh->lookup_request = GNUNET_GNS_lookup (gns,
829                                            subject_attribute,
830                                            &v_msg->subject_key, //subject_pkey,
831                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
832                                            GNUNET_GNS_LO_DEFAULT,
833                                            NULL, //shorten_key, always NULL
834                                            &handle_credential_query,
835                                            vrh);
836 }
837
838
839 /**
840  * One of our clients disconnected, clean up after it.
841  *
842  * @param cls NULL
843  * @param client the client that disconnected
844  */
845 static void
846 client_disconnect_cb (void *cls,
847                       struct GNUNET_SERVICE_Client *client,
848                       void *app_ctx)
849 {
850   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
851               "Client %p disconnected\n",
852               client);
853 }
854
855 /**
856  * Add a client to our list of active clients.
857  *
858  * @param cls NULL
859  * @param client client to add
860  * @param mq message queue for @a client
861  * @return this client
862  */
863 static void *
864 client_connect_cb (void *cls,
865                    struct GNUNET_SERVICE_Client *client,
866                    struct GNUNET_MQ_Handle *mq)
867 {
868   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
869               "Client %p connected\n",
870               client);
871   return client;
872 }
873
874 /**
875  * Process Credential requests.
876  *
877  * @param cls closure
878  * @param server the initialized server
879  * @param c configuration to use
880  */
881 static void
882 run (void *cls,
883      const struct GNUNET_CONFIGURATION_Handle *c,
884      struct GNUNET_SERVICE_Handle *handle)
885 {
886
887   gns = GNUNET_GNS_connect (c);
888   if (NULL == gns)
889   {
890     fprintf (stderr,
891              _("Failed to connect to GNS\n"));
892   }
893
894   statistics = GNUNET_STATISTICS_create ("credential", c);
895   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
896 }
897
898
899 /**
900  * Define "main" method using service macro
901  */
902 GNUNET_SERVICE_MAIN
903 ("credential",
904  GNUNET_SERVICE_OPTION_NONE,
905  &run,
906  &client_connect_cb,
907  &client_disconnect_cb,
908  NULL,
909  GNUNET_MQ_hd_var_size (verify,
910                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
911                         struct VerifyMessage,
912                         NULL),
913  GNUNET_MQ_handler_end());
914
915 /* end of gnunet-service-credential.c */