8843abfd6a29dcda6f6105a2de2aec3a2b0fdc86
[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 DelegationSetEntry;
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_CredentialRecordData *data;
105
106   /**
107    * Size
108    */
109   uint64_t data_size;
110 };
111
112 /**
113  * DLL used for delegations
114  * Used for OR delegations
115  */
116 struct DelegationQueueEntry
117 {
118   /**
119    * DLL
120    */
121   struct DelegationQueueEntry *next;
122
123   /**
124    * DLL
125    */
126   struct DelegationQueueEntry *prev;
127
128   /**
129    * Sets under this Queue
130    */
131   struct DelegationSetEntry *set_entries_head;
132
133   /**
134    * Sets under this Queue
135    */
136   struct DelegationSetEntry *set_entries_tail;
137
138   /**
139    * Parent set
140    */
141   struct DelegationSetEntry *parent_set;
142
143   /**
144    * Required solutions
145    */
146   uint32_t required_solutions;
147 };
148
149 /**
150  * DLL for delegation sets
151  * Used for AND delegation set
152  */
153 struct DelegationSetEntry
154 {
155   /**
156    * DLL
157    */
158   struct DelegationSetEntry *next;
159
160   /**
161    * DLL
162    */
163   struct DelegationSetEntry *prev;
164
165     /**
166    * GNS handle
167    */
168   struct GNUNET_GNS_LookupRequest *lookup_request;
169
170   /**
171    * Verify handle
172    */
173   struct VerifyRequestHandle *handle;
174
175   /**
176    * Parent attribute delegation
177    */
178   struct DelegationQueueEntry *parent;
179
180   /**
181    * Issuer key
182    */
183   struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
184
185   /**
186    * Queue entries of this set
187    */
188   struct DelegationQueueEntry *queue_entries_head;
189
190   /**
191    * Queue entries of this set
192    */
193   struct DelegationQueueEntry *queue_entries_tail;
194
195   /**
196    * Parent QueueEntry
197    */
198   struct DelegationQueueEntry *parent_queue_entry;
199
200   /**
201    * Issuer attribute delegated to
202    */
203   char *issuer_attribute;
204
205   /**
206    * The current attribute to look up
207    */
208   char *lookup_attribute;
209
210   /**
211    * Trailing attribute context
212    */
213   char *attr_trailer;
214
215   /**
216    * Still to resolve delegation as string
217    */
218   char *unresolved_attribute_delegation;
219
220   /**
221    * The delegation chain entry
222    */
223   struct DelegationChainEntry *delegation_chain_entry;
224
225 };
226
227
228 /**
229  * Handle to a lookup operation from api
230  */
231 struct VerifyRequestHandle
232 {
233
234   /**
235    * We keep these in a DLL.
236    */
237   struct VerifyRequestHandle *next;
238
239   /**
240    * We keep these in a DLL.
241    */
242   struct VerifyRequestHandle *prev;
243
244   /**
245    * Handle to the requesting client
246    */
247   struct GNUNET_SERVICE_Client *client;
248
249   /**
250    * GNS handle
251    */
252   struct GNUNET_GNS_LookupRequest *lookup_request;
253
254   /**
255    * Size of delegation tree
256    */
257   uint32_t delegation_chain_size;
258
259   /**
260    * Children of this attribute
261    */
262   struct DelegationChainEntry *delegation_chain_head;
263
264   /**
265    * Children of this attribute
266    */
267   struct DelegationChainEntry *delegation_chain_tail;
268
269   /**
270    * Issuer public key
271    */
272   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
273
274   /**
275    * Issuer attribute
276    */
277   char *issuer_attribute;
278
279   /**
280    * Subject public key
281    */
282   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
283
284   /**
285    * Credential Chain
286    */
287   struct CredentialRecordEntry *cred_chain_head;
288
289   /**
290    * Credential Chain
291    */
292   struct CredentialRecordEntry *cred_chain_tail;
293
294   /**
295    * Root Delegation Set
296    */
297   struct DelegationSetEntry *root_set;
298
299   /**
300    * Current Delegation Pointer
301    */
302   struct DelegationQueueEntry *current_delegation;
303
304   /**
305    * The found credential
306    */
307   struct GNUNET_CREDENTIAL_CredentialRecordData *credential;
308
309   /**
310    * Length of the credential
311    */
312   uint32_t credential_size;
313
314   /**
315    * request id
316    */
317   uint32_t request_id;
318
319   /**
320    * Pending lookups
321    */
322   uint64_t pending_lookups;
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 static void
349 cleanup_delegation_set (struct DelegationSetEntry *ds_entry)
350 {
351   struct DelegationQueueEntry *dq_entry;
352   struct DelegationSetEntry *child;
353
354   if (NULL == ds_entry)
355     return;
356
357   for (dq_entry = ds_entry->queue_entries_head;
358        NULL != dq_entry;
359        dq_entry = ds_entry->queue_entries_head)
360   {
361     GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
362                                  ds_entry->queue_entries_tail,
363                                  dq_entry);
364     for (child = dq_entry->set_entries_head;
365          NULL != child;
366          child = dq_entry->set_entries_head)
367     {
368       GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
369                                    dq_entry->set_entries_tail,
370                                    child);
371       cleanup_delegation_set (child);
372     }
373     GNUNET_free (dq_entry);
374   }
375   if (NULL != ds_entry->issuer_key)
376     GNUNET_free (ds_entry->issuer_key);
377   if (NULL != ds_entry->lookup_attribute)
378     GNUNET_free (ds_entry->lookup_attribute);
379   if (NULL != ds_entry->issuer_attribute)
380     GNUNET_free (ds_entry->issuer_attribute);
381   if (NULL != ds_entry->unresolved_attribute_delegation)
382     GNUNET_free (ds_entry->unresolved_attribute_delegation);
383   if (NULL != ds_entry->attr_trailer)
384     GNUNET_free (ds_entry->attr_trailer);
385   if (NULL != ds_entry->lookup_request)
386   {
387     GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
388     ds_entry->lookup_request = NULL;
389   }
390   if (NULL != ds_entry->delegation_chain_entry)
391   {
392     if (NULL != ds_entry->delegation_chain_entry->subject_attribute)
393       GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute);
394     if (NULL != ds_entry->delegation_chain_entry->issuer_attribute)
395       GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
396     GNUNET_free (ds_entry->delegation_chain_entry);
397   }
398   GNUNET_free (ds_entry);
399 }
400
401 static void
402 cleanup_handle (struct VerifyRequestHandle *vrh)
403 {
404   struct CredentialRecordEntry *cr_entry;
405   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
406               "Cleaning up...\n");
407   if (NULL != vrh->lookup_request)
408   {
409     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
410     vrh->lookup_request = NULL;
411   }
412   if (NULL != vrh->credential)
413     GNUNET_free (vrh->credential);
414   cleanup_delegation_set (vrh->root_set);
415   if (NULL != vrh->issuer_attribute)
416     GNUNET_free (vrh->issuer_attribute);
417   for (cr_entry = vrh->cred_chain_head; 
418        NULL != vrh->cred_chain_head;
419        cr_entry = vrh->cred_chain_head)
420   {
421     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
422                                  vrh->cred_chain_tail,
423                                  cr_entry);
424     if (NULL != cr_entry->data)
425       GNUNET_free (cr_entry->data);
426     GNUNET_free (cr_entry);
427   }
428   GNUNET_free (vrh);
429 }
430
431 /**
432  * Task run during shutdown.
433  *
434  * @param cls unused
435  * @param tc unused
436  */
437 static void
438 shutdown_task (void *cls)
439 {
440   struct VerifyRequestHandle *vrh;
441
442   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443               "Shutting down!\n");
444
445   while (NULL != (vrh = vrh_head))
446   {
447     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
448     GNUNET_CONTAINER_DLL_remove (vrh_head,
449                                  vrh_tail,
450                                  vrh);
451     cleanup_handle (vrh);
452   }
453
454   if (NULL != gns)
455   {
456     GNUNET_GNS_disconnect (gns);
457     gns = NULL;
458   }
459   if (NULL != statistics)
460   {
461     GNUNET_STATISTICS_destroy (statistics,
462                                GNUNET_NO);
463     statistics = NULL;
464   }
465
466 }
467
468 /**
469  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
470  *
471  * @param cls client sending the message
472  * @param v_msg message of type `struct VerifyMessage`
473  * @return #GNUNET_OK if @a v_msg is well-formed
474  */
475 static int
476 check_verify (void *cls,
477               const struct VerifyMessage *v_msg)
478 {
479   size_t msg_size;
480   const char* attrs;
481
482   msg_size = ntohs (v_msg->header.size);
483   if (msg_size < sizeof (struct VerifyMessage))
484   {
485     GNUNET_break (0);
486     return GNUNET_SYSERR;
487   }
488   if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
489       (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
490   {
491     GNUNET_break (0);
492     return GNUNET_SYSERR;
493   }
494   attrs = (const char *) &v_msg[1];
495
496   if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
497        (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
498   {
499     GNUNET_break (0);
500     return GNUNET_SYSERR;
501   }
502   return GNUNET_OK;
503 }
504
505 /**
506  * Send.
507  *
508  * @param handle the handle to the request
509  */
510 static void
511 send_lookup_response (struct VerifyRequestHandle *vrh)
512 {
513   struct GNUNET_MQ_Envelope *env;
514   struct VerifyResultMessage *rmsg;
515   struct DelegationChainEntry *dce;
516   size_t size = vrh->credential_size;
517   struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
518   struct GNUNET_CREDENTIAL_Credential cred;
519   int i;
520
521   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
522               "Sending response\n");
523   i = 0;
524   for (dce = vrh->delegation_chain_head;
525        NULL != dce;
526        dce = dce->next)
527   {
528     dd[i].issuer_key = dce->issuer_key;
529     dd[i].subject_key = dce->subject_key;
530     dd[i].issuer_attribute = dce->issuer_attribute;
531     dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
532     dd[i].subject_attribute_len = 0;
533     if (NULL != dce->subject_attribute)
534     {
535       dd[i].subject_attribute = dce->subject_attribute;
536       dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
537     }
538     i++;
539   }
540
541   /**
542    * Get serialized record data
543    * Append at the end of rmsg
544    */
545   cred.issuer_key = vrh->credential->issuer_key;
546   cred.subject_key = vrh->credential->subject_key;
547   cred.issuer_attribute_len = strlen((char*)&vrh->credential[1])+1;
548   cred.issuer_attribute = (char*)&vrh->credential[1];
549   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
550                                                       dd,
551                                                       &cred);
552   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
553               "SIZE; %llu count: %d\n",size,vrh->delegation_chain_size);
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
561   if (NULL != vrh->credential)
562     rmsg->cred_found = htonl (GNUNET_YES);
563   else
564     rmsg->cred_found = htonl (GNUNET_NO);
565
566   GNUNET_assert (-1 != 
567                GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
568                                                              dd,
569                                                              &cred,
570                                                              size,
571                                                              (char*)&rmsg[1]));
572
573   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
574                   env);
575   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
576   cleanup_handle(vrh);
577
578   GNUNET_STATISTICS_update (statistics,
579                             "Completed verifications", 1,
580                             GNUNET_NO);
581 }
582
583
584 static void
585 backward_resolution (void* cls,
586                      uint32_t rd_count,
587                      const struct GNUNET_GNSRECORD_Data *rd)
588 {
589
590   struct VerifyRequestHandle *vrh;
591   struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
592   const struct GNUNET_CREDENTIAL_DelegationRecordData *sets;
593   struct CredentialRecordEntry *cred_pointer;
594   struct DelegationSetEntry *current_set;
595   struct DelegationSetEntry *ds_entry;
596   struct DelegationSetEntry *tmp_set;
597   struct DelegationQueueEntry *dq_entry;
598   char *expanded_attr;
599   char *lookup_attribute;
600   int i;
601   int j;
602
603
604   current_set = cls;
605   current_set->lookup_request = NULL;
606   vrh = current_set->handle;
607   vrh->pending_lookups--;
608   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609               "Got %d attrs\n", rd_count);
610
611   // Each OR
612   for (i=0; i < rd_count; i++) 
613   {
614     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
615       continue;
616
617     sets = rd[i].data;
618     struct GNUNET_CREDENTIAL_DelegationSetRecord set[ntohl(sets->set_count)];
619     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
620                 "Found new attribute delegation with %d sets. Creating new Job...\n",
621                ntohl (sets->set_count));
622
623     if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
624                                                   (const char*)&sets[1],
625                                                   ntohl(sets->set_count),
626                                                   set))
627     {
628       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629                   "Failed to deserialize!\n");
630       continue;
631     }
632     dq_entry = GNUNET_new (struct DelegationQueueEntry);
633     dq_entry->required_solutions = ntohl(sets->set_count);
634     dq_entry->parent_set = current_set;
635     GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
636                                  current_set->queue_entries_tail,
637                                  dq_entry);
638     // Each AND
639     for (j=0; j<ntohl(sets->set_count); j++)
640     {
641       ds_entry = GNUNET_new (struct DelegationSetEntry);
642       if (NULL != current_set->attr_trailer)
643       {
644         if (0 == set[j].subject_attribute_len)
645         {
646           GNUNET_asprintf (&expanded_attr,
647                            "%s",
648                            current_set->attr_trailer);
649
650         } else {
651           GNUNET_asprintf (&expanded_attr,
652                            "%s.%s",
653                            set[j].subject_attribute,
654                            current_set->attr_trailer);
655         }
656         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
657                     "Expanded to %s\n", expanded_attr);
658         ds_entry->unresolved_attribute_delegation = expanded_attr;
659       } else {
660         if (0 != set[j].subject_attribute_len)
661         {
662           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
663                       "Not Expanding %s\n", set[j].subject_attribute);
664           ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
665         }
666       }
667
668       //Add a credential chain entry
669       ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
670       ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
671       ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
672       GNUNET_memcpy (ds_entry->issuer_key,
673                      &set[j].subject_key,
674                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
675       if (0 < set[j].subject_attribute_len)
676         ds_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup (set[j].subject_attribute);
677       ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
678       ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
679
680       ds_entry->parent_queue_entry = dq_entry; //current_delegation;
681       GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
682                                    dq_entry->set_entries_tail,
683                                    ds_entry);
684
685       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
686                   "Checking for cred match\n");
687       /**
688        * Check if this delegation already matches one of our credentials
689        */
690       for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
691           cred_pointer = cred_pointer->next)
692       {
693         cred = cred_pointer->data;
694         if(0 != memcmp (&set->subject_key, 
695                         &cred_pointer->data->issuer_key,
696                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
697           continue;
698         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
699                     "Checking if %s matches %s\n",
700                     ds_entry->unresolved_attribute_delegation, (char*)&cred[1]);
701
702         if (0 != strcmp (ds_entry->unresolved_attribute_delegation, (char*)&cred[1]))
703           continue;
704
705         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
706                     "Found issuer\n");
707
708         //Backtrack
709         for (tmp_set = ds_entry;
710              NULL != tmp_set->parent_queue_entry;
711              tmp_set = tmp_set->parent_queue_entry->parent_set)
712         {
713           tmp_set->parent_queue_entry->required_solutions--;
714           if (NULL != tmp_set->delegation_chain_entry)
715           {
716             vrh->delegation_chain_size++;
717             GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
718                                          vrh->delegation_chain_tail,
719                                          tmp_set->delegation_chain_entry);
720           }
721           if (0 < tmp_set->parent_queue_entry->required_solutions)
722             break;
723         }
724
725         if (NULL == tmp_set->parent_queue_entry)
726         {
727           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
728                       "All solutions found\n");
729           vrh->credential = GNUNET_malloc (cred_pointer->data_size);
730           memcpy (vrh->credential,
731                   cred,
732                   cred_pointer->data_size);
733           vrh->credential_size = cred_pointer->data_size;
734           //Found match
735           send_lookup_response (vrh);
736           return;
737         }
738
739       }
740       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
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_ERROR,
763                   "Looking up %s\n", ds_entry->lookup_attribute);
764       if (NULL != ds_entry->attr_trailer)
765         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
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                                                     NULL, //shorten_key, always NULL
776                                                     &backward_resolution,
777                                                     ds_entry);
778       GNUNET_free (lookup_attribute);
779     }
780   }
781
782   if(0 == vrh->pending_lookups)
783   {
784     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
785                 "We are all out of attributes...\n");
786     send_lookup_response (vrh);
787     return;
788
789   }
790
791
792
793 /**
794  * Result from GNS lookup.
795  *
796  * @param cls the closure (our client lookup handle)
797  * @param rd_count the number of records in @a rd
798  * @param rd the record data
799  */
800 static void
801 handle_credential_query (void* cls,
802                          uint32_t rd_count,
803                          const struct GNUNET_GNSRECORD_Data *rd)
804 {
805   struct VerifyRequestHandle *vrh = cls;
806   struct DelegationSetEntry *ds_entry;
807   const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
808   struct CredentialRecordEntry *cr_entry;
809   int cred_record_count;
810   int i;
811
812   vrh->lookup_request = NULL;
813   cred_record_count = 0;
814   for (i=0; i < rd_count; i++)
815   {
816     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
817       continue;
818     cred_record_count++;
819     crd = rd[i].data;
820     if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
821                                                &crd->purpose,
822                                                &crd->signature,
823                                                &crd->issuer_key))
824     {
825       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
826                   "Invalid credential found\n");
827       continue;
828     }
829     cr_entry = GNUNET_new (struct CredentialRecordEntry);
830     cr_entry->data = GNUNET_malloc (rd[i].data_size);
831     memcpy (cr_entry->data,
832             crd,
833             rd[i].data_size);
834     cr_entry->data_size = rd[i].data_size;
835     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
836                                       vrh->cred_chain_tail,
837                                       cr_entry);
838
839     if (0 != memcmp (&crd->issuer_key,
840                      &vrh->issuer_key,
841                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
842       continue;
843     if (0 != strcmp ((char*)&crd[1], vrh->issuer_attribute))
844       continue;
845     vrh->credential = GNUNET_malloc (rd[i].data_size);
846     memcpy (vrh->credential,
847             rd[i].data,
848             rd[i].data_size);
849     vrh->credential_size = rd[i].data_size;
850     //Found match prematurely
851     send_lookup_response (vrh);
852     return;
853
854   }
855
856   /**
857    * Check for attributes from the issuer and follow the chain 
858    * till you get the required subject's attributes
859    */
860   char issuer_attribute_name[strlen (vrh->issuer_attribute)];
861   strcpy (issuer_attribute_name,
862           vrh->issuer_attribute);
863   strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
864           ".gnu");
865   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866               "Looking up %s\n", issuer_attribute_name);
867   ds_entry = GNUNET_new (struct DelegationSetEntry);
868   ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
869   memcpy (ds_entry->issuer_key,
870           &vrh->issuer_key,
871           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
872   ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
873   ds_entry->handle = vrh;
874   ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
875   vrh->root_set = ds_entry;
876   vrh->pending_lookups = 1;
877   //Start with backward resolution
878   ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
879                                                 issuer_attribute_name,
880                                                 &vrh->issuer_key, //issuer_key,
881                                                 GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
882                                                 GNUNET_GNS_LO_DEFAULT,
883                                                 NULL, //shorten_key, always NULL
884                                                 &backward_resolution,
885                                                 ds_entry);
886 }
887
888
889 /**
890  * Handle Credential verification requests from client
891  *
892  * @param cls the closure
893  * @param client the client
894  * @param message the message
895  */
896 static void
897 handle_verify (void *cls,
898                const struct VerifyMessage *v_msg) 
899 {
900   char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
901   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
902   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1 + 4];
903   struct VerifyRequestHandle *vrh;
904   struct GNUNET_SERVICE_Client *client = cls;
905   char *attrptr = attrs;
906   const char *utf_in;
907
908   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
909               "Received VERIFY message\n");
910
911   utf_in = (const char *) &v_msg[1];
912   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
913
914   GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
915   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
916   GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
917   strcpy (subject_attribute+ntohs (v_msg->subject_attribute_len),
918           ".gnu");
919   subject_attribute[ntohs (v_msg->subject_attribute_len)+4] = '\0';
920   vrh = GNUNET_new (struct VerifyRequestHandle);
921   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
922   vrh->client = client;
923   vrh->request_id = v_msg->id;
924   vrh->issuer_key = v_msg->issuer_key;
925   vrh->subject_key = v_msg->subject_key;
926   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
927
928   if (NULL == subject_attribute)
929   {
930     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
931                 "No subject attribute provided!\n");
932     send_lookup_response (vrh);
933     return;
934   }
935   if (NULL == issuer_attribute)
936   {
937     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
938                 "No issuer attribute provided!\n");
939     send_lookup_response (vrh);
940     return;
941   }
942   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
943               "Looking up %s\n",
944               subject_attribute);
945   /**
946    * First, get attribute from subject
947    */
948   vrh->lookup_request = GNUNET_GNS_lookup (gns,
949                                            subject_attribute,
950                                            &v_msg->subject_key, //subject_pkey,
951                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
952                                            GNUNET_GNS_LO_DEFAULT,
953                                            NULL, //shorten_key, always NULL
954                                            &handle_credential_query,
955                                            vrh);
956 }
957
958
959 /**
960  * One of our clients disconnected, clean up after it.
961  *
962  * @param cls NULL
963  * @param client the client that disconnected
964  */
965 static void
966 client_disconnect_cb (void *cls,
967                       struct GNUNET_SERVICE_Client *client,
968                       void *app_ctx)
969 {
970   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
971               "Client %p disconnected\n",
972               client);
973 }
974
975 /**
976  * Add a client to our list of active clients.
977  *
978  * @param cls NULL
979  * @param client client to add
980  * @param mq message queue for @a client
981  * @return this client
982  */
983 static void *
984 client_connect_cb (void *cls,
985                    struct GNUNET_SERVICE_Client *client,
986                    struct GNUNET_MQ_Handle *mq)
987 {
988   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
989               "Client %p connected\n",
990               client);
991   return client;
992 }
993
994 /**
995  * Process Credential requests.
996  *
997  * @param cls closure
998  * @param server the initialized server
999  * @param c configuration to use
1000  */
1001 static void
1002 run (void *cls,
1003      const struct GNUNET_CONFIGURATION_Handle *c,
1004      struct GNUNET_SERVICE_Handle *handle)
1005 {
1006
1007   gns = GNUNET_GNS_connect (c);
1008   if (NULL == gns)
1009   {
1010     fprintf (stderr,
1011              _("Failed to connect to GNS\n"));
1012   }
1013
1014   statistics = GNUNET_STATISTICS_create ("credential", c);
1015   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1016 }
1017
1018
1019 /**
1020  * Define "main" method using service macro
1021  */
1022 GNUNET_SERVICE_MAIN
1023 ("credential",
1024  GNUNET_SERVICE_OPTION_NONE,
1025  &run,
1026  &client_connect_cb,
1027  &client_disconnect_cb,
1028  NULL,
1029  GNUNET_MQ_hd_var_size (verify,
1030                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1031                         struct VerifyMessage,
1032                         NULL),
1033  GNUNET_MQ_handler_end());
1034
1035 /* end of gnunet-service-credential.c */