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