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