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