Style fixes (mostly tabs to spaces).
[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 credential/gnunet-service-credential.c
22  * @brief GNUnet Credential Service (main service)
23  * @author Martin Schanzenbach
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    * Number of references in delegation chains
98    */
99   uint32_t refcount;
100
101   /**
102    * Payload
103    */
104   struct GNUNET_CREDENTIAL_Credential *credential;
105 };
106
107 /**
108  * DLL used for delegations
109  * Used for OR delegations
110  */
111 struct DelegationQueueEntry
112 {
113   /**
114    * DLL
115    */
116   struct DelegationQueueEntry *next;
117
118   /**
119    * DLL
120    */
121   struct DelegationQueueEntry *prev;
122
123   /**
124    * Sets under this Queue
125    */
126   struct DelegationSetQueueEntry *set_entries_head;
127
128   /**
129    * Sets under this Queue
130    */
131   struct DelegationSetQueueEntry *set_entries_tail;
132
133   /**
134    * Parent set
135    */
136   struct DelegationSetQueueEntry *parent_set;
137
138   /**
139    * Required solutions
140    */
141   uint32_t required_solutions;
142 };
143
144 /**
145  * DLL for delegation sets
146  * Used for AND delegation set
147  */
148 struct DelegationSetQueueEntry
149 {
150   /**
151    * DLL
152    */
153   struct DelegationSetQueueEntry *next;
154
155   /**
156    * DLL
157    */
158   struct DelegationSetQueueEntry *prev;
159
160     /**
161    * GNS handle
162    */
163   struct GNUNET_GNS_LookupRequest *lookup_request;
164
165   /**
166    * Verify handle
167    */
168   struct VerifyRequestHandle *handle;
169
170   /**
171    * Parent attribute delegation
172    */
173   struct DelegationQueueEntry *parent;
174
175   /**
176    * Issuer key
177    */
178   struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
179
180   /**
181    * Queue entries of this set
182    */
183   struct DelegationQueueEntry *queue_entries_head;
184
185   /**
186    * Queue entries of this set
187    */
188   struct DelegationQueueEntry *queue_entries_tail;
189
190   /**
191    * Parent QueueEntry
192    */
193   struct DelegationQueueEntry *parent_queue_entry;
194
195   /**
196    * Issuer attribute delegated to
197    */
198   char *issuer_attribute;
199
200   /**
201    * The current attribute to look up
202    */
203   char *lookup_attribute;
204
205   /**
206    * Trailing attribute context
207    */
208   char *attr_trailer;
209
210   /**
211    * Still to resolve delegation as string
212    */
213   char *unresolved_attribute_delegation;
214
215   /**
216    * The delegation chain entry
217    */
218   struct DelegationChainEntry *delegation_chain_entry;
219
220 };
221
222
223 /**
224  * Handle to a lookup operation from api
225  */
226 struct VerifyRequestHandle
227 {
228
229   /**
230    * We keep these in a DLL.
231    */
232   struct VerifyRequestHandle *next;
233
234   /**
235    * We keep these in a DLL.
236    */
237   struct VerifyRequestHandle *prev;
238
239   /**
240    * Handle to the requesting client
241    */
242   struct GNUNET_SERVICE_Client *client;
243
244   /**
245    * GNS handle
246    */
247   struct GNUNET_GNS_LookupRequest *lookup_request;
248
249   /**
250    * Size of delegation tree
251    */
252   uint32_t delegation_chain_size;
253
254   /**
255    * Children of this attribute
256    */
257   struct DelegationChainEntry *delegation_chain_head;
258
259   /**
260    * Children of this attribute
261    */
262   struct DelegationChainEntry *delegation_chain_tail;
263
264   /**
265    * Issuer public key
266    */
267   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
268
269   /**
270    * Issuer attribute
271    */
272   char *issuer_attribute;
273
274   /**
275    * Subject public key
276    */
277   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
278
279   /**
280    * Credential DLL
281    */
282   struct CredentialRecordEntry *cred_chain_head;
283
284   /**
285    * Credential DLL
286    */
287   struct CredentialRecordEntry *cred_chain_tail;
288
289   /**
290    * Credential DLL size
291    */
292   uint32_t cred_chain_size;
293
294   /**
295    * Root Delegation Set
296    */
297   struct DelegationSetQueueEntry *root_set;
298
299   /**
300    * Current Delegation Pointer
301    */
302   struct DelegationQueueEntry *current_delegation;
303
304   /**
305    * request id
306    */
307   uint32_t request_id;
308
309   /**
310    * Pending lookups
311    */
312   uint64_t pending_lookups;
313
314   /**
315    * Credential iterator
316    */
317   struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
318
319   /**
320    * Collect task
321    */
322   struct GNUNET_SCHEDULER_Task *collect_next_task;
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 /**
349  * Handle to namestore service
350  */
351 static struct GNUNET_NAMESTORE_Handle *namestore;
352
353 static void
354 cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
355 {
356   struct DelegationQueueEntry *dq_entry;
357   struct DelegationSetQueueEntry *child;
358
359   if (NULL == ds_entry)
360     return;
361
362   for (dq_entry = ds_entry->queue_entries_head;
363        NULL != dq_entry;
364        dq_entry = ds_entry->queue_entries_head)
365   {
366     GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
367                                  ds_entry->queue_entries_tail,
368                                  dq_entry);
369     for (child = dq_entry->set_entries_head;
370          NULL != child;
371          child = dq_entry->set_entries_head)
372     {
373       GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
374                                    dq_entry->set_entries_tail,
375                                    child);
376       cleanup_delegation_set (child);
377     }
378     GNUNET_free (dq_entry);
379   }
380   GNUNET_free_non_null (ds_entry->issuer_key);
381   GNUNET_free_non_null (ds_entry->lookup_attribute);
382   GNUNET_free_non_null (ds_entry->issuer_attribute);
383   GNUNET_free_non_null (ds_entry->unresolved_attribute_delegation);
384   GNUNET_free_non_null (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     GNUNET_free_non_null (ds_entry->delegation_chain_entry->subject_attribute);
393     GNUNET_free_non_null (ds_entry->delegation_chain_entry->issuer_attribute);
394     GNUNET_free (ds_entry->delegation_chain_entry);
395   }
396   GNUNET_free (ds_entry);
397 }
398
399 static void
400 cleanup_handle (struct VerifyRequestHandle *vrh)
401 {
402   struct CredentialRecordEntry *cr_entry;
403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404               "Cleaning up...\n");
405   if (NULL != vrh->lookup_request)
406   {
407     GNUNET_GNS_lookup_cancel (vrh->lookup_request);
408     vrh->lookup_request = NULL;
409   }
410   cleanup_delegation_set (vrh->root_set);
411   GNUNET_free_non_null (vrh->issuer_attribute);
412   for (cr_entry = vrh->cred_chain_head; 
413        NULL != vrh->cred_chain_head;
414        cr_entry = vrh->cred_chain_head)
415   {
416     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
417                                  vrh->cred_chain_tail,
418                                  cr_entry);
419     GNUNET_free_non_null (cr_entry->credential);
420     GNUNET_free (cr_entry);
421   }
422   GNUNET_free (vrh);
423 }
424
425 static void
426 shutdown_task (void *cls)
427 {
428   struct VerifyRequestHandle *vrh;
429
430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431               "Shutting down!\n");
432
433   while (NULL != (vrh = vrh_head))
434   {
435     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
436     GNUNET_CONTAINER_DLL_remove (vrh_head,
437                                  vrh_tail,
438                                  vrh);
439     cleanup_handle (vrh);
440   }
441
442   if (NULL != gns)
443   {
444     GNUNET_GNS_disconnect (gns);
445     gns = NULL;
446   }
447   if (NULL != namestore)
448   {
449     GNUNET_NAMESTORE_disconnect (namestore);
450     namestore = NULL;
451   }
452   if (NULL != statistics)
453   {
454     GNUNET_STATISTICS_destroy (statistics,
455                                GNUNET_NO);
456     statistics = NULL;
457   }
458
459 }
460
461
462
463 static void
464 send_lookup_response (struct VerifyRequestHandle *vrh)
465 {
466   struct GNUNET_MQ_Envelope *env;
467   struct DelegationChainResultMessage *rmsg;
468   struct DelegationChainEntry *dce;
469   struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
470   struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
471   struct CredentialRecordEntry *cd;
472   struct CredentialRecordEntry *tmp;
473   size_t size;
474
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476               "Sending response\n");
477   dce = vrh->delegation_chain_head;
478   for (uint32_t i=0;i<vrh->delegation_chain_size;i++)
479   {
480     dd[i].issuer_key = dce->issuer_key;
481     dd[i].subject_key = dce->subject_key;
482     dd[i].issuer_attribute = dce->issuer_attribute;
483     dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
484     dd[i].subject_attribute_len = 0;
485     dd[i].subject_attribute = NULL;
486     if (NULL != dce->subject_attribute)
487     {
488       dd[i].subject_attribute = dce->subject_attribute;
489       dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
490     }
491     dce = dce->next;
492   }
493
494   /**
495    * Remove all credentials not needed
496    */
497   for (cd = vrh->cred_chain_head; NULL != cd;)
498   {
499     if (cd->refcount > 0)
500     {
501       cd = cd->next;
502       continue;
503     }
504     tmp = cd;
505     cd = cd->next;
506     GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
507                                  vrh->cred_chain_tail,
508                                  tmp);
509     GNUNET_free (tmp->credential);
510     GNUNET_free (tmp);
511     vrh->cred_chain_size--;
512   }
513
514   /**
515    * Get serialized record data
516    * Append at the end of rmsg
517    */
518   cd = vrh->cred_chain_head;
519   for (uint32_t i=0;i<vrh->cred_chain_size;i++)
520   {
521     cred[i].issuer_key = cd->credential->issuer_key;
522     cred[i].subject_key = cd->credential->subject_key;
523     cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
524     cred[i].issuer_attribute = cd->credential->issuer_attribute;
525     cred[i].expiration = cd->credential->expiration;
526     cred[i].signature = cd->credential->signature;
527     cd = cd->next;
528   }
529   size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
530                                                       dd,
531                                                       vrh->cred_chain_size,
532                                                       cred);
533   env = GNUNET_MQ_msg_extra (rmsg,
534                              size,
535                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
536   //Assign id so that client can find associated request
537   rmsg->id = vrh->request_id;
538   rmsg->d_count = htonl (vrh->delegation_chain_size);
539   rmsg->c_count = htonl (vrh->cred_chain_size);
540
541   if (0 < vrh->cred_chain_size)
542     rmsg->cred_found = htonl (GNUNET_YES);
543   else
544     rmsg->cred_found = htonl (GNUNET_NO);
545
546   GNUNET_assert (-1 != 
547                  GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
548                                                                dd,
549                                                                vrh->cred_chain_size,
550                                                                cred,
551                                                                size,
552                                                                (char*)&rmsg[1]));
553
554   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
555                   env);
556   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
557   cleanup_handle(vrh);
558
559   GNUNET_STATISTICS_update (statistics,
560                             "Completed verifications", 1,
561                             GNUNET_NO);
562 }
563
564
565 static void
566 backward_resolution (void* cls,
567                      uint32_t rd_count,
568                      const struct GNUNET_GNSRECORD_Data *rd)
569 {
570
571   struct VerifyRequestHandle *vrh;
572   const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
573   struct CredentialRecordEntry *cred_pointer;
574   struct DelegationSetQueueEntry *current_set;
575   struct DelegationSetQueueEntry *ds_entry;
576   struct DelegationSetQueueEntry *tmp_set;
577   struct DelegationQueueEntry *dq_entry;
578   char *expanded_attr;
579   char *lookup_attribute;
580
581
582   current_set = cls;
583   current_set->lookup_request = NULL;
584   vrh = current_set->handle;
585   vrh->pending_lookups--;
586   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587               "Got %d attrs\n", rd_count);
588
589   // Each OR
590   for (uint32_t i=0; i < rd_count; i++) 
591   {
592     if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
593       continue;
594
595     sets = rd[i].data;
596     struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
597     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598                 "Found new attribute delegation with %d sets. Creating new Job...\n",
599                 ntohl (sets->set_count));
600
601     if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
602                                                                   (const char*)&sets[1],
603                                                                   ntohl(sets->set_count),
604                                                                   set))
605     {
606       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
607                   "Failed to deserialize!\n");
608       continue;
609     }
610     dq_entry = GNUNET_new (struct DelegationQueueEntry);
611     dq_entry->required_solutions = ntohl(sets->set_count);
612     dq_entry->parent_set = current_set;
613     GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
614                                  current_set->queue_entries_tail,
615                                  dq_entry);
616     // Each AND
617     for (uint32_t j=0; j<ntohl(sets->set_count); j++)
618     {
619       ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
620       if (NULL != current_set->attr_trailer)
621       {
622         if (0 == set[j].subject_attribute_len)
623         {
624           GNUNET_asprintf (&expanded_attr,
625                            "%s",
626                            current_set->attr_trailer);
627
628         } else {
629           GNUNET_asprintf (&expanded_attr,
630                            "%s.%s",
631                            set[j].subject_attribute,
632                            current_set->attr_trailer);
633         }
634         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635                     "Expanded to %s\n", expanded_attr);
636         ds_entry->unresolved_attribute_delegation = expanded_attr;
637       } else {
638         if (0 != set[j].subject_attribute_len)
639         {
640           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
641                       "Not Expanding %s\n", set[j].subject_attribute);
642           ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
643         }
644       }
645
646       //Add a credential chain entry
647       ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
648       ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
649       ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
650       GNUNET_memcpy (ds_entry->issuer_key,
651                      &set[j].subject_key,
652                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
653       if (0 < set[j].subject_attribute_len)
654         ds_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup (set[j].subject_attribute);
655       ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
656       ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
657
658       ds_entry->parent_queue_entry = dq_entry; //current_delegation;
659       GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
660                                    dq_entry->set_entries_tail,
661                                    ds_entry);
662
663       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664                   "Checking for cred match\n");
665       /**
666        * Check if this delegation already matches one of our credentials
667        */
668       for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
669           cred_pointer = cred_pointer->next)
670       {
671         if(0 != memcmp (&set->subject_key, 
672                         &cred_pointer->credential->issuer_key,
673                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
674           continue;
675         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676                     "Checking if %s matches %s\n",
677                     ds_entry->unresolved_attribute_delegation,
678                     cred_pointer->credential->issuer_attribute);
679
680         if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
681                          cred_pointer->credential->issuer_attribute))
682           continue;
683
684         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
685                     "Found issuer\n");
686         cred_pointer->refcount++;
687         //Backtrack
688         for (tmp_set = ds_entry;
689              NULL != tmp_set->parent_queue_entry;
690              tmp_set = tmp_set->parent_queue_entry->parent_set)
691         {
692           tmp_set->parent_queue_entry->required_solutions--;
693           if (NULL != tmp_set->delegation_chain_entry)
694           {
695             vrh->delegation_chain_size++;
696             GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
697                                          vrh->delegation_chain_tail,
698                                          tmp_set->delegation_chain_entry);
699           }
700           if (0 < tmp_set->parent_queue_entry->required_solutions)
701             break;
702         }
703
704         if (NULL == tmp_set->parent_queue_entry)
705         {
706           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707                       "All solutions found\n");
708           //Found match
709           send_lookup_response (vrh);
710           return;
711         }
712         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713                     "Not all solutions found yet.\n");
714         continue;
715
716       }
717       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718                   "Building new lookup request from %s\n",
719                   ds_entry->unresolved_attribute_delegation);
720       //Continue with backward resolution
721       char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
722       strcpy (issuer_attribute_name,
723               ds_entry->unresolved_attribute_delegation);
724       char *next_attr = strtok (issuer_attribute_name, ".");
725       GNUNET_asprintf (&lookup_attribute,
726                        "%s.gnu",
727                        next_attr);
728       GNUNET_asprintf (&ds_entry->lookup_attribute,
729                        "%s",
730                        next_attr);
731       if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
732       {
733         ds_entry->attr_trailer = NULL;
734       } else {
735         next_attr += strlen (next_attr) + 1;
736         ds_entry->attr_trailer = GNUNET_strdup (next_attr);
737       }
738
739       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740                   "Looking up %s\n", ds_entry->lookup_attribute);
741       if (NULL != ds_entry->attr_trailer)
742         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
743                     "%s still to go...\n", ds_entry->attr_trailer);
744
745       vrh->pending_lookups++;
746       ds_entry->handle = vrh;
747       ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
748                                                     lookup_attribute,
749                                                     ds_entry->issuer_key, //issuer_key,
750                                                     GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
751                                                     GNUNET_GNS_LO_DEFAULT,
752                                                     &backward_resolution,
753                                                     ds_entry);
754       GNUNET_free (lookup_attribute);
755     }
756   }
757
758   if(0 == vrh->pending_lookups)
759   {
760     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761                 "We are all out of attributes...\n");
762     send_lookup_response (vrh);
763     return;
764
765   }
766
767
768
769 /**
770  * Result from GNS lookup.
771  *
772  * @param cls the closure (our client lookup handle)
773  */
774 static void
775 delegation_chain_resolution_start (void* cls)
776 {
777   struct VerifyRequestHandle *vrh = cls;
778   struct DelegationSetQueueEntry *ds_entry;
779   struct CredentialRecordEntry *cr_entry;
780   vrh->lookup_request = NULL;
781
782   if (0 == vrh->cred_chain_size)
783   {
784     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
785                 "No credentials found\n");
786     send_lookup_response (vrh);
787     return;
788   }
789
790   for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next)
791   {
792     if (0 != memcmp (&cr_entry->credential->issuer_key,
793                      &vrh->issuer_key,
794                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
795       continue;
796     if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute))
797       continue;
798     cr_entry->refcount++;
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                                                 &backward_resolution,
833                                                 ds_entry);
834 }
835
836 static int
837 check_verify (void *cls,
838               const struct VerifyMessage *v_msg)
839 {
840   size_t msg_size;
841   const char* attr;
842
843   msg_size = ntohs (v_msg->header.size);
844   if (msg_size < sizeof (struct VerifyMessage))
845   {
846     GNUNET_break (0);
847     return GNUNET_SYSERR;
848   }
849   if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
850   {
851     GNUNET_break (0);
852     return GNUNET_SYSERR;
853   }
854   attr = (const char *) &v_msg[1];
855
856   if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
857   {
858     GNUNET_break (0);
859     return GNUNET_SYSERR;
860   }
861   return GNUNET_OK;
862 }
863
864 static void
865 handle_verify (void *cls,
866                const struct VerifyMessage *v_msg) 
867 {
868   struct VerifyRequestHandle *vrh;
869   struct GNUNET_SERVICE_Client *client = cls;
870   struct CredentialRecordEntry *cr_entry;
871   uint32_t credentials_count;
872   uint32_t credential_data_size;
873   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
874   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
875   char *attrptr = attr;
876   char *credential_data;
877   const char *utf_in;
878
879   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880               "Received VERIFY message\n");
881   utf_in = (const char *) &v_msg[1];
882   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
883   GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
884   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
885   vrh = GNUNET_new (struct VerifyRequestHandle);
886   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
887   vrh->client = client;
888   vrh->request_id = v_msg->id;
889   vrh->issuer_key = v_msg->issuer_key;
890   vrh->subject_key = v_msg->subject_key;
891   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
892   if (NULL == issuer_attribute)
893   {
894     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
895                 "No issuer attribute provided!\n");
896     send_lookup_response (vrh);
897     return;
898   }
899   /**
900    * First, collect credentials
901    * TODO: cleanup!
902    */
903   credentials_count = ntohl(v_msg->c_count);
904   credential_data_size = ntohs (v_msg->header.size) 
905     - sizeof (struct VerifyMessage)
906     - ntohs (v_msg->issuer_attribute_len)
907     - 1;
908   struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
909   credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
910   if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
911                                                               credential_data,
912                                                               credentials_count,
913                                                               credentials))
914   {
915     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
916                 "Cannot deserialize credentials!\n");
917     send_lookup_response (vrh);
918     return;
919   }
920
921   for (uint32_t i=0;i<credentials_count;i++) {
922     cr_entry = GNUNET_new (struct CredentialRecordEntry);
923     cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
924                                           credentials[i].issuer_attribute_len);
925     GNUNET_memcpy (cr_entry->credential,
926                    &credentials[i],
927                    sizeof (struct GNUNET_CREDENTIAL_Credential));
928     GNUNET_memcpy (&cr_entry->credential[1],
929                    credentials[i].issuer_attribute,
930                    credentials[i].issuer_attribute_len);
931     cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
932     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
933                                       vrh->cred_chain_tail,
934                                       cr_entry);
935     vrh->cred_chain_size++;
936   }
937
938   delegation_chain_resolution_start (vrh);
939
940 }
941
942 static void
943 handle_cred_collection_error_cb (void *cls)
944 {
945   struct VerifyRequestHandle *vrh = cls;
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947               "Got disconnected from namestore database.\n");
948   vrh->cred_collection_iter = NULL;
949   send_lookup_response (vrh);
950 }
951
952 static void
953 collect_next (void *cls)
954 {
955   struct VerifyRequestHandle *vrh = cls;
956   vrh->collect_next_task = NULL;
957   GNUNET_assert (NULL != vrh->cred_collection_iter);
958   GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
959 }
960
961 static void
962 handle_cred_collection_cb (void *cls,
963                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
964                            const char *label,
965                            unsigned int rd_count,
966                            const struct GNUNET_GNSRECORD_Data *rd)
967 {
968   struct VerifyRequestHandle *vrh = cls;
969   struct GNUNET_CREDENTIAL_Credential *crd;
970   struct CredentialRecordEntry *cr_entry;
971   int cred_record_count;
972
973   cred_record_count = 0;
974   for (uint32_t i=0; i < rd_count; i++)
975   {
976     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
977       continue;
978     cred_record_count++;
979     crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
980                                                     rd[i].data_size);
981     if (NULL == crd)
982     {
983       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
984                   "Invalid credential found\n");
985       continue;
986     }
987     cr_entry = GNUNET_new (struct CredentialRecordEntry);
988     cr_entry->credential = crd;
989     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
990                                       vrh->cred_chain_tail,
991                                       cr_entry);
992     vrh->cred_chain_size++;
993   }
994   vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
995                                                      vrh);
996 }
997
998 static void
999 handle_cred_collection_finished_cb (void *cls)
1000 {
1001   struct VerifyRequestHandle *vrh = cls;
1002   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1003               "Done collecting credentials.\n");
1004   vrh->cred_collection_iter = NULL;
1005   delegation_chain_resolution_start (vrh);
1006 }
1007
1008 static void
1009 handle_collect (void *cls,
1010                 const struct CollectMessage *c_msg) 
1011 {
1012   char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1013   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
1014   struct VerifyRequestHandle *vrh;
1015   struct GNUNET_SERVICE_Client *client = cls;
1016   char *attrptr = attr;
1017   const char *utf_in;
1018
1019   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1020               "Received COLLECT message\n");
1021
1022   utf_in = (const char *) &c_msg[1];
1023   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
1024
1025   GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
1026   issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
1027   vrh = GNUNET_new (struct VerifyRequestHandle);
1028   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
1029   vrh->client = client;
1030   vrh->request_id = c_msg->id;
1031   vrh->issuer_key = c_msg->issuer_key;
1032   GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
1033                                       &vrh->subject_key);
1034   vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
1035
1036   if (NULL == issuer_attribute)
1037   {
1038     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1039                 "No issuer attribute provided!\n");
1040     send_lookup_response (vrh);
1041     return;
1042   }
1043   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1044               "Getting credentials for subject\n");
1045   /**
1046    * First, get attribute from subject
1047    */
1048   vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
1049                                                                      &c_msg->subject_key,
1050                                                                      &handle_cred_collection_error_cb,
1051                                                                      vrh,
1052                                                                      &handle_cred_collection_cb,
1053                                                                      vrh,
1054                                                                      &handle_cred_collection_finished_cb,
1055                                                                      vrh);
1056 }
1057
1058
1059 static int
1060 check_collect (void *cls,
1061                const struct CollectMessage *c_msg)
1062 {
1063   size_t msg_size;
1064   const char* attr;
1065
1066   msg_size = ntohs (c_msg->header.size);
1067   if (msg_size < sizeof (struct CollectMessage))
1068   {
1069     GNUNET_break (0);
1070     return GNUNET_SYSERR;
1071   }
1072   if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
1073   {
1074     GNUNET_break (0);
1075     return GNUNET_SYSERR;
1076   }
1077   attr = (const char *) &c_msg[1];
1078
1079   if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
1080        (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
1081   {
1082     GNUNET_break (0);
1083     return GNUNET_SYSERR;
1084   }
1085   return GNUNET_OK;
1086 }
1087
1088 static void
1089 client_disconnect_cb (void *cls,
1090                       struct GNUNET_SERVICE_Client *client,
1091                       void *app_ctx)
1092 {
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094               "Client %p disconnected\n",
1095               client);
1096 }
1097
1098 static void *
1099 client_connect_cb (void *cls,
1100                    struct GNUNET_SERVICE_Client *client,
1101                    struct GNUNET_MQ_Handle *mq)
1102 {
1103   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104               "Client %p connected\n",
1105               client);
1106   return client;
1107 }
1108
1109 /**
1110  * Process Credential requests.
1111  *
1112  * @param cls closure
1113  * @param c configuration to use
1114  * @param handle service handle
1115  */
1116 static void
1117 run (void *cls,
1118      const struct GNUNET_CONFIGURATION_Handle *c,
1119      struct GNUNET_SERVICE_Handle *handle)
1120 {
1121
1122   gns = GNUNET_GNS_connect (c);
1123   if (NULL == gns)
1124   {
1125     fprintf (stderr,
1126              _("Failed to connect to GNS\n"));
1127   }
1128   namestore = GNUNET_NAMESTORE_connect (c);
1129   if (NULL == namestore)
1130   {
1131     fprintf (stderr,
1132              _("Failed to connect to namestore\n"));
1133   }
1134
1135   statistics = GNUNET_STATISTICS_create ("credential", c);
1136   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1137 }
1138
1139
1140 /**
1141  * Define "main" method using service macro
1142  */
1143 GNUNET_SERVICE_MAIN
1144 ("credential",
1145  GNUNET_SERVICE_OPTION_NONE,
1146  &run,
1147  &client_connect_cb,
1148  &client_disconnect_cb,
1149  NULL,
1150  GNUNET_MQ_hd_var_size (verify,
1151                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
1152                         struct VerifyMessage,
1153                         NULL),
1154  GNUNET_MQ_hd_var_size (collect,
1155                         GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
1156                         struct CollectMessage,
1157                         NULL),
1158  GNUNET_MQ_handler_end());
1159
1160 /* end of gnunet-service-credential.c */