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