diff options
Diffstat (limited to 'src/lib/anastasis_recovery.c')
-rw-r--r-- | src/lib/anastasis_recovery.c | 1425 |
1 files changed, 1425 insertions, 0 deletions
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c new file mode 100644 index 0000000..5b0726f --- /dev/null +++ b/src/lib/anastasis_recovery.c | |||
@@ -0,0 +1,1425 @@ | |||
1 | /* | ||
2 | This file is part of Anastasis | ||
3 | Copyright (C) 2020, 2021 Taler Systems SA | ||
4 | |||
5 | Anastasis is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU Lesser General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | /** | ||
17 | * @brief anastasis client api | ||
18 | * @author Christian Grothoff | ||
19 | * @author Dominik Meister | ||
20 | * @author Dennis Neufeld | ||
21 | */ | ||
22 | #include "platform.h" | ||
23 | #include "anastasis.h" | ||
24 | #include <taler/taler_json_lib.h> | ||
25 | #include <gnunet/gnunet_util_lib.h> | ||
26 | #include <taler/taler_merchant_service.h> | ||
27 | #include <zlib.h> | ||
28 | |||
29 | |||
30 | /** | ||
31 | * Challenge struct contains the uuid and public key's needed for the | ||
32 | * recovery process and a reference to ANASTASIS_Recovery. | ||
33 | */ | ||
34 | struct ANASTASIS_Challenge | ||
35 | { | ||
36 | |||
37 | /** | ||
38 | * Information exported to clients about this challenge. | ||
39 | */ | ||
40 | struct ANASTASIS_ChallengeDetails ci; | ||
41 | |||
42 | /** | ||
43 | * Key used to encrypt the truth passed to the server | ||
44 | */ | ||
45 | struct ANASTASIS_CRYPTO_TruthKeyP truth_key; | ||
46 | |||
47 | /** | ||
48 | * Salt; used to derive hash from security question answers. | ||
49 | */ | ||
50 | struct ANASTASIS_CRYPTO_QuestionSaltP salt; | ||
51 | |||
52 | /** | ||
53 | * Provider salt; used to derive our key material from our identity | ||
54 | * key. | ||
55 | */ | ||
56 | struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; | ||
57 | |||
58 | /** | ||
59 | * Decrypted key share for this challenge. Set once the | ||
60 | * challenge was @e ri.solved. | ||
61 | */ | ||
62 | struct ANASTASIS_CRYPTO_KeyShareP key_share; | ||
63 | |||
64 | /** | ||
65 | * Callback which gives back the instructions and a status code of | ||
66 | * the request to the user when answering a challenge was initiated. | ||
67 | */ | ||
68 | ANASTASIS_AnswerFeedback af; | ||
69 | |||
70 | /** | ||
71 | * Closure for the challenge callback | ||
72 | */ | ||
73 | void *af_cls; | ||
74 | |||
75 | /** | ||
76 | * Defines the base URL of the Anastasis provider used for the challenge. | ||
77 | */ | ||
78 | char *url; | ||
79 | |||
80 | /** | ||
81 | * What is the type of this challenge (E-Mail, Security Question, SMS...) | ||
82 | */ | ||
83 | char *type; | ||
84 | |||
85 | /** | ||
86 | * Instructions for solving the challenge (generic, set client-side | ||
87 | * when challenge was established). | ||
88 | */ | ||
89 | char *instructions; | ||
90 | |||
91 | /** | ||
92 | * Answer to the security question, if @a type is "question". Otherwise NULL. | ||
93 | */ | ||
94 | char *answer; | ||
95 | |||
96 | /** | ||
97 | * Reference to the recovery process which is ongoing | ||
98 | */ | ||
99 | struct ANASTASIS_Recovery *recovery; | ||
100 | |||
101 | /** | ||
102 | * keyshare lookup operation | ||
103 | */ | ||
104 | struct ANASTASIS_KeyShareLookupOperation *kslo; | ||
105 | |||
106 | }; | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Defines a decryption policy with multiple escrow methods | ||
111 | */ | ||
112 | struct DecryptionPolicy | ||
113 | { | ||
114 | |||
115 | /** | ||
116 | * Publicly visible details about a decryption policy. | ||
117 | */ | ||
118 | struct ANASTASIS_DecryptionPolicy pub_details; | ||
119 | |||
120 | /** | ||
121 | * Encrypted masterkey (encrypted with the policy key). | ||
122 | */ | ||
123 | struct ANASTASIS_CRYPTO_EncryptedMasterKeyP emk; | ||
124 | |||
125 | /** | ||
126 | * Salt used to decrypt master key. | ||
127 | */ | ||
128 | struct ANASTASIS_CRYPTO_MasterSaltP salt; | ||
129 | |||
130 | }; | ||
131 | |||
132 | |||
133 | /** | ||
134 | * stores provider URLs, identity key material, decrypted recovery document (internally!) | ||
135 | */ | ||
136 | struct ANASTASIS_Recovery | ||
137 | { | ||
138 | |||
139 | /** | ||
140 | * Identity key material used for the derivation of keys | ||
141 | */ | ||
142 | struct ANASTASIS_CRYPTO_UserIdentifierP id; | ||
143 | |||
144 | /** | ||
145 | * Recovery information which is given to the user | ||
146 | */ | ||
147 | struct ANASTASIS_RecoveryInformation ri; | ||
148 | |||
149 | /** | ||
150 | * Internal of @e ri.dps_len policies that would allow recovery of the core secret. | ||
151 | */ | ||
152 | struct DecryptionPolicy *dps; | ||
153 | |||
154 | /** | ||
155 | * Array of @e ri.cs_len challenges to be solved (for any of the policies). | ||
156 | */ | ||
157 | struct ANASTASIS_Challenge *cs; | ||
158 | |||
159 | /** | ||
160 | * Identity data to user id from. | ||
161 | */ | ||
162 | json_t *id_data; | ||
163 | |||
164 | /** | ||
165 | * Callback to send back a recovery document with the policies and the version | ||
166 | */ | ||
167 | ANASTASIS_PolicyCallback pc; | ||
168 | |||
169 | /** | ||
170 | * closure for the Policy callback | ||
171 | */ | ||
172 | void *pc_cls; | ||
173 | |||
174 | /** | ||
175 | * Callback to send back the core secret which was saved by | ||
176 | * anastasis, after all challenges are completed | ||
177 | */ | ||
178 | ANASTASIS_CoreSecretCallback csc; | ||
179 | |||
180 | /** | ||
181 | * Closure for the core secret callback | ||
182 | */ | ||
183 | void *csc_cls; | ||
184 | |||
185 | /** | ||
186 | * Curl context | ||
187 | */ | ||
188 | struct GNUNET_CURL_Context *ctx; | ||
189 | |||
190 | /** | ||
191 | * Reference to the policy lookup operation which is executed | ||
192 | */ | ||
193 | struct ANASTASIS_PolicyLookupOperation *plo; | ||
194 | |||
195 | /** | ||
196 | * Array of challenges that have been solved. | ||
197 | * Valid entries up to @e solved_challenge_pos. | ||
198 | * Length matches the total number of challenges in @e ri. | ||
199 | */ | ||
200 | struct ANASTASIS_Challenge **solved_challenges; | ||
201 | |||
202 | /** | ||
203 | * Our provider URL. | ||
204 | */ | ||
205 | char *provider_url; | ||
206 | |||
207 | /** | ||
208 | * Name of the secret, can be NULL. | ||
209 | */ | ||
210 | char *secret_name; | ||
211 | |||
212 | /** | ||
213 | * Task to run @e pc asynchronously. | ||
214 | */ | ||
215 | struct GNUNET_SCHEDULER_Task *do_async; | ||
216 | |||
217 | /** | ||
218 | * Retrieved encrypted core secret from policy | ||
219 | */ | ||
220 | void *enc_core_secret; | ||
221 | |||
222 | /** | ||
223 | * Size of the @e enc_core_secret | ||
224 | */ | ||
225 | size_t enc_core_secret_size; | ||
226 | |||
227 | /** | ||
228 | * Current offset in the @e solved_challenges array. | ||
229 | */ | ||
230 | unsigned int solved_challenge_pos; | ||
231 | |||
232 | }; | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Function called with the results of a #ANASTASIS_keyshare_lookup(). | ||
237 | * | ||
238 | * @param cls closure | ||
239 | * @param http_status HTTP status of the request | ||
240 | * @param ud details about the lookup operation | ||
241 | */ | ||
242 | static void | ||
243 | keyshare_lookup_cb (void *cls, | ||
244 | const struct ANASTASIS_KeyShareDownloadDetails *dd) | ||
245 | { | ||
246 | struct ANASTASIS_Challenge *c = cls; | ||
247 | struct ANASTASIS_Recovery *recovery = c->recovery; | ||
248 | struct ANASTASIS_CRYPTO_UserIdentifierP id; | ||
249 | struct DecryptionPolicy *rdps; | ||
250 | |||
251 | c->kslo = NULL; | ||
252 | switch (dd->status) | ||
253 | { | ||
254 | case ANASTASIS_KSD_SUCCESS: | ||
255 | break; | ||
256 | case ANASTASIS_KSD_PAYMENT_REQUIRED: | ||
257 | { | ||
258 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
259 | .cs = ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED, | ||
260 | .challenge = c, | ||
261 | .details.payment_required.taler_pay_uri | ||
262 | = dd->details.payment_required.taler_pay_uri, | ||
263 | .details.payment_required.payment_secret | ||
264 | = dd->details.payment_required.payment_secret | ||
265 | }; | ||
266 | |||
267 | c->af (c->af_cls, | ||
268 | &csr); | ||
269 | return; | ||
270 | } | ||
271 | case ANASTASIS_KSD_INVALID_ANSWER: | ||
272 | { | ||
273 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
274 | .cs = ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS, | ||
275 | .challenge = c, | ||
276 | .details.open_challenge.body | ||
277 | = dd->details.open_challenge.body, | ||
278 | .details.open_challenge.content_type | ||
279 | = dd->details.open_challenge.content_type, | ||
280 | .details.open_challenge.body_size | ||
281 | = dd->details.open_challenge.body_size, | ||
282 | .details.open_challenge.http_status | ||
283 | = dd->details.open_challenge.http_status | ||
284 | }; | ||
285 | |||
286 | c->af (c->af_cls, | ||
287 | &csr); | ||
288 | return; | ||
289 | } | ||
290 | case ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION: | ||
291 | { | ||
292 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
293 | .cs = ANASTASIS_CHALLENGE_STATUS_REDIRECT_FOR_AUTHENTICATION, | ||
294 | .challenge = c, | ||
295 | .details.redirect_url | ||
296 | = dd->details.redirect_url | ||
297 | }; | ||
298 | |||
299 | c->af (c->af_cls, | ||
300 | &csr); | ||
301 | return; | ||
302 | } | ||
303 | case ANASTASIS_KSD_TRUTH_UNKNOWN: | ||
304 | { | ||
305 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
306 | .cs = ANASTASIS_CHALLENGE_STATUS_TRUTH_UNKNOWN, | ||
307 | .challenge = c | ||
308 | }; | ||
309 | |||
310 | c->af (c->af_cls, | ||
311 | &csr); | ||
312 | return; | ||
313 | } | ||
314 | case ANASTASIS_KSD_RATE_LIMIT_EXCEEDED: | ||
315 | { | ||
316 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
317 | .cs = ANASTASIS_CHALLENGE_STATUS_RATE_LIMIT_EXCEEDED, | ||
318 | .challenge = c | ||
319 | }; | ||
320 | |||
321 | c->af (c->af_cls, | ||
322 | &csr); | ||
323 | return; | ||
324 | } | ||
325 | case ANASTASIS_KSD_SERVER_ERROR: | ||
326 | case ANASTASIS_KSD_CLIENT_FAILURE: | ||
327 | { | ||
328 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
329 | .cs = ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE, | ||
330 | .challenge = c, | ||
331 | .details.server_failure.ec | ||
332 | = dd->details.server_failure.ec, | ||
333 | .details.server_failure.http_status | ||
334 | = dd->details.server_failure.http_status | ||
335 | }; | ||
336 | |||
337 | c->af (c->af_cls, | ||
338 | &csr); | ||
339 | return; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | GNUNET_assert (NULL != dd); | ||
344 | ANASTASIS_CRYPTO_user_identifier_derive (recovery->id_data, | ||
345 | &c->provider_salt, | ||
346 | &id); | ||
347 | ANASTASIS_CRYPTO_keyshare_decrypt (&dd->details.eks, | ||
348 | &id, | ||
349 | c->answer, | ||
350 | &c->key_share); | ||
351 | recovery->solved_challenges[recovery->solved_challenge_pos++] = c; | ||
352 | |||
353 | { | ||
354 | struct ANASTASIS_ChallengeStartResponse csr = { | ||
355 | .cs = ANASTASIS_CHALLENGE_STATUS_SOLVED, | ||
356 | .challenge = c | ||
357 | }; | ||
358 | |||
359 | c->ci.solved = true; | ||
360 | c->af (c->af_cls, | ||
361 | &csr); | ||
362 | } | ||
363 | |||
364 | |||
365 | /* Check if there is a policy for which all challenges have | ||
366 | been satisfied, if so, store it in 'rdps'. */ | ||
367 | rdps = NULL; | ||
368 | for (unsigned int i = 0; i < recovery->ri.dps_len; i++) | ||
369 | { | ||
370 | struct DecryptionPolicy *dps = &recovery->dps[i]; | ||
371 | bool missing = false; | ||
372 | |||
373 | for (unsigned int j = 0; j < dps->pub_details.challenges_length; j++) | ||
374 | { | ||
375 | bool found = false; | ||
376 | |||
377 | for (unsigned int k = 0; k < recovery->solved_challenge_pos; k++) | ||
378 | { | ||
379 | if (dps->pub_details.challenges[j] == recovery->solved_challenges[k]) | ||
380 | { | ||
381 | found = true; | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | if (! found) | ||
386 | { | ||
387 | missing = true; | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | if (! missing) | ||
392 | { | ||
393 | rdps = dps; | ||
394 | break; | ||
395 | } | ||
396 | } | ||
397 | if (NULL == rdps) | ||
398 | return; | ||
399 | |||
400 | { | ||
401 | void *core_secret; | ||
402 | size_t core_secret_size; | ||
403 | struct ANASTASIS_CRYPTO_KeyShareP | ||
404 | key_shares[rdps->pub_details.challenges_length]; | ||
405 | struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; | ||
406 | |||
407 | for (unsigned int l = 0; l < rdps->pub_details.challenges_length; l++) | ||
408 | for (unsigned int m = 0; m < recovery->solved_challenge_pos; m++) | ||
409 | if (rdps->pub_details.challenges[l] == recovery->solved_challenges[m]) | ||
410 | key_shares[l] = recovery->solved_challenges[m]->key_share; | ||
411 | ANASTASIS_CRYPTO_policy_key_derive (key_shares, | ||
412 | rdps->pub_details.challenges_length, | ||
413 | &rdps->salt, | ||
414 | &policy_key); | ||
415 | ANASTASIS_CRYPTO_core_secret_recover (&rdps->emk, | ||
416 | &policy_key, | ||
417 | recovery->enc_core_secret, | ||
418 | recovery->enc_core_secret_size, | ||
419 | &core_secret, | ||
420 | &core_secret_size); | ||
421 | recovery->csc (recovery->csc_cls, | ||
422 | ANASTASIS_RS_SUCCESS, | ||
423 | core_secret, | ||
424 | core_secret_size); | ||
425 | GNUNET_free (core_secret); | ||
426 | ANASTASIS_recovery_abort (recovery); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | |||
431 | const struct ANASTASIS_ChallengeDetails * | ||
432 | ANASTASIS_challenge_get_details (struct ANASTASIS_Challenge *challenge) | ||
433 | { | ||
434 | return &challenge->ci; | ||
435 | } | ||
436 | |||
437 | |||
438 | int | ||
439 | ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c, | ||
440 | const struct ANASTASIS_PaymentSecretP *psp, | ||
441 | struct GNUNET_TIME_Relative timeout, | ||
442 | const struct GNUNET_HashCode *hashed_answer, | ||
443 | ANASTASIS_AnswerFeedback af, | ||
444 | void *af_cls) | ||
445 | { | ||
446 | if (c->ci.solved) | ||
447 | { | ||
448 | GNUNET_break (0); | ||
449 | return GNUNET_NO; /* already solved */ | ||
450 | } | ||
451 | if (NULL != c->kslo) | ||
452 | { | ||
453 | GNUNET_break (0); | ||
454 | return GNUNET_NO; /* already solving */ | ||
455 | } | ||
456 | c->af = af; | ||
457 | c->af_cls = af_cls; | ||
458 | c->kslo = ANASTASIS_keyshare_lookup (c->recovery->ctx, | ||
459 | c->url, | ||
460 | &c->ci.uuid, | ||
461 | &c->truth_key, | ||
462 | psp, | ||
463 | timeout, | ||
464 | hashed_answer, | ||
465 | &keyshare_lookup_cb, | ||
466 | c); | ||
467 | if (NULL == c->kslo) | ||
468 | { | ||
469 | GNUNET_break (0); | ||
470 | return GNUNET_SYSERR; | ||
471 | } | ||
472 | return GNUNET_OK; | ||
473 | } | ||
474 | |||
475 | |||
476 | int | ||
477 | ANASTASIS_challenge_answer ( | ||
478 | struct ANASTASIS_Challenge *c, | ||
479 | const struct ANASTASIS_PaymentSecretP *psp, | ||
480 | struct GNUNET_TIME_Relative timeout, | ||
481 | const char *answer_str, | ||
482 | ANASTASIS_AnswerFeedback af, | ||
483 | void *af_cls) | ||
484 | { | ||
485 | struct GNUNET_HashCode hashed_answer; | ||
486 | |||
487 | GNUNET_free (c->answer); | ||
488 | c->answer = GNUNET_strdup (answer_str); | ||
489 | ANASTASIS_CRYPTO_secure_answer_hash (answer_str, | ||
490 | &c->ci.uuid, | ||
491 | &c->salt, | ||
492 | &hashed_answer); | ||
493 | return ANASTASIS_challenge_start (c, | ||
494 | psp, | ||
495 | timeout, | ||
496 | &hashed_answer, | ||
497 | af, | ||
498 | af_cls); | ||
499 | } | ||
500 | |||
501 | |||
502 | int | ||
503 | ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c, | ||
504 | const struct ANASTASIS_PaymentSecretP *psp, | ||
505 | struct GNUNET_TIME_Relative timeout, | ||
506 | uint64_t answer, | ||
507 | ANASTASIS_AnswerFeedback af, | ||
508 | void *af_cls) | ||
509 | { | ||
510 | struct GNUNET_HashCode answer_s; | ||
511 | |||
512 | ANASTASIS_hash_answer (answer, | ||
513 | &answer_s); | ||
514 | return ANASTASIS_challenge_start (c, | ||
515 | psp, | ||
516 | timeout, | ||
517 | &answer_s, | ||
518 | af, | ||
519 | af_cls); | ||
520 | } | ||
521 | |||
522 | |||
523 | void | ||
524 | ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c) | ||
525 | { | ||
526 | if (NULL == c->kslo) | ||
527 | { | ||
528 | GNUNET_break (0); | ||
529 | return; | ||
530 | } | ||
531 | ANASTASIS_keyshare_lookup_cancel (c->kslo); | ||
532 | c->kslo = NULL; | ||
533 | c->af = NULL; | ||
534 | c->af_cls = NULL; | ||
535 | } | ||
536 | |||
537 | |||
538 | /** | ||
539 | * Function called with the results of a ANASTASIS_policy_lookup | ||
540 | * | ||
541 | * @param cls closure | ||
542 | * @param http_status HTTP status of the request | ||
543 | * @param ud details about the lookup operation | ||
544 | */ | ||
545 | static void | ||
546 | policy_lookup_cb (void *cls, | ||
547 | unsigned int http_status, | ||
548 | const struct ANASTASIS_DownloadDetails *dd) | ||
549 | { | ||
550 | struct ANASTASIS_Recovery *r = cls; | ||
551 | void *plaintext; | ||
552 | size_t size_plaintext; | ||
553 | json_error_t json_error; | ||
554 | json_t *dec_policies; | ||
555 | json_t *esc_methods; | ||
556 | |||
557 | r->plo = NULL; | ||
558 | switch (http_status) | ||
559 | { | ||
560 | case MHD_HTTP_OK: | ||
561 | break; | ||
562 | case MHD_HTTP_NOT_FOUND: | ||
563 | r->csc (r->csc_cls, | ||
564 | ANASTASIS_RS_POLICY_UNKNOWN, | ||
565 | NULL, | ||
566 | 0); | ||
567 | ANASTASIS_recovery_abort (r); | ||
568 | return; | ||
569 | case MHD_HTTP_NO_CONTENT: | ||
570 | /* Account known, policy expired */ | ||
571 | r->csc (r->csc_cls, | ||
572 | ANASTASIS_RS_POLICY_GONE, | ||
573 | NULL, | ||
574 | 0); | ||
575 | ANASTASIS_recovery_abort (r); | ||
576 | return; | ||
577 | case MHD_HTTP_INTERNAL_SERVER_ERROR: | ||
578 | /* Bad server... */ | ||
579 | r->csc (r->csc_cls, | ||
580 | ANASTASIS_RS_POLICY_SERVER_ERROR, | ||
581 | NULL, | ||
582 | 0); | ||
583 | ANASTASIS_recovery_abort (r); | ||
584 | return; | ||
585 | case MHD_HTTP_NOT_MODIFIED: | ||
586 | /* Should not be possible, we do not cache, fall-through! */ | ||
587 | default: | ||
588 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
589 | "Unexpected response code %u in %s:%u\n", | ||
590 | http_status, | ||
591 | __FILE__, | ||
592 | __LINE__); | ||
593 | r->csc (r->csc_cls, | ||
594 | ANASTASIS_RS_POLICY_DOWNLOAD_FAILED, | ||
595 | NULL, | ||
596 | 0); | ||
597 | ANASTASIS_recovery_abort (r); | ||
598 | return; | ||
599 | } | ||
600 | if (NULL == dd->policy) | ||
601 | { | ||
602 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
603 | "No recovery data available"); | ||
604 | r->csc (r->csc_cls, | ||
605 | ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY, | ||
606 | NULL, | ||
607 | 0); | ||
608 | ANASTASIS_recovery_abort (r); | ||
609 | return; | ||
610 | } | ||
611 | ANASTASIS_CRYPTO_recovery_document_decrypt (&r->id, | ||
612 | dd->policy, | ||
613 | dd->policy_size, | ||
614 | &plaintext, | ||
615 | &size_plaintext); | ||
616 | if (size_plaintext < sizeof (uint32_t)) | ||
617 | { | ||
618 | GNUNET_break_op (0); | ||
619 | r->csc (r->csc_cls, | ||
620 | ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION, | ||
621 | NULL, | ||
622 | 0); | ||
623 | ANASTASIS_recovery_abort (r); | ||
624 | GNUNET_free (plaintext); | ||
625 | return; | ||
626 | } | ||
627 | { | ||
628 | json_t *recovery_document; | ||
629 | uint32_t be_size; | ||
630 | uLongf pt_size; | ||
631 | char *pt; | ||
632 | |||
633 | memcpy (&be_size, | ||
634 | plaintext, | ||
635 | sizeof (uint32_t)); | ||
636 | pt_size = ntohl (be_size); | ||
637 | pt = GNUNET_malloc_large (pt_size); | ||
638 | if (NULL == pt) | ||
639 | { | ||
640 | GNUNET_break_op (0); | ||
641 | r->csc (r->csc_cls, | ||
642 | ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG, | ||
643 | NULL, | ||
644 | 0); | ||
645 | ANASTASIS_recovery_abort (r); | ||
646 | GNUNET_free (plaintext); | ||
647 | return; | ||
648 | } | ||
649 | if (Z_OK != | ||
650 | uncompress ((Bytef *) pt, | ||
651 | &pt_size, | ||
652 | (const Bytef *) plaintext + sizeof (uint32_t), | ||
653 | size_plaintext - sizeof (uint32_t))) | ||
654 | { | ||
655 | GNUNET_break_op (0); | ||
656 | r->csc (r->csc_cls, | ||
657 | ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION, | ||
658 | NULL, | ||
659 | 0); | ||
660 | GNUNET_free (plaintext); | ||
661 | GNUNET_free (pt); | ||
662 | ANASTASIS_recovery_abort (r); | ||
663 | return; | ||
664 | } | ||
665 | GNUNET_free (plaintext); | ||
666 | recovery_document = json_loadb ((char *) pt, | ||
667 | pt_size, | ||
668 | JSON_DECODE_ANY, | ||
669 | &json_error); | ||
670 | GNUNET_free (pt); | ||
671 | if (NULL == recovery_document) | ||
672 | { | ||
673 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
674 | "Failed to read JSON input: %s at %d:%s (offset: %d)\n", | ||
675 | json_error.text, | ||
676 | json_error.line, | ||
677 | json_error.source, | ||
678 | json_error.position); | ||
679 | GNUNET_break_op (0); | ||
680 | r->csc (r->csc_cls, | ||
681 | ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON, | ||
682 | NULL, | ||
683 | 0); | ||
684 | ANASTASIS_recovery_abort (r); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | { | ||
689 | const char *secret_name = NULL; | ||
690 | struct GNUNET_JSON_Specification spec[] = { | ||
691 | GNUNET_JSON_spec_json ("policies", | ||
692 | &dec_policies), | ||
693 | GNUNET_JSON_spec_json ("escrow_methods", | ||
694 | &esc_methods), | ||
695 | GNUNET_JSON_spec_mark_optional ( | ||
696 | GNUNET_JSON_spec_string ("secret_name", | ||
697 | &secret_name)), | ||
698 | GNUNET_JSON_spec_varsize ("encrypted_core_secret", | ||
699 | &r->enc_core_secret, | ||
700 | &r->enc_core_secret_size), | ||
701 | GNUNET_JSON_spec_end () | ||
702 | }; | ||
703 | |||
704 | if (GNUNET_OK != | ||
705 | GNUNET_JSON_parse (recovery_document, | ||
706 | spec, | ||
707 | NULL, NULL)) | ||
708 | { | ||
709 | GNUNET_break_op (0); | ||
710 | json_dumpf (recovery_document, | ||
711 | stderr, | ||
712 | 0); | ||
713 | json_decref (recovery_document); | ||
714 | r->csc (r->csc_cls, | ||
715 | ANASTASIS_RS_POLICY_MALFORMED_JSON, | ||
716 | NULL, | ||
717 | 0); | ||
718 | ANASTASIS_recovery_abort (r); | ||
719 | return; | ||
720 | } | ||
721 | if (NULL != secret_name) | ||
722 | { | ||
723 | GNUNET_break (NULL == r->secret_name); | ||
724 | r->secret_name = GNUNET_strdup (secret_name); | ||
725 | r->ri.secret_name = r->secret_name; | ||
726 | } | ||
727 | } | ||
728 | json_decref (recovery_document); | ||
729 | } | ||
730 | |||
731 | r->ri.version = dd->version; | ||
732 | r->ri.cs_len = json_array_size (esc_methods); | ||
733 | r->ri.dps_len = json_array_size (dec_policies); | ||
734 | r->ri.dps = GNUNET_new_array (r->ri.dps_len, | ||
735 | struct ANASTASIS_DecryptionPolicy *); | ||
736 | r->dps = GNUNET_new_array (r->ri.dps_len, | ||
737 | struct DecryptionPolicy); | ||
738 | r->solved_challenges = GNUNET_new_array (r->ri.cs_len, | ||
739 | struct ANASTASIS_Challenge *); | ||
740 | r->ri.cs = GNUNET_new_array (r->ri.cs_len, | ||
741 | struct ANASTASIS_Challenge *); | ||
742 | r->cs = GNUNET_new_array (r->ri.cs_len, | ||
743 | struct ANASTASIS_Challenge); | ||
744 | for (unsigned int i = 0; i < r->ri.cs_len; i++) | ||
745 | { | ||
746 | struct ANASTASIS_Challenge *cs = &r->cs[i]; | ||
747 | const char *instructions; | ||
748 | const char *url; | ||
749 | const char *escrow_type; | ||
750 | struct GNUNET_JSON_Specification spec[] = { | ||
751 | GNUNET_JSON_spec_fixed_auto ("uuid", | ||
752 | &cs->ci.uuid), | ||
753 | GNUNET_JSON_spec_string ("url", | ||
754 | &url), | ||
755 | GNUNET_JSON_spec_string ("instructions", | ||
756 | &instructions), | ||
757 | GNUNET_JSON_spec_fixed_auto ("truth_key", | ||
758 | &cs->truth_key), | ||
759 | GNUNET_JSON_spec_fixed_auto ("salt", | ||
760 | &cs->salt), | ||
761 | GNUNET_JSON_spec_fixed_auto ("provider_salt", | ||
762 | &cs->provider_salt), | ||
763 | GNUNET_JSON_spec_string ("escrow_type", | ||
764 | &escrow_type), | ||
765 | GNUNET_JSON_spec_end () | ||
766 | }; | ||
767 | |||
768 | r->ri.cs[i] = cs; | ||
769 | cs->recovery = r; | ||
770 | if (GNUNET_OK != | ||
771 | GNUNET_JSON_parse (json_array_get (esc_methods, | ||
772 | i), | ||
773 | spec, | ||
774 | NULL, NULL)) | ||
775 | { | ||
776 | GNUNET_break_op (0); | ||
777 | json_decref (esc_methods); | ||
778 | json_decref (dec_policies); | ||
779 | r->csc (r->csc_cls, | ||
780 | ANASTASIS_RS_POLICY_MALFORMED_JSON, | ||
781 | NULL, | ||
782 | 0); | ||
783 | ANASTASIS_recovery_abort (r); | ||
784 | return; | ||
785 | } | ||
786 | cs->url = GNUNET_strdup (url); | ||
787 | cs->type = GNUNET_strdup (escrow_type); | ||
788 | cs->ci.type = cs->type; | ||
789 | cs->ci.provider_url = cs->url; | ||
790 | cs->instructions = GNUNET_strdup (instructions); | ||
791 | cs->ci.instructions = cs->instructions; | ||
792 | } | ||
793 | json_decref (esc_methods); | ||
794 | |||
795 | for (unsigned int j = 0; j < r->ri.dps_len; j++) | ||
796 | { | ||
797 | struct DecryptionPolicy *dp = &r->dps[j]; | ||
798 | json_t *uuids = NULL; | ||
799 | json_t *uuid; | ||
800 | size_t n_index; | ||
801 | struct GNUNET_JSON_Specification spec[] = { | ||
802 | GNUNET_JSON_spec_fixed_auto ("master_key", | ||
803 | &dp->emk), | ||
804 | GNUNET_JSON_spec_fixed_auto ("salt", | ||
805 | &dp->salt), | ||
806 | GNUNET_JSON_spec_json ("uuids", | ||
807 | &uuids), | ||
808 | GNUNET_JSON_spec_end () | ||
809 | }; | ||
810 | |||
811 | r->ri.dps[j] = &r->dps[j].pub_details; | ||
812 | if ( (GNUNET_OK != | ||
813 | GNUNET_JSON_parse (json_array_get (dec_policies, | ||
814 | j), | ||
815 | spec, | ||
816 | NULL, NULL)) || | ||
817 | (! json_is_array (uuids)) ) | ||
818 | { | ||
819 | GNUNET_break_op (0); | ||
820 | json_decref (uuids); | ||
821 | json_decref (dec_policies); | ||
822 | r->csc (r->csc_cls, | ||
823 | ANASTASIS_RS_POLICY_MALFORMED_JSON, | ||
824 | NULL, | ||
825 | 0); | ||
826 | ANASTASIS_recovery_abort (r); | ||
827 | return; | ||
828 | } | ||
829 | |||
830 | dp->pub_details.challenges_length = json_array_size (uuids); | ||
831 | dp->pub_details.challenges | ||
832 | = GNUNET_new_array (dp->pub_details.challenges_length, | ||
833 | struct ANASTASIS_Challenge *); | ||
834 | json_array_foreach (uuids, n_index, uuid) | ||
835 | { | ||
836 | const char *uuid_str = json_string_value (uuid); | ||
837 | struct ANASTASIS_CRYPTO_TruthUUIDP uuid; | ||
838 | bool found = false; | ||
839 | |||
840 | if ( (NULL == uuid_str) || | ||
841 | (GNUNET_OK != | ||
842 | GNUNET_STRINGS_string_to_data ( | ||
843 | uuid_str, | ||
844 | strlen (uuid_str), | ||
845 | &uuid, | ||
846 | sizeof (uuid))) ) | ||
847 | { | ||
848 | GNUNET_break_op (0); | ||
849 | json_decref (dec_policies); | ||
850 | json_decref (uuids); | ||
851 | r->csc (r->csc_cls, | ||
852 | ANASTASIS_RS_POLICY_MALFORMED_JSON, | ||
853 | NULL, | ||
854 | 0); | ||
855 | ANASTASIS_recovery_abort (r); | ||
856 | return; | ||
857 | } | ||
858 | for (unsigned int i = 0; i<r->ri.cs_len; i++) | ||
859 | { | ||
860 | if (0 != | ||
861 | GNUNET_memcmp (&uuid, | ||
862 | &r->cs[i].ci.uuid)) | ||
863 | continue; | ||
864 | found = true; | ||
865 | dp->pub_details.challenges[n_index] = &r->cs[i]; | ||
866 | break; | ||
867 | } | ||
868 | if (! found) | ||
869 | { | ||
870 | GNUNET_break_op (0); | ||
871 | json_decref (dec_policies); | ||
872 | json_decref (uuids); | ||
873 | r->csc (r->csc_cls, | ||
874 | ANASTASIS_RS_POLICY_MALFORMED_JSON, | ||
875 | NULL, | ||
876 | 0); | ||
877 | ANASTASIS_recovery_abort (r); | ||
878 | return; | ||
879 | } | ||
880 | } | ||
881 | json_decref (uuids); | ||
882 | } | ||
883 | json_decref (dec_policies); | ||
884 | r->pc (r->pc_cls, | ||
885 | &r->ri); | ||
886 | } | ||
887 | |||
888 | |||
889 | struct ANASTASIS_Recovery * | ||
890 | ANASTASIS_recovery_begin ( | ||
891 | struct GNUNET_CURL_Context *ctx, | ||
892 | const json_t *id_data, | ||
893 | unsigned int version, | ||
894 | const char *anastasis_provider_url, | ||
895 | const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt, | ||
896 | ANASTASIS_PolicyCallback pc, | ||
897 | void *pc_cls, | ||
898 | ANASTASIS_CoreSecretCallback csc, | ||
899 | void *csc_cls) | ||
900 | { | ||
901 | struct ANASTASIS_Recovery *r; | ||
902 | struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; | ||
903 | |||
904 | r = GNUNET_new (struct ANASTASIS_Recovery); | ||
905 | r->csc = csc; | ||
906 | r->csc_cls = csc_cls; | ||
907 | r->pc = pc; | ||
908 | r->pc_cls = pc_cls; | ||
909 | r->ctx = ctx; | ||
910 | r->id_data = json_incref ((json_t *) id_data); | ||
911 | r->provider_url = GNUNET_strdup (anastasis_provider_url); | ||
912 | ANASTASIS_CRYPTO_user_identifier_derive (id_data, | ||
913 | provider_salt, | ||
914 | &r->id); | ||
915 | ANASTASIS_CRYPTO_account_public_key_derive (&r->id, | ||
916 | &pub_key); | ||
917 | r->ri.version = version; | ||
918 | if (0 != version) | ||
919 | { | ||
920 | r->plo = ANASTASIS_policy_lookup_version (r->ctx, | ||
921 | anastasis_provider_url, | ||
922 | &pub_key, | ||
923 | &policy_lookup_cb, | ||
924 | r, | ||
925 | version); | ||
926 | } | ||
927 | else | ||
928 | { | ||
929 | r->plo = ANASTASIS_policy_lookup (r->ctx, | ||
930 | anastasis_provider_url, | ||
931 | &pub_key, | ||
932 | &policy_lookup_cb, | ||
933 | r); | ||
934 | } | ||
935 | if (NULL == r->plo) | ||
936 | { | ||
937 | GNUNET_break (0); | ||
938 | ANASTASIS_recovery_abort (r); | ||
939 | return NULL; | ||
940 | } | ||
941 | return r; | ||
942 | } | ||
943 | |||
944 | |||
945 | json_t * | ||
946 | ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) | ||
947 | { | ||
948 | json_t *dps_arr; | ||
949 | json_t *cs_arr; | ||
950 | |||
951 | dps_arr = json_array (); | ||
952 | GNUNET_assert (NULL != dps_arr); | ||
953 | for (unsigned int i = 0; i<r->ri.dps_len; i++) | ||
954 | { | ||
955 | const struct DecryptionPolicy *dp = &r->dps[i]; | ||
956 | json_t *c_arr; | ||
957 | json_t *dps; | ||
958 | |||
959 | c_arr = json_array (); | ||
960 | GNUNET_assert (NULL != c_arr); | ||
961 | for (unsigned int j = 0; j < dp->pub_details.challenges_length; j++) | ||
962 | { | ||
963 | const struct ANASTASIS_Challenge *c = dp->pub_details.challenges[j]; | ||
964 | json_t *cs; | ||
965 | |||
966 | cs = json_pack ("{s:o}", | ||
967 | "uuid", | ||
968 | GNUNET_JSON_from_data_auto (&c->ci.uuid)); | ||
969 | GNUNET_assert (NULL != cs); | ||
970 | GNUNET_assert (0 == | ||
971 | json_array_append_new (c_arr, | ||
972 | cs)); | ||
973 | } | ||
974 | dps = json_pack ("{s:o, s:o, s:o}", | ||
975 | "emk", | ||
976 | GNUNET_JSON_from_data_auto (&dp->emk), | ||
977 | "salt", | ||
978 | GNUNET_JSON_from_data_auto (&dp->salt), | ||
979 | "challenges", | ||
980 | c_arr); | ||
981 | GNUNET_assert (NULL != dps); | ||
982 | GNUNET_assert (0 == | ||
983 | json_array_append_new (dps_arr, | ||
984 | dps)); | ||
985 | } | ||
986 | cs_arr = json_array (); | ||
987 | GNUNET_assert (NULL != cs_arr); | ||
988 | for (unsigned int i = 0; i<r->ri.cs_len; i++) | ||
989 | { | ||
990 | const struct ANASTASIS_Challenge *c = &r->cs[i]; | ||
991 | json_t *cs; | ||
992 | |||
993 | cs = json_pack ("{s:o,s:o,s:o,s:o,s:o?," | ||
994 | " s:s,s:s,s:s,s:b}", | ||
995 | "uuid", | ||
996 | GNUNET_JSON_from_data_auto (&c->ci.uuid), | ||
997 | "truth_key", | ||
998 | GNUNET_JSON_from_data_auto (&c->truth_key), | ||
999 | "salt", | ||
1000 | GNUNET_JSON_from_data_auto (&c->salt), | ||
1001 | "provider_salt", | ||
1002 | GNUNET_JSON_from_data_auto (&c->provider_salt), | ||
1003 | "key_share", | ||
1004 | c->ci.solved | ||
1005 | ? GNUNET_JSON_from_data_auto (&c->key_share) | ||
1006 | : NULL, | ||
1007 | "url", | ||
1008 | c->url, | ||
1009 | "type", | ||
1010 | c->type, | ||
1011 | "instructions", | ||
1012 | c->instructions, | ||
1013 | "solved", | ||
1014 | c->ci.solved); | ||
1015 | GNUNET_assert (NULL != cs); | ||
1016 | GNUNET_assert (0 == | ||
1017 | json_array_append_new (cs_arr, | ||
1018 | cs)); | ||
1019 | } | ||
1020 | |||
1021 | return json_pack ("{s:o, s:o, s:o, s:I, s:O, " | ||
1022 | " s:s, s:s?, s:o}", | ||
1023 | "id", | ||
1024 | GNUNET_JSON_from_data_auto (&r->id), | ||
1025 | "dps", | ||
1026 | dps_arr, | ||
1027 | "cs", | ||
1028 | cs_arr, | ||
1029 | "version", | ||
1030 | (json_int_t) r->ri.version, | ||
1031 | "id_data", | ||
1032 | r->id_data, | ||
1033 | "provider_url", | ||
1034 | r->provider_url, | ||
1035 | "secret_name", | ||
1036 | r->secret_name, | ||
1037 | "core_secret", | ||
1038 | GNUNET_JSON_from_data (r->enc_core_secret, | ||
1039 | r->enc_core_secret_size)); | ||
1040 | } | ||
1041 | |||
1042 | |||
1043 | /** | ||
1044 | * Parse the @a cs_array and update @a r accordingly | ||
1045 | * | ||
1046 | * @param[in,out] r recovery information to update | ||
1047 | * @param cs_arr serialized data to parse | ||
1048 | * @return #GNUNET_OK on success | ||
1049 | */ | ||
1050 | static int | ||
1051 | parse_cs_array (struct ANASTASIS_Recovery *r, | ||
1052 | json_t *cs_arr) | ||
1053 | { | ||
1054 | json_t *cs; | ||
1055 | unsigned int n_index; | ||
1056 | |||
1057 | if (! json_is_array (cs_arr)) | ||
1058 | { | ||
1059 | GNUNET_break_op (0); | ||
1060 | return GNUNET_SYSERR; | ||
1061 | } | ||
1062 | r->ri.cs_len = json_array_size (cs_arr); | ||
1063 | r->solved_challenges = GNUNET_new_array (r->ri.cs_len, | ||
1064 | struct ANASTASIS_Challenge *); | ||
1065 | r->ri.cs = GNUNET_new_array (r->ri.cs_len, | ||
1066 | struct ANASTASIS_Challenge *); | ||
1067 | r->cs = GNUNET_new_array (r->ri.cs_len, | ||
1068 | struct ANASTASIS_Challenge); | ||
1069 | json_array_foreach (cs_arr, n_index, cs) | ||
1070 | { | ||
1071 | struct ANASTASIS_Challenge *c = &r->cs[n_index]; | ||
1072 | const char *instructions; | ||
1073 | const char *url; | ||
1074 | const char *escrow_type; | ||
1075 | struct GNUNET_JSON_Specification spec[] = { | ||
1076 | GNUNET_JSON_spec_fixed_auto ("uuid", | ||
1077 | &c->ci.uuid), | ||
1078 | GNUNET_JSON_spec_string ("url", | ||
1079 | &url), | ||
1080 | GNUNET_JSON_spec_string ("instructions", | ||
1081 | &instructions), | ||
1082 | GNUNET_JSON_spec_fixed_auto ("truth_key", | ||
1083 | &c->truth_key), | ||
1084 | GNUNET_JSON_spec_fixed_auto ("salt", | ||
1085 | &c->salt), | ||
1086 | GNUNET_JSON_spec_fixed_auto ("provider_salt", | ||
1087 | &c->provider_salt), | ||
1088 | GNUNET_JSON_spec_string ("type", | ||
1089 | &escrow_type), | ||
1090 | GNUNET_JSON_spec_mark_optional ( | ||
1091 | GNUNET_JSON_spec_fixed_auto ("key_share", | ||
1092 | &c->key_share)), | ||
1093 | GNUNET_JSON_spec_end () | ||
1094 | }; | ||
1095 | |||
1096 | r->ri.cs[n_index] = c; | ||
1097 | c->recovery = r; | ||
1098 | if (GNUNET_OK != | ||
1099 | GNUNET_JSON_parse (cs, | ||
1100 | spec, | ||
1101 | NULL, NULL)) | ||
1102 | { | ||
1103 | GNUNET_break_op (0); | ||
1104 | return GNUNET_SYSERR; | ||
1105 | } | ||
1106 | c->url = GNUNET_strdup (url); | ||
1107 | c->type = GNUNET_strdup (escrow_type); | ||
1108 | c->ci.type = c->type; | ||
1109 | c->instructions = GNUNET_strdup (instructions); | ||
1110 | c->ci.instructions = c->instructions; | ||
1111 | c->ci.provider_url = c->url; | ||
1112 | { | ||
1113 | json_t *ks; | ||
1114 | |||
1115 | ks = json_object_get (cs, | ||
1116 | "key_share"); | ||
1117 | if ( (NULL != ks) && | ||
1118 | (! json_is_null (ks)) ) | ||
1119 | { | ||
1120 | c->ci.solved = true; | ||
1121 | r->solved_challenges[r->solved_challenge_pos++] = c; | ||
1122 | } | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | return GNUNET_OK; | ||
1127 | } | ||
1128 | |||
1129 | |||
1130 | /** | ||
1131 | * Parse the @a dps_array and update @a r accordingly | ||
1132 | * | ||
1133 | * @param[in,out] r recovery information to update | ||
1134 | * @param dps_arr serialized data to parse | ||
1135 | * @return #GNUNET_OK on success | ||
1136 | */ | ||
1137 | static int | ||
1138 | parse_dps_array (struct ANASTASIS_Recovery *r, | ||
1139 | json_t *dps_arr) | ||
1140 | { | ||
1141 | json_t *dps; | ||
1142 | unsigned int n_index; | ||
1143 | |||
1144 | if (! json_is_array (dps_arr)) | ||
1145 | { | ||
1146 | GNUNET_break_op (0); | ||
1147 | return GNUNET_SYSERR; | ||
1148 | } | ||
1149 | r->ri.dps_len = json_array_size (dps_arr); | ||
1150 | r->dps = GNUNET_new_array (r->ri.dps_len, | ||
1151 | struct DecryptionPolicy); | ||
1152 | r->ri.dps = GNUNET_new_array (r->ri.dps_len, | ||
1153 | struct ANASTASIS_DecryptionPolicy *); | ||
1154 | |||
1155 | json_array_foreach (dps_arr, n_index, dps) | ||
1156 | { | ||
1157 | struct DecryptionPolicy *dp = &r->dps[n_index]; | ||
1158 | json_t *challenges; | ||
1159 | struct GNUNET_JSON_Specification spec[] = { | ||
1160 | GNUNET_JSON_spec_fixed_auto ("emk", | ||
1161 | &dp->emk), | ||
1162 | GNUNET_JSON_spec_fixed_auto ("salt", | ||
1163 | &dp->salt), | ||
1164 | GNUNET_JSON_spec_json ("challenges", | ||
1165 | &challenges), | ||
1166 | GNUNET_JSON_spec_end () | ||
1167 | }; | ||
1168 | const char *err_json_name; | ||
1169 | unsigned int err_line; | ||
1170 | |||
1171 | r->ri.dps[n_index] = &dp->pub_details; | ||
1172 | if (GNUNET_OK != | ||
1173 | GNUNET_JSON_parse (dps, | ||
1174 | spec, | ||
1175 | &err_json_name, | ||
1176 | &err_line)) | ||
1177 | { | ||
1178 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1179 | "Failed to parse decryption policy JSON entry `%s'\n", | ||
1180 | err_json_name); | ||
1181 | json_dumpf (dps, | ||
1182 | stderr, | ||
1183 | JSON_INDENT (2)); | ||
1184 | return GNUNET_SYSERR; | ||
1185 | } | ||
1186 | if (! json_is_array (challenges)) | ||
1187 | { | ||
1188 | GNUNET_break_op (0); | ||
1189 | GNUNET_JSON_parse_free (spec); | ||
1190 | return GNUNET_SYSERR; | ||
1191 | } | ||
1192 | dp->pub_details.challenges_length = json_array_size (challenges); | ||
1193 | dp->pub_details.challenges = GNUNET_new_array ( | ||
1194 | dp->pub_details.challenges_length, | ||
1195 | struct ANASTASIS_Challenge *); | ||
1196 | |||
1197 | { | ||
1198 | json_t *challenge; | ||
1199 | unsigned int c_index; | ||
1200 | json_array_foreach (challenges, c_index, challenge) | ||
1201 | { | ||
1202 | struct ANASTASIS_CRYPTO_TruthUUIDP uuid; | ||
1203 | struct GNUNET_JSON_Specification ispec[] = { | ||
1204 | GNUNET_JSON_spec_fixed_auto ("uuid", | ||
1205 | &uuid), | ||
1206 | GNUNET_JSON_spec_end () | ||
1207 | }; | ||
1208 | bool found = false; | ||
1209 | |||
1210 | if (GNUNET_OK != | ||
1211 | GNUNET_JSON_parse (challenge, | ||
1212 | ispec, | ||
1213 | NULL, NULL)) | ||
1214 | { | ||
1215 | GNUNET_break_op (0); | ||
1216 | GNUNET_JSON_parse_free (spec); | ||
1217 | return GNUNET_SYSERR; | ||
1218 | } | ||
1219 | for (unsigned int i = 0; i<r->ri.cs_len; i++) | ||
1220 | { | ||
1221 | if (0 != | ||
1222 | GNUNET_memcmp (&uuid, | ||
1223 | &r->cs[i].ci.uuid)) | ||
1224 | continue; | ||
1225 | dp->pub_details.challenges[c_index] = &r->cs[i]; | ||
1226 | found = true; | ||
1227 | } | ||
1228 | if (! found) | ||
1229 | { | ||
1230 | GNUNET_break_op (0); | ||
1231 | GNUNET_JSON_parse_free (spec); | ||
1232 | return GNUNET_SYSERR; | ||
1233 | } | ||
1234 | } | ||
1235 | } | ||
1236 | GNUNET_JSON_parse_free (spec); | ||
1237 | } | ||
1238 | return GNUNET_OK; | ||
1239 | } | ||
1240 | |||
1241 | |||
1242 | /** | ||
1243 | * Asynchronously call "pc" on the recovery information. | ||
1244 | * | ||
1245 | * @param cls a `struct ANASTASIS_Recovery *` | ||
1246 | */ | ||
1247 | static void | ||
1248 | run_async_pc (void *cls) | ||
1249 | { | ||
1250 | struct ANASTASIS_Recovery *r = cls; | ||
1251 | |||
1252 | r->do_async = NULL; | ||
1253 | r->pc (r->pc_cls, | ||
1254 | &r->ri); | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | struct ANASTASIS_Recovery * | ||
1259 | ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx, | ||
1260 | const json_t *input, | ||
1261 | ANASTASIS_PolicyCallback pc, | ||
1262 | void *pc_cls, | ||
1263 | ANASTASIS_CoreSecretCallback csc, | ||
1264 | void *csc_cls) | ||
1265 | { | ||
1266 | struct ANASTASIS_Recovery *r; | ||
1267 | |||
1268 | r = GNUNET_new (struct ANASTASIS_Recovery); | ||
1269 | r->csc = csc; | ||
1270 | r->csc_cls = csc_cls; | ||
1271 | r->pc = pc; | ||
1272 | r->pc_cls = pc_cls; | ||
1273 | r->ctx = ctx; | ||
1274 | { | ||
1275 | const char *err_json_name; | ||
1276 | unsigned int err_line; | ||
1277 | uint32_t version; | ||
1278 | json_t *dps_arr; | ||
1279 | json_t *cs_arr; | ||
1280 | json_t *id_data; | ||
1281 | const char *provider_url; | ||
1282 | const char *secret_name; | ||
1283 | void *ecs; | ||
1284 | size_t ecs_size; | ||
1285 | struct GNUNET_JSON_Specification spec[] = { | ||
1286 | GNUNET_JSON_spec_fixed_auto ("id", | ||
1287 | &r->id), | ||
1288 | GNUNET_JSON_spec_string ("provider_url", | ||
1289 | &provider_url), | ||
1290 | GNUNET_JSON_spec_mark_optional ( | ||
1291 | GNUNET_JSON_spec_string ("secret_name", | ||
1292 | &secret_name)), | ||
1293 | GNUNET_JSON_spec_uint32 ("version", | ||
1294 | &version), | ||
1295 | GNUNET_JSON_spec_json ("dps", | ||
1296 | &dps_arr), | ||
1297 | GNUNET_JSON_spec_json ("cs", | ||
1298 | &cs_arr), | ||
1299 | GNUNET_JSON_spec_json ("id_data", | ||
1300 | &id_data), | ||
1301 | GNUNET_JSON_spec_varsize ("core_secret", | ||
1302 | &ecs, | ||
1303 | &ecs_size), | ||
1304 | GNUNET_JSON_spec_end () | ||
1305 | }; | ||
1306 | |||
1307 | if (GNUNET_OK != | ||
1308 | GNUNET_JSON_parse (input, | ||
1309 | spec, | ||
1310 | &err_json_name, | ||
1311 | &err_line)) | ||
1312 | { | ||
1313 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1314 | "Failed to parse recovery document JSON entry `%s'\n", | ||
1315 | err_json_name); | ||
1316 | json_dumpf (input, | ||
1317 | stderr, | ||
1318 | JSON_INDENT (2)); | ||
1319 | return NULL; | ||
1320 | } | ||
1321 | r->ri.version = version; | ||
1322 | if ( (GNUNET_OK != | ||
1323 | parse_cs_array (r, | ||
1324 | cs_arr)) || | ||
1325 | (GNUNET_OK != | ||
1326 | parse_dps_array (r, | ||
1327 | dps_arr)) ) | ||
1328 | { | ||
1329 | GNUNET_break_op (0); | ||
1330 | ANASTASIS_recovery_abort (r); | ||
1331 | GNUNET_JSON_parse_free (spec); | ||
1332 | return NULL; | ||
1333 | } | ||
1334 | r->id_data = json_incref (id_data); | ||
1335 | r->provider_url = GNUNET_strdup (provider_url); | ||
1336 | if (NULL != secret_name) | ||
1337 | r->secret_name = GNUNET_strdup (secret_name); | ||
1338 | r->ri.secret_name = r->secret_name; | ||
1339 | if (0 != ecs_size) | ||
1340 | { | ||
1341 | r->enc_core_secret = GNUNET_memdup (ecs, | ||
1342 | ecs_size); | ||
1343 | r->enc_core_secret_size = ecs_size; | ||
1344 | } | ||
1345 | GNUNET_JSON_parse_free (spec); | ||
1346 | } | ||
1347 | if (0 == r->ri.dps_len) | ||
1348 | { | ||
1349 | struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; | ||
1350 | |||
1351 | ANASTASIS_CRYPTO_account_public_key_derive (&r->id, | ||
1352 | &pub_key); | ||
1353 | if (0 != r->ri.version) | ||
1354 | { | ||
1355 | r->plo = ANASTASIS_policy_lookup_version (r->ctx, | ||
1356 | r->provider_url, | ||
1357 | &pub_key, | ||
1358 | &policy_lookup_cb, | ||
1359 | r, | ||
1360 | r->ri.version); | ||
1361 | } | ||
1362 | else | ||
1363 | { | ||
1364 | r->plo = ANASTASIS_policy_lookup (r->ctx, | ||
1365 | r->provider_url, | ||
1366 | &pub_key, | ||
1367 | &policy_lookup_cb, | ||
1368 | r); | ||
1369 | } | ||
1370 | if (NULL == r->plo) | ||
1371 | { | ||
1372 | GNUNET_break (0); | ||
1373 | ANASTASIS_recovery_abort (r); | ||
1374 | return NULL; | ||
1375 | } | ||
1376 | } | ||
1377 | else | ||
1378 | { | ||
1379 | r->do_async = GNUNET_SCHEDULER_add_now (&run_async_pc, | ||
1380 | r); | ||
1381 | } | ||
1382 | return r; | ||
1383 | } | ||
1384 | |||
1385 | |||
1386 | void | ||
1387 | ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r) | ||
1388 | { | ||
1389 | if (NULL != r->do_async) | ||
1390 | { | ||
1391 | GNUNET_SCHEDULER_cancel (r->do_async); | ||
1392 | r->do_async = NULL; | ||
1393 | } | ||
1394 | if (NULL != r->plo) | ||
1395 | { | ||
1396 | ANASTASIS_policy_lookup_cancel (r->plo); | ||
1397 | r->plo = NULL; | ||
1398 | } | ||
1399 | GNUNET_free (r->solved_challenges); | ||
1400 | for (unsigned int j = 0; j < r->ri.dps_len; j++) | ||
1401 | GNUNET_free (r->dps[j].pub_details.challenges); | ||
1402 | GNUNET_free (r->ri.dps); | ||
1403 | for (unsigned int i = 0; i < r->ri.cs_len; i++) | ||
1404 | { | ||
1405 | struct ANASTASIS_Challenge *cs = r->ri.cs[i]; | ||
1406 | |||
1407 | if (NULL != cs->kslo) | ||
1408 | { | ||
1409 | ANASTASIS_keyshare_lookup_cancel (cs->kslo); | ||
1410 | cs->kslo = NULL; | ||
1411 | } | ||
1412 | GNUNET_free (cs->url); | ||
1413 | GNUNET_free (cs->type); | ||
1414 | GNUNET_free (cs->instructions); | ||
1415 | GNUNET_free (cs->answer); | ||
1416 | } | ||
1417 | GNUNET_free (r->ri.cs); | ||
1418 | GNUNET_free (r->cs); | ||
1419 | GNUNET_free (r->dps); | ||
1420 | json_decref (r->id_data); | ||
1421 | GNUNET_free (r->provider_url); | ||
1422 | GNUNET_free (r->secret_name); | ||
1423 | GNUNET_free (r->enc_core_secret); | ||
1424 | GNUNET_free (r); | ||
1425 | } | ||