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