- refactor
[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_ERROR, "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_ERROR, "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_ERROR, "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_ERROR, "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       GNUNET_free (val->value);
242       GNUNET_free (val);
243       val = tmp_val;
244     }
245     GNUNET_free (attr->name);
246     GNUNET_free (attr);
247     attr = tmp_attr;
248   }
249
250   
251   GNUNET_free (token);
252 }
253
254 void
255 token_add_attr (struct IdentityToken *token,
256                 const char* key,
257                 const char* value)
258 {
259   struct TokenAttr *attr;
260   struct TokenAttrValue *new_val;
261   GNUNET_assert (NULL != token);
262
263   new_val = GNUNET_malloc (sizeof (struct TokenAttrValue));
264   new_val->value = GNUNET_strdup (value);
265   for (attr = token->attr_head; NULL != attr; attr = attr->next)
266   {
267     if (0 == strcmp (key, attr->name))
268       break;
269   }
270
271   if (NULL == attr)
272   {
273     attr = GNUNET_malloc (sizeof (struct TokenAttr));
274     attr->name = GNUNET_strdup (key);
275     GNUNET_CONTAINER_DLL_insert (token->attr_head,
276                                  token->attr_tail,
277                                  attr);
278   }
279
280   GNUNET_CONTAINER_DLL_insert (attr->val_head,
281                                attr->val_tail,
282                                new_val);
283 }
284
285 static void
286 parse_json_payload(const char* payload_base64,
287                    struct IdentityToken *token) 
288 {
289   const char *key;
290   const json_t *value;
291   const json_t *arr_value;
292   char *payload;
293   int idx;
294   json_t *payload_json;
295   json_error_t err_json;
296
297   GNUNET_STRINGS_base64_decode (payload_base64,
298                                 strlen (payload_base64),
299                                 &payload);
300   //TODO signature and aud key
301   payload_json = json_loads (payload, JSON_DECODE_ANY, &err_json);
302
303   json_object_foreach (payload_json, key, value)
304   {
305     if (json_is_array (value))
306     {
307       json_array_foreach (value, idx, arr_value)
308       {
309         token_add_attr (token,
310                         key,
311                         json_string_value (arr_value));
312       }
313     } else {
314       token_add_attr (token, key, json_string_value (value));
315     }
316   }
317
318   GNUNET_free (payload);
319 }
320
321 int
322 token_parse2 (const char* raw_data,
323               const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
324               const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
325               struct IdentityToken **result)
326 {
327   char *enc_token_str;
328   char *tmp_buf;
329   char *token_str;
330   char *enc_token;
331   char *payload_base64;
332   size_t enc_token_len;
333
334   GNUNET_asprintf (&tmp_buf, "%s", raw_data);
335   strtok (tmp_buf, ",");
336   enc_token_str = strtok (NULL, ",");
337
338   enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
339                                                 strlen (enc_token_str),
340                                                 &enc_token);
341   if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key,
342                                        aud_key,
343                                        enc_token,
344                                        enc_token_len,
345                                        &token_str))
346   {
347     GNUNET_free (tmp_buf);
348     GNUNET_free (enc_token);
349     return GNUNET_SYSERR;
350   }
351
352   GNUNET_assert (NULL != strtok (token_str, "."));
353   payload_base64 = strtok (NULL, ".");
354
355   *result = GNUNET_malloc (sizeof (struct IdentityToken));
356   parse_json_payload (payload_base64, *result);
357
358   (*result)->aud_key =  *aud_key;
359   GNUNET_free (enc_token);
360   GNUNET_free (token_str);
361   GNUNET_free (tmp_buf);
362   return GNUNET_OK;
363 }
364
365 int
366 token_parse (const char* raw_data,
367              const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
368              struct IdentityToken **result)
369 {
370   char *ecdh_pubkey_str;
371   char *enc_token_str;
372   char *tmp_buf;
373   char *token_str;
374   char *enc_token;
375   char *payload_base64;
376   size_t enc_token_len;
377   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
378
379   GNUNET_asprintf (&tmp_buf, "%s", raw_data);
380   ecdh_pubkey_str = strtok (tmp_buf, ",");
381   enc_token_str = strtok (NULL, ",");
382
383   GNUNET_STRINGS_string_to_data (ecdh_pubkey_str,
384                                  strlen (ecdh_pubkey_str),
385                                  &ecdh_pubkey,
386                                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
387   enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
388                                                 strlen (enc_token_str),
389                                                 &enc_token);
390   if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
391                                       &ecdh_pubkey,
392                                       enc_token,
393                                       enc_token_len,
394                                       &token_str))
395   {
396     GNUNET_free (tmp_buf);
397     GNUNET_free (enc_token);
398     return GNUNET_SYSERR;
399   }
400
401   GNUNET_assert (NULL != strtok (token_str, "."));
402   payload_base64 = strtok (NULL, ".");
403
404   *result = GNUNET_malloc (sizeof (struct IdentityToken));
405   parse_json_payload (payload_base64, *result);
406
407   GNUNET_free (enc_token);
408   GNUNET_free (token_str);
409   GNUNET_free (tmp_buf);
410   return GNUNET_OK;
411 }
412
413 static char*
414 create_json_payload (const struct IdentityToken *token)
415 {
416   struct TokenAttr *attr;
417   struct TokenAttrValue *val;
418   json_t *root;
419   char *json_str;
420
421   root = json_object();
422   for (attr = token->attr_head; NULL != attr; attr = attr->next)
423   {
424     for (val = attr->val_head; NULL != val; val = val->next)
425     {
426       json_object_set_new (root,
427                            attr->name,
428                            json_string (val->value)); 
429     }
430   }
431   json_str = json_dumps (root, JSON_INDENT(1));
432   json_decref (root);
433   return json_str;
434 }
435
436 static char*
437 create_json_header(void)
438 {
439   json_t *root;
440   char *json_str;
441
442   root = json_object ();
443   json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE));
444   json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE));
445
446   json_str = json_dumps (root, JSON_INDENT(1));
447   json_decref (root);
448   return json_str;
449 }
450
451 int
452 token_to_string (const struct IdentityToken *token,
453                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
454                  char **result)
455 {
456   char *payload_str;
457   char *header_str;
458   char *payload_base64;
459   char *header_base64;
460   char *padding;
461   char *signature_target;
462   char *signature_str;
463   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
464   header_str = create_json_header();
465   GNUNET_STRINGS_base64_encode (header_str,
466                                 strlen (header_str),
467                                 &header_base64);
468   //Remove GNUNET padding of base64
469   padding = strtok(header_base64, "=");
470   while (NULL != padding)
471     padding = strtok(NULL, "=");
472
473   payload_str = create_json_payload (token);
474   GNUNET_STRINGS_base64_encode (payload_str,
475                                 strlen (payload_str),
476                                 &payload_base64);
477
478   //Remove GNUNET padding of base64
479   padding = strtok(payload_base64, "=");
480   while (NULL != padding)
481     padding = strtok(NULL, "=");
482
483   GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64);
484   purpose =
485     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
486                    strlen (signature_target));
487   purpose->size =
488     htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
489   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
490   memcpy (&purpose[1], signature_target, strlen (signature_target));
491   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
492                                              purpose,
493                                              (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature))
494   {
495     GNUNET_free (signature_target);
496     GNUNET_free (payload_str);
497     GNUNET_free (payload_base64);
498     GNUNET_free (purpose);
499     return GNUNET_SYSERR;
500   }
501
502   GNUNET_STRINGS_base64_encode ((const char*)&token->signature,
503                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
504                                 &signature_str);
505   GNUNET_asprintf (result, "%s.%s.%s",
506                    header_base64, payload_base64, signature_str);
507   GNUNET_free (signature_target);
508   GNUNET_free (payload_str);
509   GNUNET_free (header_str);
510   GNUNET_free (signature_str);
511   GNUNET_free (payload_base64);
512   GNUNET_free (header_base64);
513   GNUNET_free (purpose);
514   return GNUNET_OK;
515 }
516
517 int
518 token_serialize (const struct IdentityToken *token,
519                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
520                  struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
521                  char **result)
522 {
523   char *token_str;
524   char *enc_token;
525   char *dh_key_str;
526   char *enc_token_base64;
527   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
528
529   GNUNET_assert (GNUNET_OK == token_to_string (token,
530                                                priv_key,
531                                                &token_str));
532
533   GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str,
534                                                  &token->aud_key,
535                                                  &enc_token,
536                                                  ecdh_privkey,
537                                                  &ecdh_pubkey));
538   GNUNET_STRINGS_base64_encode (enc_token,
539                                 strlen (token_str),
540                                 &enc_token_base64);
541   dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey,
542                                                     sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
543   GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64);
544   GNUNET_free (dh_key_str);
545   GNUNET_free (enc_token_base64);
546   GNUNET_free (enc_token);
547   GNUNET_free (token_str);
548   return GNUNET_OK;
549 }
550
551 struct TokenTicketPayload*
552 ticket_payload_create (const char* nonce,
553                        const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
554                        const char* lbl_str)
555 {
556   struct TokenTicketPayload* payload;
557
558   payload = GNUNET_malloc (sizeof (struct TokenTicketPayload));
559   GNUNET_asprintf (&payload->nonce, nonce, strlen (nonce));
560   payload->identity_key = *identity_pkey;
561   GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str));
562   return payload;
563 }
564
565 void
566 ticket_payload_destroy (struct TokenTicketPayload* payload)
567 {
568   if (NULL != payload->nonce)
569     GNUNET_free (payload->nonce);
570   if (NULL != payload->label)
571     GNUNET_free (payload->label);
572   GNUNET_free (payload);
573 }
574
575 void
576 ticket_payload_serialize (struct TokenTicketPayload *payload,
577                           char **result)
578 {
579   char* identity_key_str;
580
581   identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key,
582                                                           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
583
584   GNUNET_asprintf (result, 
585                    "{\"nonce\": \"%u\",\"identity\": \"%s\",\"label\": \"%s\"}",
586                    payload->nonce, identity_key_str, payload->label);
587   GNUNET_free (identity_key_str);
588
589 }
590
591
592 /**
593  * Create the token code
594  * The metadata is encrypted with a share ECDH derived secret using B (aud_key)
595  * and e (ecdh_privkey)
596  * The ticket also contains E (ecdh_pubkey) and a signature over the
597  * metadata and E
598  */
599 struct TokenTicket*
600 ticket_create (const char* nonce_str,
601                const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
602                const char* lbl_str,
603                const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key)
604 {
605   struct TokenTicket *ticket;
606   struct TokenTicketPayload *code_payload;
607
608   ticket = GNUNET_malloc (sizeof (struct TokenTicket));
609   code_payload = ticket_payload_create (nonce_str,
610                                         identity_pkey,
611                                         lbl_str);
612   ticket->aud_key = *aud_key;
613   ticket->payload = code_payload;
614
615
616   return ticket;
617 }
618
619 void
620 ticket_destroy (struct TokenTicket *ticket)
621 {
622   ticket_payload_destroy (ticket->payload);
623   GNUNET_free (ticket);
624 }
625
626 int
627 ticket_serialize (struct TokenTicket *ticket,
628                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
629                   char **result)
630 {
631   char *code_payload_str;
632   char *enc_ticket_payload;
633   char *ticket_payload_str;
634   char *ticket_sig_str;
635   char *ticket_str;
636   char *dh_key_str;
637   char *write_ptr;
638   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
639
640   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
641
642   ticket_payload_serialize (ticket->payload,
643                             &code_payload_str);
644
645   GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str,
646                                                  &ticket->aud_key,
647                                                  &enc_ticket_payload,
648                                                  &ecdhe_privkey,
649                                                  &ticket->ecdh_pubkey));
650
651   GNUNET_free (ecdhe_privkey);
652
653   purpose = 
654     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + 
655                    sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
656                    strlen (code_payload_str)); // E_K (code_str)
657   purpose->size = 
658     htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
659            sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
660            strlen (code_payload_str));
661   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
662   write_ptr = (char*) &purpose[1];
663   memcpy (write_ptr,
664           &ticket->ecdh_pubkey,
665           sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
666   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
667   memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
668   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
669                                                         purpose,
670                                                         &ticket->signature));
671   GNUNET_STRINGS_base64_encode (enc_ticket_payload,
672                                 strlen (code_payload_str),
673                                 &ticket_payload_str);
674   ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature,
675                                                         sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
676
677   dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey,
678                                                     sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
679   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s to encrypt\n", dh_key_str);
680   GNUNET_asprintf (&ticket_str, "{\"meta\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}",
681                    ticket_payload_str, dh_key_str, ticket_sig_str);
682   GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result);
683   GNUNET_free (dh_key_str);
684   GNUNET_free (purpose);
685   GNUNET_free (ticket_str);
686   GNUNET_free (ticket_sig_str);
687   GNUNET_free (code_payload_str);
688   GNUNET_free (enc_ticket_payload);
689   GNUNET_free (ticket_payload_str);
690   return GNUNET_OK;
691 }
692
693 int
694 ticket_payload_parse(const char *raw_data,
695                      ssize_t data_len,
696                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
697                      const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey,
698                      struct TokenTicketPayload **result)
699 {
700   const char* label_str;
701   const char* nonce_str;
702   const char* identity_key_str;
703
704   json_t *root;
705   json_t *label_json;
706   json_t *identity_json;
707   json_t *nonce_json;
708   json_error_t err_json;
709   char* meta_str;
710   struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey;
711
712   if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
713                                       ecdhe_pkey,
714                                       raw_data,
715                                       data_len,
716                                       &meta_str))
717   {
718     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata decryption failed\n");
719     return GNUNET_SYSERR;
720   }
721
722   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata: %s\n", meta_str);
723   root = json_loads (meta_str, JSON_DECODE_ANY, &err_json);
724   if (!root)
725   {
726     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
727                 "Error parsing metadata: %s\n", err_json.text);
728     GNUNET_free (meta_str);
729     return GNUNET_SYSERR;
730   }
731
732   identity_json = json_object_get (root, "identity");
733   if (!json_is_string (identity_json))
734   {
735     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
736                 "Error parsing metadata: %s\n", err_json.text);
737     json_decref (root);
738     GNUNET_free (meta_str);
739     return GNUNET_SYSERR;
740   }
741   identity_key_str = json_string_value (identity_json);
742   GNUNET_STRINGS_string_to_data (identity_key_str,
743                                  strlen (identity_key_str),
744                                  &id_pkey,
745                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
746
747
748   label_json = json_object_get (root, "label");
749   if (!json_is_string (label_json))
750   {
751     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
752                 "Error parsing metadata: %s\n", err_json.text);
753     json_decref (root);
754     GNUNET_free (meta_str);
755     return GNUNET_SYSERR;
756   }
757
758   label_str = json_string_value (label_json);
759   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found label: %s\n", label_str);
760
761   nonce_json = json_object_get (root, "nonce");
762   if (!json_is_string (label_json))
763   {
764     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
765                 "Error parsing metadata: %s\n", err_json.text);
766     json_decref (root);
767     GNUNET_free (meta_str);
768     return GNUNET_SYSERR;
769   }
770
771   nonce_str = json_string_value (nonce_json);
772   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found nonce: %s\n", nonce_str);
773
774   *result = ticket_payload_create (nonce_str,
775                                    (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey,
776                                    label_str);
777   GNUNET_free (meta_str);
778   json_decref (root);
779   return GNUNET_OK;
780
781 }
782
783 int
784 ticket_parse (const char *raw_data,
785               const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
786               struct TokenTicket **result)
787 {
788   const char* enc_meta_str;
789   const char* ecdh_enc_str;
790   const char* signature_enc_str;
791
792   json_t *root;
793   json_t *signature_json;
794   json_t *ecdh_json;
795   json_t *enc_meta_json;
796   json_error_t err_json;
797   char* enc_meta;
798   char* ticket_decoded;
799   char* write_ptr;
800   size_t enc_meta_len;
801   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
802   struct TokenTicket *ticket;
803   struct TokenTicketPayload *ticket_payload;
804
805   ticket_decoded = NULL;
806   GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded);
807   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Token Code: %s\n", ticket_decoded);
808   root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json);
809   if (!root)
810   {
811     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
812                 "%s\n", err_json.text);
813     return GNUNET_SYSERR;
814   }
815
816   signature_json = json_object_get (root, "signature");
817   ecdh_json = json_object_get (root, "ecdh");
818   enc_meta_json = json_object_get (root, "meta");
819
820   signature_enc_str = json_string_value (signature_json);
821   ecdh_enc_str = json_string_value (ecdh_json);
822   enc_meta_str = json_string_value (enc_meta_json);
823
824   ticket = GNUNET_malloc (sizeof (struct TokenTicket));
825
826   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str,
827                                                   strlen (ecdh_enc_str),
828                                                   &ticket->ecdh_pubkey,
829                                                   sizeof  (struct GNUNET_CRYPTO_EcdhePublicKey)))
830   {
831     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in metadata\n", ecdh_enc_str);
832     json_decref (root);
833     GNUNET_free (ticket);
834     return GNUNET_SYSERR;
835   }
836   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s for metadata decryption\n", ecdh_enc_str);
837   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str,
838                                                   strlen (signature_enc_str),
839                                                   &ticket->signature,
840                                                   sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
841   {
842     json_decref (root);
843     GNUNET_free (ticket_decoded);
844     GNUNET_free (ticket);
845     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in metadata\n");
846     return GNUNET_SYSERR;
847   }
848
849   enc_meta_len = GNUNET_STRINGS_base64_decode (enc_meta_str,
850                                                strlen (enc_meta_str),
851                                                &enc_meta);
852
853
854   if (GNUNET_OK != ticket_payload_parse (enc_meta,
855                                          enc_meta_len,
856                                          priv_key,
857                                          (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey,
858                                          &ticket_payload))
859   {
860     json_decref (root);
861     GNUNET_free (enc_meta);
862     GNUNET_free (ticket_decoded);
863     GNUNET_free (ticket);
864     return GNUNET_SYSERR;
865   }
866
867   ticket->payload = ticket_payload;
868   //TODO: check signature here
869   purpose = 
870     GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + 
871                    sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
872                    enc_meta_len); // E_K (code_str)
873   purpose->size = 
874     htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
875            sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
876            enc_meta_len);
877   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
878   write_ptr = (char*) &purpose[1];
879   memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
880   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
881   memcpy (write_ptr, enc_meta, enc_meta_len);
882
883   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET,
884                                                purpose,
885                                                &ticket->signature,
886                                                &ticket_payload->identity_key))
887   {
888     ticket_destroy (ticket);
889     GNUNET_free (ticket_decoded);
890     json_decref (root);
891     GNUNET_free (purpose);
892     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
893                 "Error verifying signature for token code\n");
894     return GNUNET_SYSERR;
895   }
896   *result = ticket;
897   GNUNET_free (purpose);
898
899   GNUNET_free (enc_meta);
900   GNUNET_free (ticket_decoded);
901   json_decref (root);
902   return GNUNET_OK;
903
904 }
905
906
907
908 /* end of identity_token.c */