4841370b350931118a5d9fecb4be724b504d0629
[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   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
884   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
885   struct VerifyRequestHandle *vrh;
886   struct GNUNET_SERVICE_Client *client = cls;
887   char *attrptr = attr;
888   const char *utf_in;
889
890   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891               "Received VERIFY message\n");
892
893   utf_in = (const char *) &v_msg[1];
894   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
895
896   GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
897   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
898   vrh = GNUNET_new (struct VerifyRequestHandle);
899   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
900   vrh->client = client;
901   vrh->request_id = v_msg->id;
902   vrh->issuer_key = v_msg->issuer_key;
903   vrh->subject_key = v_msg->subject_key;
904   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
905   if (NULL == issuer_attribute)
906   {
907     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
908                 "No issuer attribute provided!\n");
909     send_lookup_response (vrh);
910     return;
911   }
912   /**
913    * First, collect credentials
914    * TODO: cleanup!
915    */
916   uint32_t credentials_count = ntohl(v_msg->c_count);
917   int i;
918   uint32_t credential_data_size = ntohs (v_msg->header.size) 
919     - sizeof (struct VerifyMessage)
920     - ntohs (v_msg->issuer_attribute_len)
921     - 1;
922   struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
923   char *credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
924   struct CredentialRecordEntry *cr_entry;
925   if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
926                                                               credential_data,
927                                                               credentials_count,
928                                                               credentials))
929   {
930     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
931                 "Cannot deserialize credentials!\n");
932     send_lookup_response (vrh);
933     return;
934   }
935
936   for (i=0;i<credentials_count;i++) {
937     cr_entry = GNUNET_new (struct CredentialRecordEntry);
938     cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
939                                           strlen (credentials[i].issuer_attribute) + 1);
940     GNUNET_memcpy (cr_entry->credential,
941                    &credentials[i],
942                    sizeof (struct GNUNET_CREDENTIAL_Credential));
943     GNUNET_memcpy (&cr_entry->credential[1],
944                    credentials[i].issuer_attribute,
945                    strlen (credentials[i].issuer_attribute));
946     cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
947     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
948                                       vrh->cred_chain_tail,
949                                       cr_entry);
950     vrh->cred_chain_size++;
951   }
952
953   delegation_chain_resolution_start (vrh);
954
955 }
956
957 /**
958  * We encountered an error while collecting
959  */
960 static void
961 handle_cred_collection_error_cb (void *cls)
962 {
963   struct VerifyRequestHandle *vrh = cls;
964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965               "Got disconnected from namestore database.\n");
966   vrh->cred_collection_iter = NULL;
967   send_lookup_response (vrh);
968 }
969
970 static void
971 collect_next (void *cls)
972 {
973   struct VerifyRequestHandle *vrh = cls;
974   vrh->collect_next_task = NULL;
975   GNUNET_assert (NULL != vrh->cred_collection_iter);
976   GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
977 }
978
979 /**
980  * Store credential
981  */
982 static void
983 handle_cred_collection_cb (void *cls,
984                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
985                            const char *label,
986                            unsigned int rd_count,
987                            const struct GNUNET_GNSRECORD_Data *rd)
988 {
989   struct VerifyRequestHandle *vrh = cls;
990   struct GNUNET_CREDENTIAL_Credential *crd;
991   struct CredentialRecordEntry *cr_entry;
992   int cred_record_count;
993   int i;
994
995   cred_record_count = 0;
996   for (i=0; i < rd_count; i++)
997   {
998     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
999       continue;
1000     cred_record_count++;
1001     crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
1002                                                     rd[i].data_size);
1003     if (NULL == crd)
1004     {
1005       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1006                   "Invalid credential found\n");
1007       continue;
1008     }
1009     cr_entry = GNUNET_new (struct CredentialRecordEntry);
1010     cr_entry->credential = crd;
1011     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
1012                                       vrh->cred_chain_tail,
1013                                       cr_entry);
1014     vrh->cred_chain_size++;
1015   }
1016   vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
1017                                                      vrh);
1018 }
1019
1020 /**
1021  * We encountered an error while collecting
1022  */
1023 static void
1024 handle_cred_collection_finished_cb (void *cls)
1025 {
1026   struct VerifyRequestHandle *vrh = cls;
1027   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1028               "Done collecting credentials.\n");
1029   vrh->cred_collection_iter = NULL;
1030   delegation_chain_resolution_start (vrh);
1031 }
1032
1033 /**
1034  * Handle Credential collection requests from client
1035  *
1036  * @param cls the closure
1037  * @param client the client
1038  * @param message the message
1039  */
1040 static void
1041 handle_collect (void *cls,
1042                 const struct CollectMessage *c_msg) 
1043 {
1044   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1045   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1046   struct VerifyRequestHandle *vrh;
1047   struct GNUNET_SERVICE_Client *client = cls;
1048   char *attrptr = attr;
1049   const char *utf_in;
1050
1051   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052               "Received COLLECT message\n");
1053
1054   utf_in = (const char *) &c_msg[1];
1055   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
1056
1057   GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
1058   issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
1059   vrh = GNUNET_new (struct VerifyRequestHandle);
1060   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
1061   vrh->client = client;
1062   vrh->request_id = c_msg->id;
1063   vrh->issuer_key = c_msg->issuer_key;
1064   GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
1065                                       &vrh->subject_key);
1066   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
1067
1068   if (NULL == issuer_attribute)
1069   {
1070     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1071                 "No issuer attribute provided!\n");
1072     send_lookup_response (vrh);
1073     return;
1074   }
1075   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076               "Getting credentials for subject\n");
1077   /**
1078    * First, get attribute from subject
1079    */
1080   vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
1081                                                                      &c_msg->subject_key,
1082                                                                      &handle_cred_collection_error_cb,
1083                                                                      vrh,
1084                                                                      &handle_cred_collection_cb,
1085                                                                      vrh,
1086                                                                      &handle_cred_collection_finished_cb,
1087                                                                      vrh);
1088 }
1089
1090
1091 /**
1092  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT message
1093  *
1094  * @param cls client sending the message
1095  * @param v_msg message of type `struct CollectMessage`
1096  * @return #GNUNET_OK if @a v_msg is well-formed
1097  */
1098 static int
1099 check_collect (void *cls,
1100                const struct CollectMessage *c_msg)
1101 {
1102   size_t msg_size;
1103   const char* attr;
1104
1105   msg_size = ntohs (c_msg->header.size);
1106   if (msg_size < sizeof (struct CollectMessage))
1107   {
1108     GNUNET_break (0);
1109     return GNUNET_SYSERR;
1110   }
1111   if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
1112   {
1113     GNUNET_break (0);
1114     return GNUNET_SYSERR;
1115   }
1116   attr = (const char *) &c_msg[1];
1117
1118   if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
1119        (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
1120   {
1121     GNUNET_break (0);
1122     return GNUNET_SYSERR;
1123   }
1124   return GNUNET_OK;
1125 }
1126
1127 /**
1128  * One of our clients disconnected, clean up after it.
1129  *
1130  * @param cls NULL
1131  * @param client the client that disconnected
1132  */
1133 static void
1134 client_disconnect_cb (void *cls,
1135                       struct GNUNET_SERVICE_Client *client,
1136                       void *app_ctx)
1137 {
1138   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139               "Client %p disconnected\n",
1140               client);
1141 }
1142
1143 /**
1144  * Add a client to our list of active clients.
1145  *
1146  * @param cls NULL
1147  * @param client client to add
1148  * @param mq message queue for @a client
1149  * @return this client
1150  */
1151 static void *
1152 client_connect_cb (void *cls,
1153                    struct GNUNET_SERVICE_Client *client,
1154                    struct GNUNET_MQ_Handle *mq)
1155 {
1156   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157               "Client %p connected\n",
1158               client);
1159   return client;
1160 }
1161
1162 /**
1163  * Process Credential requests.
1164  *
1165  * @param cls closure
1166  * @param server the initialized server
1167  * @param c configuration to use
1168  */
1169 static void
1170 run (void *cls,
1171      const struct GNUNET_CONFIGURATION_Handle *c,
1172      struct GNUNET_SERVICE_Handle *handle)
1173 {
1174
1175   gns = GNUNET_GNS_connect (c);
1176   if (NULL == gns)
1177   {
1178     fprintf (stderr,
1179              _("Failed to connect to GNS\n"));
1180   }
1181   namestore = GNUNET_NAMESTORE_connect (c);
1182   if (NULL == namestore)
1183   {
1184     fprintf (stderr,
1185              _("Failed to connect to namestore\n"));
1186   }
1187
1188   statistics = GNUNET_STATISTICS_create ("credential", c);
1189   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1190 }
1191
1192
1193 /**
1194  * Define "main" method using service macro
1195  */
1196 GNUNET_SERVICE_MAIN
1197 ("credential",
1198  GNUNET_SERVICE_OPTION_NONE,
1199  &run,
1200  &client_connect_cb,
1201  &client_disconnect_cb,
1202  NULL,
1203  GNUNET_MQ_hd_var_size (verify,
1204                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1205                         struct VerifyMessage,
1206                         NULL),
1207  GNUNET_MQ_hd_var_size (collect,
1208                         GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
1209                         struct CollectMessage,
1210                         NULL),
1211  GNUNET_MQ_handler_end());
1212
1213 /* end of gnunet-service-credential.c */