28773de8e82a9d115fc5843636b834a273ad3dbc
[oweals/gnunet.git] / src / credential / credential_serialization.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016 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 /**
23  * @file credential/credential_serialization.c
24  * @brief API to serialize and deserialize delegation chains 
25  * and credentials
26  * @author Martin Schanzenbach
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_credential_service.h"
32 #include "gnunet_signatures.h"
33 #include "credential.h"
34
35 /**
36  * Calculate how many bytes we will need to serialize
37  * the given delegation chain
38  *
39  * @param ds_count number of delegation chain entries
40  * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet
41  * @return the required size to serialize
42  */
43 size_t
44 GNUNET_CREDENTIAL_delegation_set_get_size (
45   unsigned int ds_count,
46   const struct GNUNET_CREDENTIAL_DelegationSet *dsr)
47 {
48   unsigned int i;
49   size_t ret;
50
51   ret = sizeof (struct DelegationRecordData) * (ds_count);
52
53   for (i = 0; i < ds_count; i++)
54   {
55     GNUNET_assert ((ret + dsr[i].subject_attribute_len) >= ret);
56     ret += dsr[i].subject_attribute_len;
57   }
58   return ret;
59 }
60
61 /**
62  * Serizalize the given delegation chain entries and credential
63  *
64  * @param d_count number of delegation chain entries
65  * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet
66  * @param dest_size size of the destination
67  * @param dest where to store the result
68  * @return the size of the data, -1 on failure
69  */
70 ssize_t
71 GNUNET_CREDENTIAL_delegation_set_serialize (
72   unsigned int d_count,
73   const struct GNUNET_CREDENTIAL_DelegationSet *dsr,
74   size_t dest_size,
75   char *dest)
76 {
77   struct DelegationRecordData rec;
78   unsigned int i;
79   size_t off;
80
81   off = 0;
82   for (i = 0; i < d_count; i++)
83   {
84     rec.subject_attribute_len = htonl ((uint32_t) dsr[i].subject_attribute_len);
85     rec.subject_key = dsr[i].subject_key;
86     if (off + sizeof (rec) > dest_size)
87       return -1;
88     GNUNET_memcpy (&dest[off], &rec, sizeof (rec));
89     off += sizeof (rec);
90     if (0 == dsr[i].subject_attribute_len)
91       continue;
92     if (off + dsr[i].subject_attribute_len > dest_size)
93       return -1;
94     GNUNET_memcpy (&dest[off],
95                    dsr[i].subject_attribute,
96                    dsr[i].subject_attribute_len);
97     off += dsr[i].subject_attribute_len;
98   }
99   return off;
100 }
101
102
103 /**
104  * Deserialize the given destination
105  *
106  * @param len size of the serialized delegation chain and cred
107  * @param src the serialized data
108  * @param d_count the number of delegation chain entries
109  * @param dsr where to put the delegation chain entries
110  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
111  */
112 int
113 GNUNET_CREDENTIAL_delegation_set_deserialize (
114   size_t len,
115   const char *src,
116   unsigned int d_count,
117   struct GNUNET_CREDENTIAL_DelegationSet *dsr)
118 {
119   struct DelegationRecordData rec;
120   unsigned int i;
121   size_t off;
122
123   off = 0;
124   for (i = 0; i < d_count; i++)
125   {
126     if (off + sizeof (rec) > len)
127       return GNUNET_SYSERR;
128     GNUNET_memcpy (&rec, &src[off], sizeof (rec));
129     dsr[i].subject_key = rec.subject_key;
130     off += sizeof (rec);
131     dsr[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
132     if (off + dsr[i].subject_attribute_len > len)
133       return GNUNET_SYSERR;
134     dsr[i].subject_attribute = (char *) &src[off];
135     off += dsr[i].subject_attribute_len;
136   }
137   return GNUNET_OK;
138 }
139
140
141 /**
142  * Calculate how many bytes we will need to serialize
143  * the credentials
144  *
145  * @param c_count number of credential entries
146  * @param cd a #GNUNET_CREDENTIAL_Credential
147  * @return the required size to serialize
148  */
149 size_t
150 GNUNET_CREDENTIAL_delegates_get_size (
151   unsigned int c_count,
152   const struct GNUNET_CREDENTIAL_Delegate *cd)
153 {
154   unsigned int i;
155   size_t ret;
156
157   ret = sizeof (struct DelegateEntry) * (c_count);
158
159   for (i = 0; i < c_count; i++)
160   {
161     GNUNET_assert ((ret + cd[i].issuer_attribute_len + cd[i].subject_attribute_len) >= ret);
162     // subject_attribute_len should be 0
163     ret += cd[i].issuer_attribute_len + cd[i].subject_attribute_len;
164   }
165   return ret;
166 }
167 /**
168  * Serizalize the given credentials
169  *
170  * @param c_count number of credential entries
171  * @param cd a #GNUNET_CREDENTIAL_Credential
172  * @param dest_size size of the destination
173  * @param dest where to store the result
174  * @return the size of the data, -1 on failure
175  */
176 ssize_t
177 GNUNET_CREDENTIAL_delegates_serialize (
178   unsigned int c_count,
179   const struct GNUNET_CREDENTIAL_Delegate *cd,
180   size_t dest_size,
181   char *dest)
182 {
183   struct DelegateEntry c_rec;
184   unsigned int i;
185   size_t off;
186
187   off = 0;
188   for (i = 0; i < c_count; i++)
189   {
190     c_rec.issuer_attribute_len = htonl ((uint32_t) cd[i].issuer_attribute_len);
191     c_rec.issuer_key = cd[i].issuer_key;
192     c_rec.subject_key = cd[i].subject_key;
193     c_rec.signature = cd[i].signature;
194     c_rec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DELEGATE);
195     c_rec.purpose.size =
196       htonl ((sizeof (struct DelegateEntry) + cd[i].issuer_attribute_len) -
197              sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
198     c_rec.expiration = GNUNET_htonll (cd[i].expiration.abs_value_us);
199     if (off + sizeof (c_rec) > dest_size)
200       return -1;
201     GNUNET_memcpy (&dest[off], &c_rec, sizeof (c_rec));
202     off += sizeof (c_rec);
203     if (off + cd[i].issuer_attribute_len > dest_size)
204       return -1;
205     GNUNET_memcpy (&dest[off],
206                    cd[i].issuer_attribute,
207                    cd[i].issuer_attribute_len);
208     off += cd[i].issuer_attribute_len;
209   }
210
211   return off;
212 }
213
214
215 /**
216  * Deserialize the given destination
217  *
218  * @param len size of the serialized creds
219  * @param src the serialized data
220  * @param c_count the number of credential entries
221  * @param cd where to put the credential data
222  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
223  */
224 int
225 GNUNET_CREDENTIAL_delegates_deserialize (size_t len,
226                                          const char *src,
227                                          unsigned int c_count,
228                                          struct GNUNET_CREDENTIAL_Delegate *cd)
229 {
230   struct DelegateEntry c_rec;
231   unsigned int i;
232   size_t off;
233
234   off = 0;
235   for (i = 0; i < c_count; i++)
236   {
237     if (off + sizeof (c_rec) > len)
238       return GNUNET_SYSERR;
239     GNUNET_memcpy (&c_rec, &src[off], sizeof (c_rec));
240     cd[i].issuer_attribute_len = ntohl ((uint32_t) c_rec.issuer_attribute_len);
241     cd[i].issuer_key = c_rec.issuer_key;
242     cd[i].subject_key = c_rec.subject_key;
243     cd[i].signature = c_rec.signature;
244     cd[i].expiration.abs_value_us = GNUNET_ntohll (c_rec.expiration);
245     off += sizeof (c_rec);
246     if (off + cd[i].issuer_attribute_len > len)
247       return GNUNET_SYSERR;
248     cd[i].issuer_attribute = &src[off];
249     off += cd[i].issuer_attribute_len;
250     cd[i].subject_attribute_len = 0;
251   }
252   return GNUNET_OK;
253 }
254
255
256 /**
257  * Calculate how many bytes we will need to serialize
258  * the given delegation chain and credential
259  *
260  * @param d_count number of delegation chain entries
261  * @param dd array of #GNUNET_CREDENTIAL_Delegation
262  * @param c_count number of credential entries
263  * @param cd a #GNUNET_CREDENTIAL_Credential
264  * @return the required size to serialize
265  */
266 size_t
267 GNUNET_CREDENTIAL_delegation_chain_get_size (
268   unsigned int d_count,
269   const struct GNUNET_CREDENTIAL_Delegation *dd,
270   unsigned int c_count,
271   const struct GNUNET_CREDENTIAL_Delegate *cd)
272 {
273   unsigned int i;
274   size_t ret;
275
276   ret = sizeof (struct ChainEntry) * (d_count);
277
278   for (i = 0; i < d_count; i++)
279   {
280     GNUNET_assert (
281       (ret + dd[i].issuer_attribute_len + dd[i].subject_attribute_len) >= ret);
282     ret += dd[i].issuer_attribute_len + dd[i].subject_attribute_len;
283   }
284   return ret + GNUNET_CREDENTIAL_delegates_get_size (c_count, cd);
285 }
286
287 /**
288  * Serizalize the given delegation chain entries and credential
289  *
290  * @param d_count number of delegation chain entries
291  * @param dd array of #GNUNET_CREDENTIAL_Delegation
292  * @param c_count number of credential entries
293  * @param cd a #GNUNET_CREDENTIAL_Credential
294  * @param dest_size size of the destination
295  * @param dest where to store the result
296  * @return the size of the data, -1 on failure
297  */
298 ssize_t
299 GNUNET_CREDENTIAL_delegation_chain_serialize (
300   unsigned int d_count,
301   const struct GNUNET_CREDENTIAL_Delegation *dd,
302   unsigned int c_count,
303   const struct GNUNET_CREDENTIAL_Delegate *cd,
304   size_t dest_size,
305   char *dest)
306 {
307   struct ChainEntry rec;
308   unsigned int i;
309   size_t off;
310
311   off = 0;
312   for (i = 0; i < d_count; i++)
313   {
314     rec.issuer_attribute_len = htonl ((uint32_t) dd[i].issuer_attribute_len);
315     rec.subject_attribute_len = htonl ((uint32_t) dd[i].subject_attribute_len);
316     rec.issuer_key = dd[i].issuer_key;
317     rec.subject_key = dd[i].subject_key;
318     if (off + sizeof (rec) > dest_size)
319       return -1;
320     GNUNET_memcpy (&dest[off], &rec, sizeof (rec));
321     off += sizeof (rec);
322     if (off + dd[i].issuer_attribute_len > dest_size)
323       return -1;
324     GNUNET_memcpy (&dest[off],
325                    dd[i].issuer_attribute,
326                    dd[i].issuer_attribute_len);
327     off += dd[i].issuer_attribute_len;
328     if (0 == dd[i].subject_attribute_len)
329       continue;
330     if (off + dd[i].subject_attribute_len > dest_size)
331       return -1;
332     GNUNET_memcpy (&dest[off],
333                    dd[i].subject_attribute,
334                    dd[i].subject_attribute_len);
335     off += dd[i].subject_attribute_len;
336   }
337   return off + GNUNET_CREDENTIAL_delegates_serialize (c_count,
338                                                       cd,
339                                                       dest_size - off,
340                                                       &dest[off]);
341 }
342
343
344 /**
345  * Deserialize the given destination
346  *
347  * @param len size of the serialized delegation chain and cred
348  * @param src the serialized data
349  * @param d_count the number of delegation chain entries
350  * @param dd where to put the delegation chain entries
351  * @param c_count the number of credential entries
352  * @param cd where to put the credential data
353  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
354  */
355 int
356 GNUNET_CREDENTIAL_delegation_chain_deserialize (
357   size_t len,
358   const char *src,
359   unsigned int d_count,
360   struct GNUNET_CREDENTIAL_Delegation *dd,
361   unsigned int c_count,
362   struct GNUNET_CREDENTIAL_Delegate *cd)
363 {
364   struct ChainEntry rec;
365   unsigned int i;
366   size_t off;
367
368   off = 0;
369   for (i = 0; i < d_count; i++)
370   {
371     if (off + sizeof (rec) > len)
372       return GNUNET_SYSERR;
373     GNUNET_memcpy (&rec, &src[off], sizeof (rec));
374     dd[i].issuer_attribute_len = ntohl ((uint32_t) rec.issuer_attribute_len);
375     dd[i].issuer_key = rec.issuer_key;
376     dd[i].subject_key = rec.subject_key;
377     off += sizeof (rec);
378     if (off + dd[i].issuer_attribute_len > len)
379       return GNUNET_SYSERR;
380     dd[i].issuer_attribute = &src[off];
381     off += dd[i].issuer_attribute_len;
382     dd[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
383     if (off + dd[i].subject_attribute_len > len)
384       return GNUNET_SYSERR;
385     dd[i].subject_attribute = &src[off];
386     off += dd[i].subject_attribute_len;
387   }
388   return GNUNET_CREDENTIAL_delegates_deserialize (len - off,
389                                                   &src[off],
390                                                   c_count,
391                                                   cd);
392 }
393
394 int
395 GNUNET_CREDENTIAL_delegate_serialize (struct GNUNET_CREDENTIAL_Delegate *dele,
396                                       char **data)
397 {
398   size_t size;
399   struct DelegateEntry *cdata;
400   int attr_len;
401
402   // +1 for \0
403   if (0 == dele->subject_attribute_len)
404   {
405     attr_len = dele->issuer_attribute_len + 1;
406   }
407   else
408   {
409     attr_len = dele->issuer_attribute_len + dele->subject_attribute_len + 2;
410   }
411   size = sizeof (struct DelegateEntry) + attr_len;
412
413   char tmp_str[attr_len];
414   GNUNET_memcpy (tmp_str, dele->issuer_attribute, dele->issuer_attribute_len);
415   if (0 != dele->subject_attribute_len)
416   {
417     tmp_str[dele->issuer_attribute_len] = '\0';
418     GNUNET_memcpy (tmp_str + dele->issuer_attribute_len + 1,
419                    dele->subject_attribute,
420                    dele->subject_attribute_len);
421   }
422   tmp_str[attr_len - 1] = '\0';
423
424   *data = GNUNET_malloc (size);
425   cdata = (struct DelegateEntry *) *data;
426   cdata->subject_key = dele->subject_key;
427   cdata->issuer_key = dele->issuer_key;
428   cdata->expiration = GNUNET_htonll (dele->expiration.abs_value_us);
429   cdata->signature = dele->signature;
430   cdata->issuer_attribute_len = htonl (dele->issuer_attribute_len + 1);
431   if (0 == dele->subject_attribute_len)
432   {
433     cdata->subject_attribute_len = htonl (0);
434   }
435   else
436   {
437     cdata->subject_attribute_len = htonl (dele->subject_attribute_len + 1);
438   }
439   cdata->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DELEGATE);
440   cdata->purpose.size =
441     htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
442
443   GNUNET_memcpy (&cdata[1], tmp_str, attr_len);
444
445   if (GNUNET_OK !=
446       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_DELEGATE,
447                                   &cdata->purpose,
448                                   &cdata->signature,
449                                   &cdata->issuer_key))
450   {
451     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Serialize: Invalid delegate\n");
452     return 0;
453   }
454   return size;
455 }
456
457 struct GNUNET_CREDENTIAL_Delegate *
458 GNUNET_CREDENTIAL_delegate_deserialize (const char *data, size_t data_size)
459 {
460   struct GNUNET_CREDENTIAL_Delegate *dele;
461   struct DelegateEntry *cdata;
462   char *attr_combo_str;
463
464   if (data_size < sizeof (struct DelegateEntry))
465     return NULL;
466   cdata = (struct DelegateEntry *) data;
467   if (GNUNET_OK !=
468       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_DELEGATE,
469                                   &cdata->purpose,
470                                   &cdata->signature,
471                                   &cdata->issuer_key))
472   {
473     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Deserialize: Invalid delegate\n");
474     return NULL;
475   }
476   attr_combo_str = (char *) &cdata[1];
477   int iss_len = ntohl (cdata->issuer_attribute_len);
478   int sub_len = ntohl (cdata->subject_attribute_len);
479   int attr_combo_len = iss_len + sub_len;
480
481   dele =
482     GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Delegate) + attr_combo_len);
483
484   dele->issuer_key = cdata->issuer_key;
485   dele->subject_key = cdata->subject_key;
486   GNUNET_memcpy (&dele[1], attr_combo_str, attr_combo_len);
487   dele->signature = cdata->signature;
488
489   // Set the pointers for the attributes
490   dele->issuer_attribute = (char *) &dele[1];
491   dele->issuer_attribute_len = iss_len;
492   dele->subject_attribute_len = sub_len;
493   if (0 == sub_len)
494   {
495     dele->subject_attribute = NULL;
496   }
497   else
498   {
499     dele->subject_attribute = (char *) &dele[1] + iss_len;
500   }
501
502   dele->expiration.abs_value_us = GNUNET_ntohll (cdata->expiration);
503
504   return dele;
505 }
506
507 /* end of credential_serialization.c */