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