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