ce040fe2b4662f9cff61a888ea7f86cb58e9839b
[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 CredentialRecordEntry *cr_entry;
330   uint32_t cred_verified;
331
332   cred_record_count = 0;
333   struct AttributeRecordEntry *attr_entry;
334
335   struct GNUNET_CREDENTIAL_AttributeRecordData *ard = 
336     GNUNET_new(struct GNUNET_CREDENTIAL_AttributeRecordData); 
337
338   attr_entry->record_data = *ard; 
339   ard->subject_key = vrh->issuer_key;
340   GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_queue_head,
341                                     vrh->attr_queue_tail,
342                                     attr_entry);
343   for (i=0; i < rd_count; i++)
344   {
345     if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
346       continue;
347     cred_record_count++;
348     crd = rd[i].data;
349     /**
350      * TODO:
351      * Check if we have already found our credential here
352      * If so return success
353      * Else
354      *  Save all found attributes/issues and prepare forward
355      *  resolution of issuer attribute
356      */
357     cr_entry = GNUNET_new (struct CredentialRecordEntry);
358     cr_entry->record_data = *crd;
359     GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
360                                       vrh->cred_chain_tail,
361                                       cr_entry);
362     if(GNUNET_OK == GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
363                                                &crd->purpose,
364                                                &crd->sig,
365                                                &crd->issuer_key))
366     {
367       break;
368     }
369
370   }
371
372
373   /**
374    * Check for attributes from the issuer and follow the chain 
375    * till you get the required subject's attributes
376    */
377   if(cred_verified != GNUNET_YES){
378
379
380     vrh->attr_pointer = vrh->attr_pointer->next;
381     if(vrh->attr_pointer != NULL){
382
383       //Start with backward resolution
384       GNUNET_GNS_lookup (gns,
385                          vrh->issuer_attribute,
386                          &vrh->issuer_key, //issuer_key,
387                          GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
388                          GNUNET_GNS_LO_DEFAULT,
389                          NULL, //shorten_key, always NULL
390                          &start_backward_resolution,
391                          vrh);
392     }
393   }
394
395
396   /**
397    * TODO
398    * Start resolution of Attribute delegations from issuer
399    *
400    * - Build adequate data structures for attribute(s) to lookup
401    * - Use GNUNET_GNSRECORD_TYPE_XXX
402    * - recursively try to find match(es) with results found top
403    * - return one found credential chain
404    *
405    */
406
407   /**
408    * Get serialized record data size
409    */
410   len = cred_record_count * sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData);
411
412   /**
413    * Prepare a lookup result response message for the client
414    */
415   env = GNUNET_MQ_msg_extra (rmsg,
416                              len,
417                              GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
418   //Assign id so that client can find associated request
419   rmsg->id = vrh->request_id;
420   rmsg->ad_count = htonl (cred_record_count);
421
422   /**
423    * Get serialized record data
424    * Append at the end of rmsg
425    */
426   i = 0;
427   struct GNUNET_CREDENTIAL_CredentialRecordData *tmp_record = (struct GNUNET_CREDENTIAL_CredentialRecordData*) &rmsg[1];
428   for (cr_entry = vrh->cred_chain_head; NULL != cr_entry; cr_entry = cr_entry->next)
429   {
430     memcpy (tmp_record,
431             &cr_entry->record_data,
432             sizeof (struct GNUNET_CREDENTIAL_CredentialRecordData));
433     tmp_record++;
434   }
435   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
436                   env);
437
438   GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
439
440   /**
441    * TODO:
442    * - Free DLL
443    * - Refactor into cleanup_handle() function for this
444    */
445   GNUNET_free (vrh);
446
447   GNUNET_STATISTICS_update (statistics,
448                             "Completed verifications", 1,
449                             GNUNET_NO);
450   GNUNET_STATISTICS_update (statistics,
451                             "Credentials resolved",
452                             rd_count,
453                             GNUNET_NO);
454 }
455
456 /**
457  * Handle Credential verification requests from client
458  *
459  * @param cls the closure
460  * @param client the client
461  * @param message the message
462  */
463 static void
464 handle_verify (void *cls,
465                const struct VerifyMessage *v_msg) 
466 {
467   char attrs[GNUNET_CREDENTIAL_MAX_LENGTH*2 + 1];
468   char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
469   char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
470   struct VerifyRequestHandle *vrh;
471   struct GNUNET_SERVICE_Client *client = cls;
472   char *attrptr = attrs;
473   const char *utf_in;
474
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476               "Received VERIFY message\n");
477
478   utf_in = (const char *) &v_msg[1];
479   GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
480
481   GNUNET_memcpy (issuer_attribute, attrs, ntohs (v_msg->issuer_attribute_len));
482   issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
483   GNUNET_memcpy (subject_attribute, attrs+strlen(issuer_attribute), ntohs (v_msg->subject_attribute_len));
484   subject_attribute[ntohs (v_msg->subject_attribute_len)] = '\0';
485   vrh = GNUNET_new (struct VerifyRequestHandle);
486   GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
487   vrh->client = client;
488   vrh->request_id = v_msg->id;
489   vrh->issuer_key = v_msg->issuer_key;
490   vrh->subject_key = v_msg->subject_key;
491   vrh->issuer_attribute = issuer_attribute;
492
493   if (NULL == subject_attribute)
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
496                 "No subject attribute provided!\n");
497     send_lookup_response (vrh, 0, NULL);
498     return;
499   }
500   if (NULL == issuer_attribute)
501   {
502     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
503                 "No issuer attribute provided!\n");
504     send_lookup_response (vrh, 0, NULL);
505     return;
506   }
507   /**
508    * First, get attribute from subject
509    */
510   vrh->lookup_request = GNUNET_GNS_lookup (gns,
511                                            subject_attribute,
512                                            &v_msg->subject_key, //subject_pkey,
513                                            GNUNET_GNSRECORD_TYPE_CREDENTIAL,
514                                            GNUNET_GNS_LO_DEFAULT,
515                                            NULL, //shorten_key, always NULL
516                                            &send_lookup_response,
517                                            vrh);
518 }
519
520
521 /**
522  * One of our clients disconnected, clean up after it.
523  *
524  * @param cls NULL
525  * @param client the client that disconnected
526  */
527 static void
528 client_disconnect_cb (void *cls,
529                       struct GNUNET_SERVICE_Client *client,
530                       void *app_ctx)
531 {
532   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533               "Client %p disconnected\n",
534               client);
535 }
536
537 /**
538  * Add a client to our list of active clients.
539  *
540  * @param cls NULL
541  * @param client client to add
542  * @param mq message queue for @a client
543  * @return this client
544  */
545 static void *
546 client_connect_cb (void *cls,
547                    struct GNUNET_SERVICE_Client *client,
548                    struct GNUNET_MQ_Handle *mq)
549 {
550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551               "Client %p connected\n",
552               client);
553   return client;
554 }
555
556 /**
557  * Process Credential requests.
558  *
559  * @param cls closure
560  * @param server the initialized server
561  * @param c configuration to use
562  */
563 static void
564 run (void *cls,
565      const struct GNUNET_CONFIGURATION_Handle *c,
566      struct GNUNET_SERVICE_Handle *handle)
567 {
568
569   gns = GNUNET_GNS_connect (c);
570   if (NULL == gns)
571   {
572     fprintf (stderr,
573              _("Failed to connect to GNS\n"));
574   }
575
576   statistics = GNUNET_STATISTICS_create ("credential", c);
577   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
578 }
579
580
581 /**
582  * Define "main" method using service macro
583  */
584 GNUNET_SERVICE_MAIN
585 ("credential",
586  GNUNET_SERVICE_OPTION_NONE,
587  &run,
588  &client_connect_cb,
589  &client_disconnect_cb,
590  NULL,
591  GNUNET_MQ_hd_var_size (verify,
592                         GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
593                         struct VerifyMessage,
594                         NULL),
595  GNUNET_MQ_handler_end());
596
597 /* end of gnunet-service-credential.c */