consolidate reclaim attribute lib
[oweals/gnunet.git] / src / reclaim / reclaim_attestation.c
1 /*
2    This file is part of GNUnet
3    Copyright (C) 2010-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file reclaim-attribute/reclaim_attestation.c
23  * @brief helper library to manage identity attribute attestations
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_reclaim_plugin.h"
29 #include "reclaim_attestation.h"
30
31
32 /**
33  * Handle for a plugin
34  */
35 struct Plugin
36 {
37   /**
38    * Name of the plugin
39    */
40   char *library_name;
41
42   /**
43    * Plugin API
44    */
45   struct GNUNET_RECLAIM_AttestationPluginFunctions *api;
46 };
47
48
49 /**
50  * Plugins
51  */
52 static struct Plugin **attest_plugins;
53
54
55 /**
56  * Number of plugins
57  */
58 static unsigned int num_plugins;
59
60
61 /**
62  * Init canary
63  */
64 static int initialized;
65
66
67 /**
68  * Add a plugin
69  *
70  * @param cls closure
71  * @param library_name name of the API library
72  * @param lib_ret the plugin API pointer
73  */
74 static void
75 add_plugin (void *cls, const char *library_name, void *lib_ret)
76 {
77   struct GNUNET_RECLAIM_AttestationPluginFunctions *api = lib_ret;
78   struct Plugin *plugin;
79
80   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81               "Loading attestation plugin `%s'\n",
82               library_name);
83   plugin = GNUNET_new (struct Plugin);
84   plugin->api = api;
85   plugin->library_name = GNUNET_strdup (library_name);
86   GNUNET_array_append (attest_plugins, num_plugins, plugin);
87 }
88
89
90 /**
91  * Load plugins
92  */
93 static void
94 init ()
95 {
96   if (GNUNET_YES == initialized)
97     return;
98   initialized = GNUNET_YES;
99   GNUNET_PLUGIN_load_all ("libgnunet_plugin_reclaim_attestation_",
100                           NULL,
101                           &add_plugin,
102                           NULL);
103 }
104
105
106 /**
107  * Convert an attestation type name to the corresponding number
108  *
109  * @param typename name to convert
110  * @return corresponding number, UINT32_MAX on error
111  */
112 uint32_t
113 GNUNET_RECLAIM_attestation_typename_to_number (const char *typename)
114 {
115   unsigned int i;
116   struct Plugin *plugin;
117   uint32_t ret;
118   init ();
119   for (i = 0; i < num_plugins; i++)
120   {
121     plugin = attest_plugins[i];
122     if (UINT32_MAX !=
123         (ret = plugin->api->typename_to_number (plugin->api->cls,
124                                                 typename)))
125       return ret;
126   }
127   return UINT32_MAX;
128 }
129
130
131 /**
132  * Convert an attestation type number to the corresponding attestation type string
133  *
134  * @param type number of a type
135  * @return corresponding typestring, NULL on error
136  */
137 const char *
138 GNUNET_RECLAIM_attestation_number_to_typename (uint32_t type)
139 {
140   unsigned int i;
141   struct Plugin *plugin;
142   const char *ret;
143
144   init ();
145   for (i = 0; i < num_plugins; i++)
146   {
147     plugin = attest_plugins[i];
148     if (NULL !=
149         (ret = plugin->api->number_to_typename (plugin->api->cls, type)))
150       return ret;
151   }
152   return NULL;
153 }
154
155
156 /**
157  * Convert human-readable version of a 'claim' of an attestation to the binary
158  * representation
159  *
160  * @param type type of the claim
161  * @param s human-readable string
162  * @param data set to value in binary encoding (will be allocated)
163  * @param data_size set to number of bytes in @a data
164  * @return #GNUNET_OK on success
165  */
166 int
167 GNUNET_RECLAIM_attestation_string_to_value (uint32_t type,
168                                             const char *s,
169                                             void **data,
170                                             size_t *data_size)
171 {
172   unsigned int i;
173   struct Plugin *plugin;
174
175   init ();
176   for (i = 0; i < num_plugins; i++)
177   {
178     plugin = attest_plugins[i];
179     if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls,
180                                                    type,
181                                                    s,
182                                                    data,
183                                                    data_size))
184       return GNUNET_OK;
185   }
186   return GNUNET_SYSERR;
187 }
188
189
190 /**
191  * Convert the 'claim' of an attestation to a string
192  *
193  * @param type the type of attestation
194  * @param data claim in binary encoding
195  * @param data_size number of bytes in @a data
196  * @return NULL on error, otherwise human-readable representation of the claim
197  */
198 char *
199 GNUNET_RECLAIM_attestation_value_to_string (uint32_t type,
200                                             const void *data,
201                                             size_t data_size)
202 {
203   unsigned int i;
204   struct Plugin *plugin;
205   char *ret;
206
207   init ();
208   for (i = 0; i < num_plugins; i++)
209   {
210     plugin = attest_plugins[i];
211     if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls,
212                                                      type,
213                                                      data,
214                                                      data_size)))
215       return ret;
216   }
217   return NULL;
218 }
219
220
221 /**
222    * Create a new attestation.
223    *
224    * @param attr_name the attestation name
225    * @param type the attestation type
226    * @param data the attestation value
227    * @param data_size the attestation value size
228    * @return the new attestation
229    */
230 struct GNUNET_RECLAIM_Attestation *
231 GNUNET_RECLAIM_attestation_new (const char *attr_name,
232                                 uint32_t type,
233                                 const void *data,
234                                 size_t data_size)
235 {
236   struct GNUNET_RECLAIM_Attestation *attr;
237   char *write_ptr;
238   char *attr_name_tmp = GNUNET_strdup (attr_name);
239
240   GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp);
241
242   attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attestation)
243                         + strlen (attr_name_tmp) + 1 + data_size);
244   attr->type = type;
245   attr->data_size = data_size;
246   attr->flag = 0;
247   write_ptr = (char *) &attr[1];
248   GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1);
249   attr->name = write_ptr;
250   write_ptr += strlen (attr->name) + 1;
251   GNUNET_memcpy (write_ptr, data, data_size);
252   attr->data = write_ptr;
253   GNUNET_free (attr_name_tmp);
254   return attr;
255 }
256
257
258 /**
259  * Get required size for serialization buffer
260  *
261  * @param attrs the attribute list to serialize
262  * @return the required buffer size
263  */
264 size_t
265 GNUNET_RECLAIM_attestation_list_serialize_get_size (
266   const struct GNUNET_RECLAIM_AttestationList *attestations)
267 {
268   struct GNUNET_RECLAIM_AttestationListEntry *le;
269   size_t len = 0;
270
271   for (le = attestations->list_head; NULL != le; le = le->next)
272   {
273     GNUNET_assert (NULL != le->attestation);
274     len += GNUNET_RECLAIM_attestation_serialize_get_size (le->attestation);
275     len += sizeof(struct GNUNET_RECLAIM_AttestationListEntry);
276   }
277   return len;
278 }
279
280
281 /**
282  * Serialize an attribute list
283  *
284  * @param attrs the attribute list to serialize
285  * @param result the serialized attribute
286  * @return length of serialized data
287  */
288 size_t
289 GNUNET_RECLAIM_attestation_list_serialize (
290   const struct GNUNET_RECLAIM_AttestationList *attestations,
291   char *result)
292 {
293   struct GNUNET_RECLAIM_AttestationListEntry *le;
294   size_t len;
295   size_t total_len;
296   char *write_ptr;
297   write_ptr = result;
298   total_len = 0;
299   for (le = attestations->list_head; NULL != le; le = le->next)
300   {
301     GNUNET_assert (NULL != le->attestation);
302     len = GNUNET_RECLAIM_attestation_serialize (le->attestation, write_ptr);
303     total_len += len;
304     write_ptr += len;
305   }
306   return total_len;
307 }
308
309
310 /**
311  * Deserialize an attestation list
312  *
313  * @param data the serialized attribute list
314  * @param data_size the length of the serialized data
315  * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller
316  */
317 struct GNUNET_RECLAIM_AttestationList *
318 GNUNET_RECLAIM_attestation_list_deserialize (const char *data, size_t data_size)
319 {
320   struct GNUNET_RECLAIM_AttestationList *al;
321   struct GNUNET_RECLAIM_AttestationListEntry *ale;
322   size_t att_len;
323   const char *read_ptr;
324
325   al = GNUNET_new (struct GNUNET_RECLAIM_AttestationList);
326
327   if ((data_size < sizeof(struct
328                           Attestation)
329        + sizeof(struct GNUNET_RECLAIM_AttestationListEntry)))
330     return al;
331
332   read_ptr = data;
333   while (((data + data_size) - read_ptr) >= sizeof(struct Attestation))
334   {
335     ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry);
336     ale->attestation =
337       GNUNET_RECLAIM_attestation_deserialize (read_ptr,
338                                               data_size - (read_ptr - data));
339     GNUNET_CONTAINER_DLL_insert (al->list_head, al->list_tail, ale);
340     att_len = GNUNET_RECLAIM_attestation_serialize_get_size (ale->attestation);
341     read_ptr += att_len;
342   }
343   return al;
344 }
345
346
347 /**
348  * Make a (deep) copy of the attestation list
349  * @param attrs claim list to copy
350  * @return copied claim list
351  */
352 struct GNUNET_RECLAIM_AttestationList *
353 GNUNET_RECLAIM_attestation_list_dup (
354   const struct GNUNET_RECLAIM_AttestationList *al)
355 {
356   struct GNUNET_RECLAIM_AttestationListEntry *ale;
357   struct GNUNET_RECLAIM_AttestationListEntry *result_ale;
358   struct GNUNET_RECLAIM_AttestationList *result;
359
360   result = GNUNET_new (struct GNUNET_RECLAIM_AttestationList);
361   for (ale = al->list_head; NULL != ale; ale = ale->next)
362   {
363     result_ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry);
364     GNUNET_assert (NULL != ale->attestation);
365     result_ale->attestation =
366       GNUNET_RECLAIM_attestation_new (ale->attestation->name,
367                                       ale->attestation->type,
368                                       ale->attestation->data,
369                                       ale->attestation->data_size);
370     result_ale->attestation->id = ale->attestation->id;
371     GNUNET_CONTAINER_DLL_insert (result->list_head,
372                                  result->list_tail,
373                                  result_ale);
374   }
375   return result;
376 }
377
378
379 /**
380  * Destroy attestation list
381  *
382  * @param attrs list to destroy
383  */
384 void
385 GNUNET_RECLAIM_attestation_list_destroy (
386   struct GNUNET_RECLAIM_AttestationList *al)
387 {
388   struct GNUNET_RECLAIM_AttestationListEntry *ale;
389   struct GNUNET_RECLAIM_AttestationListEntry *tmp_ale;
390
391   for (ale = al->list_head; NULL != ale;)
392   {
393     if (NULL != ale->attestation)
394       GNUNET_free (ale->attestation);
395     tmp_ale = ale;
396     ale = ale->next;
397     GNUNET_free (tmp_ale);
398   }
399   GNUNET_free (al);
400 }
401
402
403 /**
404  * Get required size for serialization buffer
405  *
406  * @param attr the attestation to serialize
407  * @return the required buffer size
408  */
409 size_t
410 GNUNET_RECLAIM_attestation_serialize_get_size (
411   const struct GNUNET_RECLAIM_Attestation *attestation)
412 {
413   return sizeof(struct Attestation) + strlen (attestation->name)
414          + attestation->data_size;
415 }
416
417
418 /**
419  * Serialize an attestation
420  *
421  * @param attr the attestation to serialize
422  * @param result the serialized attestation
423  * @return length of serialized data
424  */
425 size_t
426 GNUNET_RECLAIM_attestation_serialize (
427   const struct GNUNET_RECLAIM_Attestation *attestation,
428   char *result)
429 {
430   size_t data_len_ser;
431   size_t name_len;
432   struct Attestation *atts;
433   char *write_ptr;
434
435   atts = (struct Attestation *) result;
436   atts->attestation_type = htons (attestation->type);
437   atts->attestation_flag = htonl (attestation->flag);
438   atts->attestation_id = attestation->id;
439   name_len = strlen (attestation->name);
440   atts->name_len = htons (name_len);
441   write_ptr = (char *) &atts[1];
442   GNUNET_memcpy (write_ptr, attestation->name, name_len);
443   write_ptr += name_len;
444   // TODO plugin-ize
445   // data_len_ser = plugin->serialize_attribute_value (attr,
446   //                                                  &attr_ser[1]);
447   data_len_ser = attestation->data_size;
448   GNUNET_memcpy (write_ptr, attestation->data, attestation->data_size);
449   atts->data_size = htons (data_len_ser);
450
451   return sizeof(struct Attestation) + strlen (attestation->name)
452          + attestation->data_size;
453 }
454
455
456 /**
457  * Deserialize an attestation
458  *
459  * @param data the serialized attestation
460  * @param data_size the length of the serialized data
461  *
462  * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller
463  */
464 struct GNUNET_RECLAIM_Attestation *
465 GNUNET_RECLAIM_attestation_deserialize (const char *data, size_t data_size)
466 {
467   struct GNUNET_RECLAIM_Attestation *attestation;
468   struct Attestation *atts;
469   size_t data_len;
470   size_t name_len;
471   char *write_ptr;
472
473   if (data_size < sizeof(struct Attestation))
474     return NULL;
475
476   atts = (struct Attestation *) data;
477   data_len = ntohs (atts->data_size);
478   name_len = ntohs (atts->name_len);
479   if (data_size < sizeof(struct Attestation) + data_len + name_len)
480   {
481     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
482                 "Buffer too small to deserialize\n");
483     return NULL;
484   }
485   attestation = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_Attestation)
486                                + data_len + name_len + 1);
487   attestation->type = ntohs (atts->attestation_type);
488   attestation->flag = ntohl (atts->attestation_flag);
489   attestation->id = atts->attestation_id;
490   attestation->data_size = data_len;
491
492   write_ptr = (char *) &attestation[1];
493   GNUNET_memcpy (write_ptr, &atts[1], name_len);
494   write_ptr[name_len] = '\0';
495   attestation->name = write_ptr;
496
497   write_ptr += name_len + 1;
498   GNUNET_memcpy (write_ptr, (char *) &atts[1] + name_len,
499                  attestation->data_size);
500   attestation->data = write_ptr;
501   return attestation;
502 }
503
504 struct GNUNET_RECLAIM_AttributeList*
505 GNUNET_RECLAIM_attestation_get_attributes (const struct GNUNET_RECLAIM_Attestation *attest)
506 {
507   unsigned int i;
508   struct Plugin *plugin;
509   struct GNUNET_RECLAIM_AttributeList *ret;
510   init ();
511   for (i = 0; i < num_plugins; i++)
512   {
513     plugin = attest_plugins[i];
514     if (NULL !=
515        (ret = plugin->api->get_attributes (plugin->api->cls,
516                                               attest)))
517       return ret;
518   }
519   return NULL;
520 }