-merge
[oweals/gnunet.git] / src / identity-provider / identity_token.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
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  * @file identity-provider/identity_token.c
23  * @brief helper library to manage identity tokens
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_signatures.h"
29 #include "identity_token.h"
30 #include <jansson.h>
31 #include <inttypes.h>
32
33 #define JWT_ALG "alg"
34
35 #define JWT_ALG_VALUE "ED512"
36
37 #define JWT_TYP "typ"
38
39 #define JWT_TYP_VALUE "jwt"
40
41 /**
42  * Crypto helper functions
43  */
44
45 static int
46 create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
47                          struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
48                          struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
49 {
50   struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
51
52   GNUNET_CRYPTO_hash_to_enc (new_key_hash,
53                              &new_key_hash_str);
54   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
55   static const char ctx_key[] = "gnuid-aes-ctx-key";
56   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
57                      new_key_hash, sizeof (struct GNUNET_HashCode),
58                      ctx_key, strlen (ctx_key),
59                      NULL, 0);
60   static const char ctx_iv[] = "gnuid-aes-ctx-iv";
61   GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
62                      new_key_hash, sizeof (struct GNUNET_HashCode),
63                      ctx_iv, strlen (ctx_iv),
64                      NULL, 0);
65   return GNUNET_OK;
66 }
67
68
69
70 /**
71  * Decrypts data part from a token code
72  */
73 static int
74 decrypt_str_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
75                    const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key,
76                    const char *cyphertext,
77                    size_t cyphertext_len,
78                    char **result_str)
79 {
80   struct GNUNET_HashCode new_key_hash;
81   struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
82   struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
83
84   char *str_buf = GNUNET_malloc (cyphertext_len);
85   size_t str_size;
86
87   //Calculate symmetric key from ecdh parameters
88   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_ecdh (priv_key,
89                                                         ecdh_key,
90                                                         &new_key_hash));
91
92   create_sym_key_from_ecdh (&new_key_hash,
93                             &enc_key,
94                             &enc_iv);
95
96   str_size = GNUNET_CRYPTO_symmetric_decrypt (cyphertext,
97                                               cyphertext_len,
98                                               &enc_key,
99                                               &enc_iv,
100                                               str_buf);
101   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
102               "Decrypted bytes: %zd Expected bytes: %zd\n",
103               str_size,
104               cyphertext_len);
105   if (-1 == str_size)
106   {
107     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH invalid\n");
108     GNUNET_free (str_buf);
109     return GNUNET_SYSERR;
110   }
111   *result_str = GNUNET_malloc (str_size+1);
112   GNUNET_memcpy (*result_str, str_buf, str_size);
113   (*result_str)[str_size] = '\0';
114   GNUNET_free (str_buf);
115   return GNUNET_OK;
116
117 }
118
119 /**
120  * Decrypt string using pubkey and ECDHE
121 */
122 static int
123 decrypt_str_ecdhe2 (const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_privkey,
124                     const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
125                     const char *ciphertext,
126                     size_t ciphertext_len,
127                     char **plaintext)
128 {
129   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
130   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
131   struct GNUNET_HashCode new_key_hash;
132
133   //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
134   *plaintext = GNUNET_malloc (ciphertext_len);
135
136   // Derived key K = H(eB)
137   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (ecdh_privkey,
138                                                         aud_key,
139                                                         &new_key_hash));
140   create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
141   GNUNET_CRYPTO_symmetric_decrypt (ciphertext,
142                                    ciphertext_len,
143                                    &skey, &iv,
144                                    *plaintext);
145   return GNUNET_OK;
146 }
147
148
149 /**
150  * Encrypt string using pubkey and ECDHE
151  * Returns ECDHE pubkey to be used for decryption
152  */
153 static int
154 encrypt_str_ecdhe (const char *plaintext,
155                    const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
156                    char **cyphertext,
157                    struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
158                    struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pubkey)
159 {
160   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
161   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
162   struct GNUNET_HashCode new_key_hash;
163   ssize_t enc_size;
164
165   // ECDH keypair E = eG
166   *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
167   GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
168                                       ecdh_pubkey);
169
170   //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
171   *cyphertext = GNUNET_malloc (strlen (plaintext));
172
173   // Derived key K = H(eB)
174   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
175                                                         pub_key,
176                                                         &new_key_hash));
177   create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
178   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting string %s\n (len=%zd)",
179               plaintext,
180               strlen (plaintext));
181   enc_size = GNUNET_CRYPTO_symmetric_encrypt (plaintext,
182                                               strlen (plaintext),
183                                               &skey, &iv,
184                                               *cyphertext);
185   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted (len=%zd)", enc_size);
186   return GNUNET_OK;
187 }
188
189
190 /**
191  * Identity Token API
192  */
193
194
195 /**
196  * Create an Identity Token
197  *
198  * @param type the JSON API resource type
199  * @param id the JSON API resource id
200  * @return a new JSON API resource or NULL on error.
201  */
202 struct IdentityToken*
203 token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey* iss,
204                                        const struct GNUNET_CRYPTO_EcdsaPublicKey* aud)
205 {
206   struct IdentityToken *token;
207   char* audience;
208   char* issuer;
209
210   issuer = GNUNET_STRINGS_data_to_string_alloc (iss,
211                                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
212   audience = GNUNET_STRINGS_data_to_string_alloc (aud,
213                                                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
214
215   token = GNUNET_malloc (sizeof (struct IdentityToken));
216   token_add_attr (token, "iss", issuer);
217   token_add_attr (token, "aud", audience);
218   token_add_attr (token, "sub", issuer);
219   token->aud_key = *aud;
220   GNUNET_free (issuer);
221   GNUNET_free (audience);
222   return token;
223 }
224
225 void
226 token_destroy (struct IdentityToken *token)
227 {
228   struct TokenAttr *attr;
229   struct TokenAttr *tmp_attr;
230   struct TokenAttrValue *val;
231   struct TokenAttrValue *tmp_val;
232
233   for (attr = token->attr_head; NULL != attr;)
234   {
235     tmp_attr = attr->next;
236     GNUNET_CONTAINER_DLL_remove (token->attr_head,
237                                  token->attr_tail,
238                                  attr);
239     for (val = attr->val_head; NULL != val;)
240     {
241       tmp_val = val->next;
242       GNUNET_CONTAINER_DLL_remove (attr->val_head,
243                                    attr->val_tail,
244                                    val);
245       if (NULL != val->value)
246         GNUNET_free (val->value);
247       GNUNET_free (val);
248       val = tmp_val;
249     }
250     GNUNET_free (attr->name);
251     GNUNET_free (attr);
252     attr = tmp_attr;
253   }
254
255   
256   GNUNET_free (token);
257 }
258
259 void
260 token_add_attr_json (struct IdentityToken *token,
261                      const char* key,
262                      json_t* value)
263 {
264   struct TokenAttr *attr;
265   struct TokenAttrValue *new_val;
266   GNUNET_assert (NULL != token);
267
268   new_val = GNUNET_malloc (sizeof (struct TokenAttrValue));
269   new_val->json_value = value;
270   json_incref(value);
271   for (attr = token->attr_head; NULL != attr; attr = attr->next)
272   {
273     if (0 == strcmp (key, attr->name))
274       break;
275   }
276
277   if (NULL == attr)
278   {
279     attr = GNUNET_malloc (sizeof (struct TokenAttr));
280     attr->name = GNUNET_strdup (key);
281     GNUNET_CONTAINER_DLL_insert (token->attr_head,
282                                  token->attr_tail,
283                                  attr);
284   }
285
286   GNUNET_CONTAINER_DLL_insert (attr->val_head,
287                                attr->val_tail,
288                                new_val);
289 }
290
291 void
292 token_add_attr (struct IdentityToken *token,
293                 const char* key,
294                 const char* value)
295 {
296   struct TokenAttr *attr;
297   struct TokenAttrValue *new_val;
298   GNUNET_assert (NULL != token);
299
300   new_val = GNUNET_malloc (sizeof (struct TokenAttrValue));
301   new_val->value = GNUNET_strdup (value);
302   for (attr = token->attr_head; NULL != attr; attr = attr->next)
303   {
304     if (0 == strcmp (key, attr->name))
305       break;
306   }
307
308   if (NULL == attr)
309   {
310     attr = GNUNET_malloc (sizeof (struct TokenAttr));
311     attr->name = GNUNET_strdup (key);
312     GNUNET_CONTAINER_DLL_insert (token->attr_head,
313                                  token->attr_tail,
314                                  attr);
315   }
316
317   GNUNET_CONTAINER_DLL_insert (attr->val_head,
318                                attr->val_tail,
319                                new_val);
320 }
321
322 void
323 token_add_attr_int (struct IdentityToken *token,
324                     const char* key,
325                     uint64_t value)
326 {
327   struct TokenAttr *attr;
328   struct TokenAttrValue *new_val;
329   GNUNET_assert (NULL != token);
330
331   new_val = GNUNET_malloc (sizeof (struct TokenAttrValue));
332   new_val->int_value = value;
333   for (attr = token->attr_head; NULL != attr; attr = attr->next)
334   {
335     if (0 == strcmp (key, attr->name))
336       break;
337   }
338
339   if (NULL == attr)
340   {
341     attr = GNUNET_malloc (sizeof (struct TokenAttr));
342     attr->name = GNUNET_strdup (key);
343     GNUNET_CONTAINER_DLL_insert (token->attr_head,
344                                  token->attr_tail,
345                                  attr);
346   }
347
348   GNUNET_CONTAINER_DLL_insert (attr->val_head,
349                                attr->val_tail,
350                                new_val);
351 }
352
353 static void
354 parse_json_payload(const char* payload_base64,
355                    struct IdentityToken *token) 
356 {
357   const char *key;
358   const json_t *value;
359   const json_t *arr_value;
360   char *payload;
361   int idx;
362   json_t *payload_json;
363   json_error_t err_json;
364
365   GNUNET_STRINGS_base64_decode (payload_base64,
366                                 strlen (payload_base64),
367                                 &payload);
368   //TODO signature and aud key
369   payload_json = json_loads (payload, JSON_DECODE_ANY, &err_json);
370
371   json_object_foreach (payload_json, key, value)
372   {
373     if (json_is_array (value))
374     {
375       json_array_foreach (value, idx, arr_value)
376       {
377         if (json_is_integer (arr_value))
378           token_add_attr_int (token, key,
379                               json_integer_value (arr_value));
380         else if (json_is_string (arr_value))
381           token_add_attr (token,
382                           key,
383                           json_string_value (arr_value));
384         else
385           token_add_attr_json (token,
386                                key,
387                                (json_t*)arr_value);
388       }
389     } else {
390       if (json_is_integer (value))
391         token_add_attr_int (token, key,
392                             json_integer_value (value));
393       else if (json_is_string (value))
394         token_add_attr (token, key, json_string_value (value));
395       else
396         token_add_attr_json (token, key, (json_t*)value);
397     }
398   }
399
400   json_decref (payload_json);
401   GNUNET_free (payload);
402 }
403
404 int
405 token_parse2 (const char* raw_data,
406               const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
407               const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
408               struct IdentityToken **result)
409 {
410   char *enc_token_str;
411   char *tmp_buf;
412   char *token_str;
413   char *enc_token;
414   char *payload_base64;
415   size_t enc_token_len;
416
417   GNUNET_asprintf (&tmp_buf, "%s", raw_data);
418   strtok (tmp_buf, ",");
419   enc_token_str = strtok (NULL, ",");
420
421   enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
422                                                 strlen (enc_token_str),
423                                                 &enc_token);
424   if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key,
425                                        aud_key,
426                                        enc_token,
427                                        enc_token_len,
428                                        &token_str))
429   {
430     GNUNET_free (tmp_buf);
431     GNUNET_free (enc_token);
432     return GNUNET_SYSERR;
433   }
434
435   GNUNET_assert (NULL != strtok (token_str, "."));
436   payload_base64 = strtok (NULL, ".");
437
438   *result = GNUNET_malloc (sizeof (struct IdentityToken));
439   parse_json_payload (payload_base64, *result);
440
441   (*result)->aud_key =  *aud_key;
442   GNUNET_free (enc_token);
443   GNUNET_free (token_str);
444   GNUNET_free (tmp_buf);
445   return GNUNET_OK;
446 }
447
448 int
449 token_parse (const char* raw_data,
450              const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
451              struct IdentityToken **result)
452 {
453   char *ecdh_pubkey_str;
454   char *enc_token_str;
455   char *tmp_buf;
456   char *token_str;
457   char *enc_token;
458   char *payload_base64;
459   size_t enc_token_len;
460   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
461
462   GNUNET_asprintf (&tmp_buf, "%s", raw_data);
463   ecdh_pubkey_str = strtok (tmp_buf, ",");
464   enc_token_str = strtok (NULL, ",");
465
466   GNUNET_assert (NULL != ecdh_pubkey_str);
467   GNUNET_assert (NULL != enc_token_str);
468
469   GNUNET_STRINGS_string_to_data (ecdh_pubkey_str,
470                                  strlen (ecdh_pubkey_str),
471                                  &ecdh_pubkey,
472                                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
473   enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
474                                                 strlen (enc_token_str),
475                                                 &enc_token);
476   if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
477                                       &ecdh_pubkey,
478                                       enc_token,
479                                       enc_token_len,
480                                       &token_str))
481   {
482     GNUNET_free (tmp_buf);
483     GNUNET_free (enc_token);
484     return GNUNET_SYSERR;
485   }
486
487   GNUNET_assert (NULL != strtok (token_str, "."));
488   payload_base64 = strtok (NULL, ".");
489
490   *result = GNUNET_malloc (sizeof (struct IdentityToken));
491   parse_json_payload (payload_base64, *result);
492
493   GNUNET_free (enc_token);
494   GNUNET_free (token_str);
495   GNUNET_free (tmp_buf);
496   return GNUNET_OK;
497 }
498
499 static char*
500 create_json_payload (const struct IdentityToken *token)
501 {
502   struct TokenAttr *attr;
503   struct TokenAttrValue *val;
504   json_t *root;
505   char *json_str;
506
507   root = json_object();
508   for (attr = token->attr_head; NULL != attr; attr = attr->next)
509   {
510     for (val = attr->val_head; NULL != val; val = val->next)
511     {
512       if (NULL != val->value)
513       {
514         json_object_set_new (root,
515                              attr->name,
516                              json_string (val->value)); 
517       } else if (NULL != val->json_value) {
518         json_object_set (root,
519                          attr->name,
520                          val->json_value);
521       }else {
522         json_object_set_new (root,
523                              attr->name,
524                              json_integer (val->int_value));
525       }
526     }
527   }
528   json_str = json_dumps (root, JSON_INDENT(1));
529   json_decref (root);
530   return json_str;
531 }
532
533 static char*
534 create_json_header(void)
535 {
536   json_t *root;
537   char *json_str;
538
539   root = json_object ();
540   json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
541   json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
542
543   json_str = json_dumps (root, JSON_INDENT(1));
544   json_decref (root);
545   return json_str;
546 }
547
548 int
549 token_to_string (const struct IdentityToken *token,
550                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
551                  char **result)
552 {
553   char *payload_str;
554   char *header_str;
555   char *payload_base64;
556   char *header_base64;
557   char *padding;
558   char *signature_target;
559   char *signature_str;
560   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
561   header_str = create_json_header();
562   GNUNET_STRINGS_base64_encode (header_str,
563                                 strlen (header_str),
564                                 &header_base64);
565   //Remove GNUNET padding of base64
566   padding = strtok(header_base64, "=");
567   while (NULL != padding)
568     padding = strtok(NULL, "=");
569
570   payload_str = create_json_payload (token);
571   GNUNET_STRINGS_base64_encode (payload_str,
572                                 strlen (payload_str),
573                                 &payload_base64);
574
575   //Remove GNUNET padding of base64
576   padding = strtok(payload_base64, "=");
577   while (NULL != padding)
578     padding = strtok(NULL, "=");
579
580   GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64);
581   purpose =
582     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
583                    strlen (signature_target));
584   purpose->size =
585     htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
586   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
587   GNUNET_memcpy (&purpose[1], signature_target, strlen (signature_target));
588   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
589                                              purpose,
590                                              (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature))
591   {
592     GNUNET_free (signature_target);
593     GNUNET_free (payload_str);
594     GNUNET_free (payload_base64);
595     GNUNET_free (header_base64);
596     GNUNET_free (purpose);
597     return GNUNET_SYSERR;
598   }
599
600   GNUNET_STRINGS_base64_encode ((const char*)&token->signature,
601                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
602                                 &signature_str);
603   GNUNET_asprintf (result, "%s.%s.%s",
604                    header_base64, payload_base64, signature_str);
605   GNUNET_free (signature_target);
606   GNUNET_free (payload_str);
607   GNUNET_free (header_str);
608   GNUNET_free (signature_str);
609   GNUNET_free (payload_base64);
610   GNUNET_free (header_base64);
611   GNUNET_free (purpose);
612   return GNUNET_OK;
613 }
614
615 int
616 token_serialize (const struct IdentityToken *token,
617                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
618                  struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
619                  char **result)
620 {
621   char *token_str;
622   char *enc_token;
623   char *dh_key_str;
624   char *enc_token_base64;
625   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
626
627   GNUNET_assert (GNUNET_OK == token_to_string (token,
628                                                priv_key,
629                                                &token_str));
630
631   GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str,
632                                                  &token->aud_key,
633                                                  &enc_token,
634                                                  ecdh_privkey,
635                                                  &ecdh_pubkey));
636   GNUNET_STRINGS_base64_encode (enc_token,
637                                 strlen (token_str),
638                                 &enc_token_base64);
639   dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey,
640                                                     sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
641   GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64);
642   GNUNET_free (dh_key_str);
643   GNUNET_free (enc_token_base64);
644   GNUNET_free (enc_token);
645   GNUNET_free (token_str);
646   return GNUNET_OK;
647 }
648
649 struct TokenTicketPayload*
650 ticket_payload_create (uint64_t nonce,
651                        const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
652                        const char* lbl_str)
653 {
654   struct TokenTicketPayload* payload;
655
656   payload = GNUNET_malloc (sizeof (struct TokenTicketPayload));
657   payload->nonce = nonce;
658   payload->identity_key = *identity_pkey;
659   GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str));
660   return payload;
661 }
662
663 void
664 ticket_payload_destroy (struct TokenTicketPayload* payload)
665 {
666   if (NULL != payload->label)
667     GNUNET_free (payload->label);
668   GNUNET_free (payload);
669 }
670
671 void
672 ticket_payload_serialize (struct TokenTicketPayload *payload,
673                           char **result)
674 {
675   char* identity_key_str;
676
677   identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key,
678                                                           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
679
680   GNUNET_asprintf (result, 
681                    "{\"nonce\": \"%"SCNu64"\",\"identity\": \"%s\",\"label\": \"%s\"}",
682                    payload->nonce, identity_key_str, payload->label);
683   GNUNET_free (identity_key_str);
684
685 }
686
687
688 /**
689  * Create the token code
690  * The data is encrypted with a share ECDH derived secret using B (aud_key)
691  * and e (ecdh_privkey)
692  * The ticket also contains E (ecdh_pubkey) and a signature over the
693  * data and E
694  */
695 struct TokenTicket*
696 ticket_create (uint64_t nonce,
697                const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
698                const char* lbl_str,
699                const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key)
700 {
701   struct TokenTicket *ticket;
702   struct TokenTicketPayload *code_payload;
703
704   ticket = GNUNET_malloc (sizeof (struct TokenTicket));
705   code_payload = ticket_payload_create (nonce,
706                                         identity_pkey,
707                                         lbl_str);
708   ticket->aud_key = *aud_key;
709   ticket->payload = code_payload;
710
711
712   return ticket;
713 }
714
715 void
716 ticket_destroy (struct TokenTicket *ticket)
717 {
718   ticket_payload_destroy (ticket->payload);
719   GNUNET_free (ticket);
720 }
721
722 int
723 ticket_serialize (struct TokenTicket *ticket,
724                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
725                   char **result)
726 {
727   char *code_payload_str;
728   char *enc_ticket_payload;
729   char *ticket_payload_str;
730   char *ticket_sig_str;
731   char *ticket_str;
732   char *dh_key_str;
733   char *write_ptr;
734   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
735
736   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
737
738   ticket_payload_serialize (ticket->payload,
739                             &code_payload_str);
740
741   GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str,
742                                                  &ticket->aud_key,
743                                                  &enc_ticket_payload,
744                                                  &ecdhe_privkey,
745                                                  &ticket->ecdh_pubkey));
746
747   GNUNET_free (ecdhe_privkey);
748
749   purpose = 
750     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + 
751                    sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
752                    strlen (code_payload_str)); // E_K (code_str)
753   purpose->size = 
754     htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
755            sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
756            strlen (code_payload_str));
757   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
758   write_ptr = (char*) &purpose[1];
759   GNUNET_memcpy (write_ptr,
760                  &ticket->ecdh_pubkey,
761                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
762   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
763   GNUNET_memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
764   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
765                                                         purpose,
766                                                         &ticket->signature));
767   GNUNET_STRINGS_base64_encode (enc_ticket_payload,
768                                 strlen (code_payload_str),
769                                 &ticket_payload_str);
770   ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature,
771                                                         sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
772
773   dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey,
774                                                     sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
775   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using ECDH pubkey %s to encrypt\n", dh_key_str);
776   GNUNET_asprintf (&ticket_str, "{\"data\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}",
777                    ticket_payload_str, dh_key_str, ticket_sig_str);
778   GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result);
779   GNUNET_free (dh_key_str);
780   GNUNET_free (purpose);
781   GNUNET_free (ticket_str);
782   GNUNET_free (ticket_sig_str);
783   GNUNET_free (code_payload_str);
784   GNUNET_free (enc_ticket_payload);
785   GNUNET_free (ticket_payload_str);
786   return GNUNET_OK;
787 }
788
789 int
790 ticket_payload_parse(const char *raw_data,
791                      ssize_t data_len,
792                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
793                      const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey,
794                      struct TokenTicketPayload **result)
795 {
796   const char* label_str;
797   const char* nonce_str;
798   const char* identity_key_str;
799
800   json_t *root;
801   json_t *label_json;
802   json_t *identity_json;
803   json_t *nonce_json;
804   json_error_t err_json;
805   char* data_str;
806   uint64_t nonce;
807   struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey;
808
809   if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
810                                       ecdhe_pkey,
811                                       raw_data,
812                                       data_len,
813                                       &data_str))
814   {
815     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Data decryption failed\n");
816     return GNUNET_SYSERR;
817   }
818
819   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data: %s\n", data_str);
820   root = json_loads (data_str, JSON_DECODE_ANY, &err_json);
821   if (!root)
822   {
823     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824                 "Error parsing data: %s\n", err_json.text);
825     GNUNET_free (data_str);
826     return GNUNET_SYSERR;
827   }
828
829   identity_json = json_object_get (root, "identity");
830   if (!json_is_string (identity_json))
831   {
832     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
833                 "Error parsing data: %s\n", err_json.text);
834     json_decref (root);
835     GNUNET_free (data_str);
836     return GNUNET_SYSERR;
837   }
838   identity_key_str = json_string_value (identity_json);
839   GNUNET_STRINGS_string_to_data (identity_key_str,
840                                  strlen (identity_key_str),
841                                  &id_pkey,
842                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
843
844
845   label_json = json_object_get (root, "label");
846   if (!json_is_string (label_json))
847   {
848     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
849                 "Error parsing data: %s\n", err_json.text);
850     json_decref (root);
851     GNUNET_free (data_str);
852     return GNUNET_SYSERR;
853   }
854
855   label_str = json_string_value (label_json);
856   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found label: %s\n", label_str);
857
858   nonce_json = json_object_get (root, "nonce");
859   if (!json_is_string (label_json))
860   {
861     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
862                 "Error parsing data: %s\n", err_json.text);
863     json_decref (root);
864     GNUNET_free (data_str);
865     return GNUNET_SYSERR;
866   }
867
868   nonce_str = json_string_value (nonce_json);
869   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found nonce: %s\n", nonce_str);
870
871   GNUNET_assert (0 != sscanf (nonce_str, "%"SCNu64, &nonce));
872
873   *result = ticket_payload_create (nonce,
874                                    (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey,
875                                    label_str);
876   GNUNET_free (data_str);
877   json_decref (root);
878   return GNUNET_OK;
879
880 }
881
882 int
883 ticket_parse (const char *raw_data,
884               const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
885               struct TokenTicket **result)
886 {
887   const char* enc_data_str;
888   const char* ecdh_enc_str;
889   const char* signature_enc_str;
890
891   json_t *root;
892   json_t *signature_json;
893   json_t *ecdh_json;
894   json_t *enc_data_json;
895   json_error_t err_json;
896   char* enc_data;
897   char* ticket_decoded;
898   char* write_ptr;
899   size_t enc_data_len;
900   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
901   struct TokenTicket *ticket;
902   struct TokenTicketPayload *ticket_payload;
903
904   ticket_decoded = NULL;
905   GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded);
906   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ticket: %s\n", ticket_decoded);
907   root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json);
908   if (!root)
909   {
910     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
911                 "%s\n", err_json.text);
912     return GNUNET_SYSERR;
913   }
914
915   signature_json = json_object_get (root, "signature");
916   ecdh_json = json_object_get (root, "ecdh");
917   enc_data_json = json_object_get (root, "data");
918
919   signature_enc_str = json_string_value (signature_json);
920   ecdh_enc_str = json_string_value (ecdh_json);
921   enc_data_str = json_string_value (enc_data_json);
922
923   ticket = GNUNET_malloc (sizeof (struct TokenTicket));
924
925   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str,
926                                                   strlen (ecdh_enc_str),
927                                                   &ticket->ecdh_pubkey,
928                                                   sizeof  (struct GNUNET_CRYPTO_EcdhePublicKey)))
929   {
930     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in data\n", ecdh_enc_str);
931     json_decref (root);
932     GNUNET_free (ticket);
933     return GNUNET_SYSERR;
934   }
935   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using ECDH pubkey %s for data decryption\n", ecdh_enc_str);
936   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str,
937                                                   strlen (signature_enc_str),
938                                                   &ticket->signature,
939                                                   sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
940   {
941     json_decref (root);
942     GNUNET_free (ticket_decoded);
943     GNUNET_free (ticket);
944     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in data\n");
945     return GNUNET_SYSERR;
946   }
947
948   enc_data_len = GNUNET_STRINGS_base64_decode (enc_data_str,
949                                                strlen (enc_data_str),
950                                                &enc_data);
951
952
953   if (GNUNET_OK != ticket_payload_parse (enc_data,
954                                          enc_data_len,
955                                          priv_key,
956                                          (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey,
957                                          &ticket_payload))
958   {
959     json_decref (root);
960     GNUNET_free (enc_data);
961     GNUNET_free (ticket_decoded);
962     GNUNET_free (ticket);
963     return GNUNET_SYSERR;
964   }
965
966   ticket->payload = ticket_payload;
967   purpose = 
968     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + 
969                    sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
970                    enc_data_len); // E_K (code_str)
971   purpose->size = 
972     htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
973            sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
974            enc_data_len);
975   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
976   write_ptr = (char*) &purpose[1];
977   GNUNET_memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
978   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
979   GNUNET_memcpy (write_ptr, enc_data, enc_data_len);
980
981   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET,
982                                                purpose,
983                                                &ticket->signature,
984                                                &ticket_payload->identity_key))
985   {
986     ticket_destroy (ticket);
987     GNUNET_free (ticket_decoded);
988     json_decref (root);
989     GNUNET_free (purpose);
990     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
991                 "Error verifying signature for ticket\n");
992     return GNUNET_SYSERR;
993   }
994   *result = ticket;
995   GNUNET_free (purpose);
996
997   GNUNET_free (enc_data);
998   GNUNET_free (ticket_decoded);
999   json_decref (root);
1000   return GNUNET_OK;
1001
1002 }
1003
1004
1005
1006 /* end of identity_token.c */