-change api
[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
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
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 and credential
38  *
39  * @param d_count number of delegation chain entries
40  * @param dd array of #GNUNET_CREDENTIAL_Delegation
41  * @param cd a #GNUNET_CREDENTIAL_Credential
42  * @return the required size to serialize
43  */
44 size_t
45 GNUNET_CREDENTIAL_delegation_set_get_size (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 dd array of #GNUNET_CREDENTIAL_Delegation
66  * @param cd a #GNUNET_CREDENTIAL_Credential
67  * @param dest_size size of the destination
68  * @param dest where to store the result
69  * @return the size of the data, -1 on failure
70  */
71 ssize_t
72 GNUNET_CREDENTIAL_delegation_set_serialize (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],
89                    &rec,
90                    sizeof (rec));
91     off += sizeof (rec);
92     if (0 == dsr[i].subject_attribute_len)
93       continue;
94     if (off + dsr[i].subject_attribute_len > dest_size)
95       return -1;
96     GNUNET_memcpy (&dest[off],
97                    dsr[i].subject_attribute,
98                    dsr[i].subject_attribute_len);
99     off += dsr[i].subject_attribute_len;
100   }
101   return off;
102 }
103
104
105 /**
106  * Deserialize the given destination
107  *
108  * @param len size of the serialized delegation chain and cred
109  * @param src the serialized data
110  * @param d_count the number of delegation chain entries
111  * @param dd where to put the delegation chain entries
112  * @param cd where to put the credential data
113  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
114  */
115 int
116 GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len,
117                                               const char *src,
118                                               unsigned int d_count,
119                                               struct GNUNET_CREDENTIAL_DelegationSet *dsr)
120 {
121   struct DelegationRecordData rec;
122   unsigned int i;
123   size_t off;
124
125   off = 0;
126   for (i=0;i<d_count;i++)
127   {
128     if (off + sizeof (rec) > len)
129       return GNUNET_SYSERR;
130     GNUNET_memcpy (&rec, &src[off], sizeof (rec));
131     dsr[i].subject_key = rec.subject_key;
132     off += sizeof (rec);
133     dsr[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
134     if (off + dsr[i].subject_attribute_len > len)
135       return GNUNET_SYSERR;
136     dsr[i].subject_attribute = (char*)&src[off];
137     off += dsr[i].subject_attribute_len;
138   }
139   return GNUNET_OK;
140 }
141
142
143 /**
144  * Calculate how many bytes we will need to serialize
145  * the credentials
146  *
147  * @param c_count number of credential entries
148  * @param cd a #GNUNET_CREDENTIAL_Credential
149  * @return the required size to serialize
150  */
151 size_t
152 GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count,
153                                         const struct GNUNET_CREDENTIAL_Credential *cd)
154 {
155   unsigned int i;
156   size_t ret;
157
158   ret = sizeof (struct CredentialEntry) * (c_count);
159
160   for (i=0; i<c_count;i++)
161   {
162     GNUNET_assert ((ret + cd[i].issuer_attribute_len) >= ret);
163     ret += cd[i].issuer_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_credentials_serialize (unsigned int c_count,
178                                          const struct GNUNET_CREDENTIAL_Credential *cd,
179                                          size_t dest_size,
180                                          char *dest)
181 {
182   struct CredentialEntry c_rec;
183   unsigned int i;
184   size_t off;
185
186   off = 0;
187   for (i=0;i<c_count;i++)
188   {
189     c_rec.issuer_attribute_len = htonl ((uint32_t) cd[i].issuer_attribute_len);
190     c_rec.issuer_key = cd[i].issuer_key;
191     c_rec.subject_key = cd[i].subject_key;
192     c_rec.signature = cd[i].signature;
193     c_rec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
194     c_rec.purpose.size = htonl ((sizeof (struct CredentialEntry) + cd[i].issuer_attribute_len) - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
195     c_rec.expiration = htonl ((uint32_t) cd[i].expiration.abs_value_us);
196     if (off + sizeof (c_rec) > dest_size)
197       return -1;
198     GNUNET_memcpy (&dest[off],
199                    &c_rec,
200                    sizeof (c_rec));
201     off += sizeof (c_rec);
202     if (off + cd[i].issuer_attribute_len > dest_size)
203       return -1;
204     GNUNET_memcpy (&dest[off],
205                    cd[i].issuer_attribute,
206                    cd[i].issuer_attribute_len);
207     off += cd[i].issuer_attribute_len;
208   }
209
210   return off;
211 }
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_credentials_deserialize (size_t len,
226                                            const char *src,
227                                            unsigned int c_count,
228                                            struct GNUNET_CREDENTIAL_Credential *cd)
229 {
230   struct CredentialEntry 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 = ntohl((uint32_t) 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   }
251   return GNUNET_OK;
252 }
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 (unsigned int d_count,
268                                              const struct GNUNET_CREDENTIAL_Delegation *dd,
269                                              unsigned int c_count,
270                                              const struct GNUNET_CREDENTIAL_Credential *cd)
271 {
272   unsigned int i;
273   size_t ret;
274
275   ret = sizeof (struct ChainEntry) * (d_count);
276
277   for (i=0; i<d_count;i++)
278   {
279     GNUNET_assert ((ret +
280                     dd[i].issuer_attribute_len +
281                     dd[i].subject_attribute_len) >= ret);
282     ret += dd[i].issuer_attribute_len + dd[i].subject_attribute_len;
283   }
284   return ret+GNUNET_CREDENTIAL_credentials_get_size(c_count, cd);
285   return ret;
286 }
287
288 /**
289  * Serizalize the given delegation chain entries and credential
290  *
291  * @param d_count number of delegation chain entries
292  * @param dd array of #GNUNET_CREDENTIAL_Delegation
293  * @param c_count number of credential entries
294  * @param cd a #GNUNET_CREDENTIAL_Credential
295  * @param dest_size size of the destination
296  * @param dest where to store the result
297  * @return the size of the data, -1 on failure
298  */
299 ssize_t
300 GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count,
301                                               const struct GNUNET_CREDENTIAL_Delegation *dd,
302                                               unsigned int c_count,
303                                               const struct GNUNET_CREDENTIAL_Credential *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],
321                    &rec,
322                    sizeof (rec));
323     off += sizeof (rec);
324     if (off + dd[i].issuer_attribute_len > dest_size)
325       return -1;
326     GNUNET_memcpy (&dest[off],
327                    dd[i].issuer_attribute,
328                    dd[i].issuer_attribute_len);
329     off += dd[i].issuer_attribute_len;
330     if (0 == dd[i].subject_attribute_len)
331       continue;
332     if (off + dd[i].subject_attribute_len > dest_size)
333       return -1;
334     GNUNET_memcpy (&dest[off],
335                    dd[i].subject_attribute,
336                    dd[i].subject_attribute_len);
337     off += dd[i].subject_attribute_len;
338   }
339   return off+GNUNET_CREDENTIAL_credentials_serialize (c_count,
340                                                       cd,
341                                                       dest_size-off,
342                                                       &dest[off]);
343 }
344
345
346 /**
347  * Deserialize the given destination
348  *
349  * @param len size of the serialized delegation chain and cred
350  * @param src the serialized data
351  * @param d_count the number of delegation chain entries
352  * @param dd where to put the delegation chain entries
353  * @param c_count the number of credential entries
354  * @param cd where to put the credential data
355  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
356  */
357 int
358 GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len,
359                                                 const char *src,
360                                                 unsigned int d_count,
361                                                 struct GNUNET_CREDENTIAL_Delegation *dd,
362                                                 unsigned int c_count,
363                                                 struct GNUNET_CREDENTIAL_Credential *cd)
364 {
365   struct ChainEntry rec;
366   unsigned int i;
367   size_t off;
368
369   off = 0;
370   for (i=0;i<d_count;i++)
371   {
372     if (off + sizeof (rec) > len)
373       return GNUNET_SYSERR;
374     GNUNET_memcpy (&rec, &src[off], sizeof (rec));
375     dd[i].issuer_attribute_len = ntohl ((uint32_t) rec.issuer_attribute_len);
376     dd[i].issuer_key = rec.issuer_key;
377     dd[i].subject_key = rec.subject_key;
378     off += sizeof (rec);
379     if (off + dd[i].issuer_attribute_len > len)
380       return GNUNET_SYSERR;
381     dd[i].issuer_attribute = &src[off];
382     off += dd[i].issuer_attribute_len;
383     dd[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
384     if (off + dd[i].subject_attribute_len > len)
385       return GNUNET_SYSERR;
386     dd[i].subject_attribute = &src[off];
387     off += dd[i].subject_attribute_len;
388   }
389   return GNUNET_CREDENTIAL_credentials_deserialize (len-off,
390                                                     &src[off],
391                                                     c_count,
392                                                     cd);
393 }
394 int
395 GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred,
396                                         char **data)
397 {
398   size_t size;
399   struct CredentialEntry *cdata;
400
401   size = sizeof (struct CredentialEntry) + strlen (cred->issuer_attribute) + 1;
402   *data = GNUNET_malloc (size);
403   cdata = (struct CredentialEntry*)*data;
404   cdata->subject_key = cred->subject_key;
405   cdata->issuer_key = cred->issuer_key;
406   cdata->expiration = GNUNET_htonll (cred->expiration.abs_value_us);
407   cdata->signature = cred->signature;
408   cdata->issuer_attribute_len = htonl (strlen (cred->issuer_attribute) + 1);
409   cdata->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
410   cdata->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
411   GNUNET_memcpy (&cdata[1],
412                  cred->issuer_attribute,
413                  strlen (cred->issuer_attribute));
414
415   if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
416                                              &cdata->purpose,
417                                              &cdata->signature,
418                                              &cdata->issuer_key))
419   {
420     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
421                 "Invalid credential\n");
422     //return NULL;
423   }
424   return size;
425 }
426
427 struct GNUNET_CREDENTIAL_Credential*
428 GNUNET_CREDENTIAL_credential_deserialize (const char* data,
429                                           size_t data_size)
430 {
431   struct GNUNET_CREDENTIAL_Credential *cred;
432   struct CredentialEntry *cdata;
433   char *issuer_attribute;
434
435   if (data_size < sizeof (struct CredentialEntry))
436     return NULL;
437   cdata = (struct CredentialEntry*)data;
438   if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
439                                              &cdata->purpose,
440                                              &cdata->signature,
441                                              &cdata->issuer_key))
442   {
443     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
444                 "Invalid credential\n");
445     //return NULL;
446   }
447   issuer_attribute = (char*)&cdata[1];
448
449   cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + ntohl(cdata->issuer_attribute_len));
450
451   cred->issuer_key = cdata->issuer_key;
452   cred->subject_key = cdata->subject_key;
453   GNUNET_memcpy (&cred[1],
454                  issuer_attribute,
455                  ntohl (cdata->issuer_attribute_len));
456   cred->signature = cdata->signature;
457   cred->issuer_attribute = (char*)&cred[1];
458   cred->expiration.abs_value_us = GNUNET_ntohll (cdata->expiration);
459   return cred;
460 }
461
462
463 /* end of credential_serialization.c */