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