- minor fixes
[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 "gnunet_protocols.h"
31 #include "gnunet_signatures.h"
32
33 // For Looking up GNS request
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 #include "gnunet_gns_service.h"
40
41
42
43
44 #define GNUNET_CREDENTIAL_MAX_LENGTH 255
45
46 /**
47  * DLL for record
48  */
49 struct CredentialRecordEntry
50 {
51   /**
52    * DLL
53    */
54   struct CredentialRecordEntry *next;
55
56   /**
57    * DLL
58    */
59   struct CredentialRecordEntry *prev;
60
61
62   /**
63    * Payload
64    */
65   struct GNUNET_CREDENTIAL_CredentialRecordData record_data;
66 };
67
68 /**
69  * DLL for attributes - Used as a queue
70  * Insert tail - Pop head
71  */
72 struct AttributeRecordEntry
73 {
74   /**
75    * DLL
76    */
77   struct AttributeRecordEntry *next;
78
79   /**
80    * DLL
81    */
82   struct AttributeRecordEntry *prev;
83
84   /**
85    * Payload
86    */
87   struct GNUNET_CREDENTIAL_AttributeRecordData record_data;
88 };
89
90
91 /**
92  * Handle to a lookup operation from api
93  */
94 struct VerifyRequestHandle
95 {
96
97   /**
98    * We keep these in a DLL.
99    */
100   struct VerifyRequestHandle *next;
101
102   /**
103    * We keep these in a DLL.
104    */
105   struct VerifyRequestHandle *prev;
106
107   /**
108    * Handle to the requesting client
109    */
110   struct GNUNET_SERVICE_Client *client;
111
112   /**
113    * Handle to GNS lookup
114    */
115   struct GNUNET_GNS_LookupRequest *lookup_request;
116
117   /**
118    * Issuer public key
119    */
120   struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
121   
122   /**
123    * Issuer attribute
124    */
125   char *issuer_attribute;
126
127   /**
128    * Subject public key
129    */
130   struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
131
132   /**
133    * Credential Chain
134    */
135   struct CredentialRecordEntry *cred_chain_head;
136
137   /**
138    * Credential Chain
139    */
140   struct CredentialRecordEntry *cred_chain_tail;
141
142   /**
143    * Attribute Queue
144    */
145   struct AttributeRecordEntry *attr_queue_head;
146   
147   /**
148    * Attribute Queue
149    */
150   struct AttributeRecordEntry *attr_queue_tail;
151   
152   /**
153    * Current Attribute Pointer
154    */
155   struct AttributeRecordEntry* attr_pointer; 
156
157   /**
158    * request id
159    */
160   uint32_t request_id;
161
162 };
163
164
165 /**
166  * Head of the DLL.
167  */
168 static struct VerifyRequestHandle *vrh_head;
169
170 /**
171  * Tail of the DLL.
172  */
173 static struct VerifyRequestHandle *vrh_tail;
174
175 /**
176  * Handle to the statistics service
177  */
178 static struct GNUNET_STATISTICS_Handle *statistics;
179
180
181
182 /**
183  * Handle to GNS service.
184  */
185 static struct GNUNET_GNS_Handle *gns;
186
187 /**
188  * Task run during shutdown.
189  *
190  * @param cls unused
191  * @param tc unused
192  */
193 static void
194 shutdown_task (void *cls)
195 {
196   struct VerifyRequestHandle *vrh;
197   
198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
199               "Shutting down!\n");
200   while (NULL != (vrh = vrh_head))
201   {
202     //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
203     GNUNET_CONTAINER_DLL_remove (vrh_head,
204                                  vrh_tail,
205                                  vrh);
206     GNUNET_free (vrh);
207   }
208
209   
210   if (NULL != statistics)
211   {
212     GNUNET_STATISTICS_destroy (statistics,
213                                GNUNET_NO);
214     statistics = NULL;
215   }
216   
217 }
218
219 /**
220  * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
221  *
222  * @param cls client sending the message
223  * @param v_msg message of type `struct VerifyMessage`
224  * @return #GNUNET_OK if @a v_msg is well-formed
225  */
226 static int
227 check_verify (void *cls,
228                     const struct VerifyMessage *v_msg)
229 {
230   size_t msg_size;
231   const char* attrs;
232
233   msg_size = ntohs (v_msg->header.size);
234   if (msg_size < sizeof (struct VerifyMessage))
235   {
236     GNUNET_break (0);
237     return GNUNET_SYSERR;
238   }
239   if ((ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) ||
240       (ntohs (v_msg->subject_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH))
241   {
242     GNUNET_break (0);
243     return GNUNET_SYSERR;
244   }
245   attrs = (const char *) &v_msg[1];
246   
247   if ( ('\0' != attrs[ntohs(v_msg->header.size) - sizeof (struct VerifyMessage) - 1]) ||
248        (strlen (attrs) > GNUNET_CREDENTIAL_MAX_LENGTH * 2) )
249   {
250     GNUNET_break (0);
251     return GNUNET_SYSERR;
252   }
253   return GNUNET_OK;
254 }
255
256 static void
257 start_backward_resolution (void* cls,
258                            uint32_t rd_count,
259                            const struct GNUNET_GNSRECORD_Data *rd)
260 {
261   struct VerifyRequestHandle *vrh = cls;
262   int i;
263   struct GNUNET_CREDENTIAL_CredentialRecordData *cred;
264   struct GNUNET_CREDENTIAL_AttributeRecordData *attr;
265   struct CredentialRecordEntry *cred_pointer;  
266   const char *attribute;
267   const char *cred_attribute;
268
269   for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
270       cred_pointer = cred_pointer->next){
271     cred = &cred_pointer->record_data;
272
273     if(0 == memcmp (&vrh->attr_pointer->record_data.subject_key, 
274                    &cred_pointer->record_data.issuer_key,
275                    sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))){
276
277       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278                   "Found issuer\n");
279       
280     }
281     
282
283
284
285   }
286
287
288
289   //Start from next to head
290   vrh->attr_pointer = vrh->attr_pointer->next;
291
292
293
294   if(vrh->attr_pointer->next != NULL){
295     //Start with backward resolution
296     vrh->lookup_request = GNUNET_GNS_lookup (gns,
297                                              vrh->issuer_attribute,
298                                              &vrh->issuer_key, //issuer_key,
299                                              GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
300                                              GNUNET_GNS_LO_DEFAULT,
301                                              NULL, //shorten_key, always NULL
302                                              &start_backward_resolution,
303                                              vrh);
304   }
305
306
307
308
309
310 /**
311  * Result from GNS lookup.
312  *
313  * @param cls the closure (our client lookup handle)
314  * @param rd_count the number of records in @a rd
315  * @param rd the record data
316  */
317 static void
318 send_lookup_response (void* cls,
319                       uint32_t rd_count,
320                       const struct GNUNET_GNSRECORD_Data *rd)
321 {
322   struct VerifyRequestHandle *vrh = cls;
323   size_t len;
324   int i;
325   int cred_record_count;
326   struct GNUNET_MQ_Envelope *env;
327   struct VerifyResultMessage *rmsg;
328   const struct GNUNET_CREDENTIAL_CredentialRecordData *crd;
329   struct GNUNET_CRYPTO_EccSignaturePurpose *purp;
330   struct CredentialRecordEntry *cr_entry;
331   uint32_t cred_verified;
332
333   cred_record_count = 0;
334   struct AttributeRecordEntry *attr_entry;
335
336   struct GNUNET_CREDENTIAL_AttributeRecordData *ard = 
337     GNUNET_new(struct GNUNET_CREDENTIAL_AttributeRecordData); 
338
339   attr_entry->record_data = *ard; 
340   ard->subject_key = vrh->issuer_key;
341   GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_queue_head,
342                                     vrh->attr_queue_tail,
343                                     attr_entry);
344   for (i=0; i < rd_count; i++)
345   {
346     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
347       continue;
348     cred_record_count++;
349     crd = rd[i].data;
350     /**
351      * TODO:
352      * Check if we have already found our credential here
353      * If so return success
354      * Else
355      *  Save all found attributes/issues and prepare forward
356      *  resolution of issuer attribute
357      */
358     cr_entry = GNUNET_new (struct CredentialRecordEntry);
359     cr_entry->record_data = *crd;
360     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
361                                       vrh->cred_chain_tail,
362                                       cr_entry);
363     purp = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
364                           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
365                           strlen ((char*)&crd[1]) +1 );
366     purp->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
367                         sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
368                         strlen ((char*)&crd[1]) +1 );
369
370     purp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
371     if(GNUNET_OK == GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
372                                                purp,
373                                                &crd->sig,
374                                                &crd->issuer_key))
375     {
376       GNUNET_free (purp);
377       break;
378     }
379     GNUNET_free (purp);
380
381   }
382
383
384   /**
385    * Check for attributes from the issuer and follow the chain 
386    * till you get the required subject's attributes
387    */
388   if(cred_verified != GNUNET_YES){
389
390
391     vrh->attr_pointer = vrh->attr_pointer->next;
392     if(vrh->attr_pointer != NULL){
393
394       //Start with backward resolution
395       GNUNET_GNS_lookup (gns,
396                          vrh->issuer_attribute,
397                          &vrh->issuer_key, //issuer_key,
398                          GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
399                          GNUNET_GNS_LO_DEFAULT,
400                          NULL, //shorten_key, always NULL
401                          &start_backward_resolution,
402                          vrh);
403     }
404   }
405
406
407   /**
408    * TODO
409    * Start resolution of Attribute delegations from issuer
410    *
411    * - Build adequate data structures for attribute(s) to lookup
412    * - Use GNUNET_GNSRECORD_TYPE_XXX
413    * - recursively try to find match(es) with results found top
414    * - return one found credential chain
415    *
416    */
417
418   /**
419    * Get serialized record data size
420    */
421   len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData);
422
423   /**
424    * Prepare a lookup result response message for the client
425    */
426   env = GNUNET_MQ_msg_extra (rmsg,
427                              len,
428                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
429   //Assign id so that client can find associated request
430   rmsg->id = vrh->request_id;
431   rmsg->ad_count = htonl (cred_record_count);
432
433   /**
434    * Get serialized record data
435    * Append at the end of rmsg
436    */
437   i = 0;
438   struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1];
439   for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
440   {
441     memcpy (tmp_record,
442             &cr_entry->record_data,
443             sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData));
444     tmp_record++;
445   }
446   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
447                   env);
448
449   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
450
451   /**
452    * TODO:
453    * - Free DLL
454    * - Refactor into cleanup_handle() function for this
455    */
456   GNUNET_free (vrh);
457
458   GNUNET_STATISTICS_update (statistics,
459                             "Completed verifications", 1,
460                             GNUNET_NO);
461   GNUNET_STATISTICS_update (statistics,
462                             "Credentials resolved",
463                             rd_count,
464                             GNUNET_NO);
465 }
466
467 /**
468  * Handle Credential verification requests from client
469  *
470  * @param cls the closure
471  * @param client the client
472  * @param message the message
473  */
474 static void
475 handle_verify (void *cls,
476                const struct VerifyMessage *v_msg) 
477 {
478   char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
479   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
480   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
481   struct VerifyRequestHandle *vrh;
482   struct GNUNET_SERVICE_Client *client = cls;
483   char *attrptr = attrs;
484   const char *utf_in;
485
486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487               "Received VERIFY message\n");
488
489   utf_in = (const char *) &v_msg[1];
490   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
491
492   GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
493   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
494   GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
495   subject_attribute[ntohs (v_msg->subject_attribute_len)] = '\0';
496   vrh = GNUNET_new (struct VerifyRequestHandle);
497   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
498   vrh->client = client;
499   vrh->request_id = v_msg->id;
500   vrh->issuer_key = v_msg->issuer_key;
501   vrh->subject_key = v_msg->subject_key;
502   vrh->issuer_attribute = issuer_attribute;
503
504   if (NULL == subject_attribute)
505   {
506     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
507                 "No subject attribute provided!\n");
508     send_lookup_response (vrh, 0, NULL);
509     return;
510   }
511   if (NULL == issuer_attribute)
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
514                 "No issuer attribute provided!\n");
515     send_lookup_response (vrh, 0, NULL);
516     return;
517   }
518   /**
519    * First, get attribute from subject
520    */
521   vrh->lookup_request = GNUNET_GNS_lookup (gns,
522                                            subject_attribute,
523                                            &v_msg->subject_key, //subject_pkey,
524                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
525                                            GNUNET_GNS_LO_DEFAULT,
526                                            NULL, //shorten_key, always NULL
527                                            &send_lookup_response,
528                                            vrh);
529 }
530
531
532 /**
533  * One of our clients disconnected, clean up after it.
534  *
535  * @param cls NULL
536  * @param client the client that disconnected
537  */
538 static void
539 client_disconnect_cb (void *cls,
540                       struct GNUNET_SERVICE_Client *client,
541                       void *app_ctx)
542 {
543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544               "Client %p disconnected\n",
545               client);
546 }
547
548 /**
549  * Add a client to our list of active clients.
550  *
551  * @param cls NULL
552  * @param client client to add
553  * @param mq message queue for @a client
554  * @return this client
555  */
556 static void *
557 client_connect_cb (void *cls,
558                    struct GNUNET_SERVICE_Client *client,
559                    struct GNUNET_MQ_Handle *mq)
560 {
561   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562               "Client %p connected\n",
563               client);
564   return client;
565 }
566
567 /**
568  * Process Credential requests.
569  *
570  * @param cls closure
571  * @param server the initialized server
572  * @param c configuration to use
573  */
574 static void
575 run (void *cls,
576      const struct GNUNET_CONFIGURATION_Handle *c,
577      struct GNUNET_SERVICE_Handle *handle)
578 {
579
580   gns = GNUNET_GNS_connect (c);
581   if (NULL == gns)
582   {
583     fprintf (stderr,
584              _("Failed to connect to GNS\n"));
585   }
586
587   statistics = GNUNET_STATISTICS_create ("credential", c);
588   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
589 }
590
591
592 /**
593  * Define "main" method using service macro
594  */
595 GNUNET_SERVICE_MAIN
596 ("credential",
597  GNUNET_SERVICE_OPTION_NONE,
598  &run,
599  &client_connect_cb,
600  &client_disconnect_cb,
601  NULL,
602  GNUNET_MQ_hd_var_size (verify,
603                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
604                         struct VerifyMessage,
605                         NULL),
606  GNUNET_MQ_handler_end());
607
608 /* end of gnunet-service-credential.c */