anastasis_recovery.c (47081B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU 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 #include <microhttpd.h> 29 30 31 /** 32 * Challenge struct contains the uuid and public key's needed for the 33 * recovery process and a reference to ANASTASIS_Recovery. 34 */ 35 struct ANASTASIS_Challenge 36 { 37 38 /** 39 * Information exported to clients about this challenge. 40 */ 41 struct ANASTASIS_ChallengeDetails ci; 42 43 /** 44 * Key used to encrypt the truth passed to the server 45 */ 46 struct ANASTASIS_CRYPTO_TruthKeyP truth_key; 47 48 /** 49 * Salt; used to derive hash from security question answers. 50 */ 51 struct ANASTASIS_CRYPTO_QuestionSaltP question_salt; 52 53 /** 54 * Provider salt; used to derive our key material from our identity 55 * key. 56 */ 57 struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; 58 59 /** 60 * Decrypted key share for this challenge. Set once the 61 * challenge was @e ri.solved. 62 */ 63 struct ANASTASIS_CRYPTO_KeyShareP key_share; 64 65 /** 66 * Callback which gives back the instructions and a status code of 67 * the request to the user when answering a challenge. 68 */ 69 ANASTASIS_AnswerFeedback af; 70 71 /** 72 * Closure for @e af. 73 */ 74 void *af_cls; 75 76 /** 77 * Callback which gives back the instructions and a status code of 78 * the request to the user when initiating a challenge. 79 */ 80 ANASTASIS_ChallengeStartFeedback csf; 81 82 /** 83 * Closure for @e csf. 84 */ 85 void *csf_cls; 86 87 /** 88 * Defines the base URL of the Anastasis provider used for the challenge. 89 */ 90 char *url; 91 92 /** 93 * What is the type of this challenge (E-Mail, Security Question, SMS...) 94 */ 95 char *type; 96 97 /** 98 * Instructions for solving the challenge (generic, set client-side 99 * when challenge was established). 100 */ 101 char *instructions; 102 103 /** 104 * Answer to the security question, if @a type is "question". Otherwise NULL. 105 */ 106 char *answer; 107 108 /** 109 * Reference to the recovery process which is ongoing 110 */ 111 struct ANASTASIS_Recovery *recovery; 112 113 /** 114 * Handle for the /truth/$TID/challenge request. 115 */ 116 struct ANASTASIS_TruthChallengeOperation *tco; 117 118 /** 119 * Handle for the /truth/$TID/solve request. 120 */ 121 struct ANASTASIS_TruthSolveOperation *tso; 122 123 }; 124 125 126 /** 127 * Defines a decryption policy with multiple escrow methods 128 */ 129 struct DecryptionPolicy 130 { 131 132 /** 133 * Publicly visible details about a decryption policy. 134 */ 135 struct ANASTASIS_DecryptionPolicy pub_details; 136 137 /** 138 * Encrypted master key (encrypted with the policy key). 139 */ 140 void *emk; 141 142 /** 143 * Size of the encrypted master key. 144 */ 145 size_t emk_size; 146 147 /** 148 * Salt used to decrypt master key. 149 */ 150 struct ANASTASIS_CRYPTO_MasterSaltP master_salt; 151 152 }; 153 154 155 /** 156 * stores provider URLs, identity key material, decrypted recovery document (internally!) 157 */ 158 struct ANASTASIS_Recovery 159 { 160 161 /** 162 * Identity key material used for the derivation of keys 163 */ 164 struct ANASTASIS_CRYPTO_UserIdentifierP id; 165 166 /** 167 * Recovery information which is given to the user 168 */ 169 struct ANASTASIS_RecoveryInformation ri; 170 171 /** 172 * Internal of @e ri.dps_len policies that would allow recovery of the core secret. 173 */ 174 struct DecryptionPolicy *dps; 175 176 /** 177 * Array of @e ri.cs_len challenges to be solved (for any of the policies). 178 */ 179 struct ANASTASIS_Challenge *cs; 180 181 /** 182 * Identity data to user id from. 183 */ 184 json_t *id_data; 185 186 /** 187 * Callback to send back a recovery document with the policies and the version 188 */ 189 ANASTASIS_PolicyCallback pc; 190 191 /** 192 * closure for the Policy callback 193 */ 194 void *pc_cls; 195 196 /** 197 * Callback to send back the core secret which was saved by 198 * anastasis, after all challenges are completed 199 */ 200 ANASTASIS_CoreSecretCallback csc; 201 202 /** 203 * Closure for the core secret callback 204 */ 205 void *csc_cls; 206 207 /** 208 * Curl context 209 */ 210 struct GNUNET_CURL_Context *ctx; 211 212 /** 213 * Reference to the policy lookup operation which is executed 214 */ 215 struct ANASTASIS_PolicyLookupOperation *plo; 216 217 /** 218 * Array of challenges that have been solved. 219 * Valid entries up to @e solved_challenge_pos. 220 * Length matches the total number of challenges in @e ri. 221 */ 222 struct ANASTASIS_Challenge **solved_challenges; 223 224 /** 225 * Our provider URL. 226 */ 227 char *provider_url; 228 229 /** 230 * Name of the secret, can be NULL. 231 */ 232 char *secret_name; 233 234 /** 235 * Task to run @e pc asynchronously. 236 */ 237 struct GNUNET_SCHEDULER_Task *do_async; 238 239 /** 240 * Retrieved encrypted core secret from policy 241 */ 242 void *enc_core_secret; 243 244 /** 245 * Size of the @e enc_core_secret 246 */ 247 size_t enc_core_secret_size; 248 249 /** 250 * Current offset in the @e solved_challenges array. 251 */ 252 unsigned int solved_challenge_pos; 253 254 }; 255 256 257 /** 258 * Function called with the results of a #ANASTASIS_challenge_start(). 259 * 260 * @param cls closure 261 * @param dd details about the lookup operation 262 */ 263 static void 264 truth_challenge_cb (void *cls, 265 const struct ANASTASIS_TruthChallengeDetails *tcd) 266 { 267 struct ANASTASIS_Challenge *c = cls; 268 struct ANASTASIS_ChallengeStartResponse csr = { 269 .challenge = c, 270 .ec = tcd->ec, 271 .http_status = tcd->http_status 272 }; 273 274 c->tco = NULL; 275 switch (tcd->http_status) 276 { 277 case MHD_HTTP_OK: 278 switch (tcd->details.success.cs) 279 { 280 case ANASTASIS_CS_FILE_WRITTEN: 281 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED; 282 csr.details.tan_filename 283 = tcd->details.success.details.challenge_filename; 284 break; 285 case ANASTASIS_CS_TAN_SENT: 286 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED; 287 csr.details.tan_address_hint 288 = tcd->details.success.details.tan_address_hint; 289 break; 290 case ANASTASIS_CS_TAN_ALREADY_SENT: 291 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT; 292 break; 293 case ANASTASIS_CS_WIRE_FUNDS: 294 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED; 295 csr.details.bank_transfer_required 296 = tcd->details.success.details.wire_funds; 297 break; 298 } 299 break; 300 case MHD_HTTP_PAYMENT_REQUIRED: 301 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED; 302 csr.details.payment_required.taler_pay_uri 303 = tcd->details.payment_required.payment_request; 304 csr.details.payment_required.payment_secret 305 = tcd->details.payment_required.ps; 306 break; 307 case MHD_HTTP_NOT_FOUND: 308 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN; 309 break; 310 default: 311 csr.cs = ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE; 312 break; 313 } 314 c->csf (c->csf_cls, 315 &csr); 316 } 317 318 319 /** 320 * Function called with the results of a #ANASTASIS_truth_solve(). 321 * 322 * @param cls closure 323 * @param tsr details about the solution response 324 */ 325 static void 326 truth_solve_cb (void *cls, 327 const struct ANASTASIS_TruthSolveReply *tsr) 328 { 329 struct ANASTASIS_Challenge *c = cls; 330 struct ANASTASIS_Recovery *recovery = c->recovery; 331 struct ANASTASIS_CRYPTO_UserIdentifierP id; 332 struct DecryptionPolicy *rdps; 333 struct ANASTASIS_ChallengeAnswerResponse csr = { 334 .challenge = c, 335 .ec = tsr->ec, 336 .http_status = tsr->http_status 337 }; 338 339 340 c->tso = NULL; 341 switch (tsr->http_status) 342 { 343 case MHD_HTTP_OK: 344 break; 345 case MHD_HTTP_PAYMENT_REQUIRED: 346 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_PAYMENT_REQUIRED; 347 csr.details.payment_required.taler_pay_uri 348 = tsr->details.payment_required.payment_request; 349 csr.details.payment_required.payment_secret 350 = tsr->details.payment_required.ps; 351 c->af (c->af_cls, 352 &csr); 353 return; 354 case MHD_HTTP_FORBIDDEN: 355 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_INVALID_ANSWER; 356 c->af (c->af_cls, 357 &csr); 358 return; 359 case MHD_HTTP_NOT_FOUND: 360 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_TRUTH_UNKNOWN; 361 c->af (c->af_cls, 362 &csr); 363 return; 364 case MHD_HTTP_TOO_MANY_REQUESTS: 365 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_RATE_LIMIT_EXCEEDED; 366 csr.details.rate_limit_exceeded.request_limit 367 = tsr->details.too_many_requests.request_limit; 368 csr.details.rate_limit_exceeded.request_frequency 369 = tsr->details.too_many_requests.request_frequency; 370 c->af (c->af_cls, 371 &csr); 372 return; 373 default: 374 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE; 375 c->af (c->af_cls, 376 &csr); 377 return; 378 } 379 380 ANASTASIS_CRYPTO_user_identifier_derive (recovery->id_data, 381 &c->provider_salt, 382 &id); 383 if (GNUNET_OK != 384 ANASTASIS_CRYPTO_keyshare_decrypt (&tsr->details.success.eks, 385 &id, 386 c->answer, 387 &c->key_share)) 388 { 389 /* the provider answered, but with a key share we cannot use */ 390 GNUNET_break_op (0); 391 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE; 392 c->af (c->af_cls, 393 &csr); 394 return; 395 } 396 recovery->solved_challenges[recovery->solved_challenge_pos++] = c; 397 c->ci.solved = true; 398 csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED; 399 c->af (c->af_cls, 400 &csr); 401 402 /* Check if there is a policy for which all challenges have 403 been satisfied, if so, store it in 'rdps'. */ 404 rdps = NULL; 405 for (unsigned int i = 0; i < recovery->ri.dps_len; i++) 406 { 407 struct DecryptionPolicy *dps = &recovery->dps[i]; 408 bool missing = false; 409 410 for (unsigned int j = 0; j < dps->pub_details.challenges_length; j++) 411 { 412 bool found = false; 413 414 for (unsigned int k = 0; k < recovery->solved_challenge_pos; k++) 415 { 416 if (dps->pub_details.challenges[j] == recovery->solved_challenges[k]) 417 { 418 found = true; 419 break; 420 } 421 } 422 if (! found) 423 { 424 missing = true; 425 break; 426 } 427 } 428 if (! missing) 429 { 430 rdps = dps; 431 break; 432 } 433 } 434 if (NULL == rdps) 435 return; 436 437 { 438 void *core_secret; 439 size_t core_secret_size; 440 struct ANASTASIS_CRYPTO_KeyShareP 441 key_shares[rdps->pub_details.challenges_length]; 442 struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; 443 444 for (unsigned int l = 0; l < rdps->pub_details.challenges_length; l++) 445 for (unsigned int m = 0; m < recovery->solved_challenge_pos; m++) 446 if (rdps->pub_details.challenges[l] == recovery->solved_challenges[m]) 447 key_shares[l] = recovery->solved_challenges[m]->key_share; 448 ANASTASIS_CRYPTO_policy_key_derive (key_shares, 449 rdps->pub_details.challenges_length, 450 &rdps->master_salt, 451 &policy_key); 452 GNUNET_assert (NULL != rdps->emk); 453 GNUNET_assert (rdps->emk_size > 0); 454 if (GNUNET_OK != 455 ANASTASIS_CRYPTO_core_secret_recover (rdps->emk, 456 rdps->emk_size, 457 &policy_key, 458 recovery->enc_core_secret, 459 recovery->enc_core_secret_size, 460 &core_secret, 461 &core_secret_size)) 462 { 463 /* do NOT hand a garbage buffer to the application as if it were 464 the recovered secret */ 465 GNUNET_break_op (0); 466 recovery->csc (recovery->csc_cls, 467 ANASTASIS_RS_CORE_SECRET_RECOVERY_FAILED, 468 NULL, 469 0); 470 ANASTASIS_recovery_abort (recovery); 471 return; 472 } 473 recovery->csc (recovery->csc_cls, 474 ANASTASIS_RS_SUCCESS, 475 core_secret, 476 core_secret_size); 477 GNUNET_free (core_secret); 478 ANASTASIS_recovery_abort (recovery); 479 } 480 } 481 482 483 const struct ANASTASIS_ChallengeDetails * 484 ANASTASIS_challenge_get_details (struct ANASTASIS_Challenge *challenge) 485 { 486 return &challenge->ci; 487 } 488 489 490 void 491 ANASTASIS_challenge_set_async (struct ANASTASIS_Challenge *challenge, 492 uint64_t answer_pin) 493 { 494 challenge->ci.async = true; 495 ANASTASIS_challenge_set_answer_pin (challenge, 496 answer_pin); 497 } 498 499 500 void 501 ANASTASIS_challenge_set_answer_pin (struct ANASTASIS_Challenge *challenge, 502 uint64_t answer_pin) 503 { 504 challenge->ci.have_answer_pin = true; 505 challenge->ci.answer_pin = answer_pin; 506 } 507 508 509 const struct ANASTASIS_RecoveryInformation * 510 ANASTASIS_recovery_get_info (const struct ANASTASIS_Recovery *r) 511 { 512 return &r->ri; 513 } 514 515 516 struct ANASTASIS_Challenge * 517 ANASTASIS_recovery_get_challenge ( 518 const struct ANASTASIS_Recovery *r, 519 const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid) 520 { 521 for (unsigned int i = 0; i < r->ri.cs_len; i++) 522 { 523 struct ANASTASIS_Challenge *c = r->ri.cs[i]; 524 525 if (0 == 526 GNUNET_memcmp (uuid, 527 &c->ci.uuid)) 528 return c; 529 } 530 return NULL; 531 } 532 533 534 enum GNUNET_GenericReturnValue 535 ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c, 536 const struct ANASTASIS_PaymentSecretP *psp, 537 ANASTASIS_ChallengeStartFeedback csf, 538 void *csf_cls) 539 { 540 if (c->ci.solved) 541 { 542 GNUNET_break (0); 543 return GNUNET_NO; /* already solved */ 544 } 545 if (NULL != c->tco) 546 { 547 GNUNET_break (0); 548 return GNUNET_NO; /* already solving */ 549 } 550 c->csf = csf; 551 c->csf_cls = csf_cls; 552 c->tco = ANASTASIS_truth_challenge (c->recovery->ctx, 553 c->url, 554 &c->ci.uuid, 555 &c->truth_key, 556 psp, 557 &truth_challenge_cb, 558 c); 559 if (NULL == c->tco) 560 { 561 GNUNET_break (0); 562 return GNUNET_SYSERR; 563 } 564 return GNUNET_OK; 565 } 566 567 568 enum GNUNET_GenericReturnValue 569 ANASTASIS_challenge_answer3 (struct ANASTASIS_Challenge *c, 570 const struct ANASTASIS_PaymentSecretP *psp, 571 struct GNUNET_TIME_Relative timeout, 572 const struct GNUNET_HashCode *hashed_answer, 573 ANASTASIS_AnswerFeedback af, 574 void *af_cls) 575 { 576 if (c->ci.solved) 577 { 578 GNUNET_break (0); 579 return GNUNET_NO; /* already solved */ 580 } 581 if (NULL != c->tso) 582 { 583 GNUNET_break (0); 584 return GNUNET_NO; /* already solving */ 585 } 586 c->af = af; 587 c->af_cls = af_cls; 588 c->tso = ANASTASIS_truth_solve (c->recovery->ctx, 589 c->url, 590 &c->ci.uuid, 591 &c->truth_key, 592 psp, 593 timeout, 594 hashed_answer, 595 &truth_solve_cb, 596 c); 597 if (NULL == c->tso) 598 { 599 GNUNET_break (0); 600 return GNUNET_SYSERR; 601 } 602 return GNUNET_OK; 603 } 604 605 606 enum GNUNET_GenericReturnValue 607 ANASTASIS_challenge_answer ( 608 struct ANASTASIS_Challenge *c, 609 const struct ANASTASIS_PaymentSecretP *psp, 610 struct GNUNET_TIME_Relative timeout, 611 const char *answer_str, 612 ANASTASIS_AnswerFeedback af, 613 void *af_cls) 614 { 615 struct GNUNET_HashCode hashed_answer; 616 617 GNUNET_free (c->answer); 618 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 619 "Answer to challenge is `%s'\n", 620 answer_str); 621 c->answer = GNUNET_strdup (answer_str); 622 ANASTASIS_CRYPTO_secure_answer_hash (answer_str, 623 &c->ci.uuid, 624 &c->question_salt, 625 &hashed_answer); 626 return ANASTASIS_challenge_answer3 (c, 627 psp, 628 timeout, 629 &hashed_answer, 630 af, 631 af_cls); 632 } 633 634 635 enum GNUNET_GenericReturnValue 636 ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c, 637 const struct ANASTASIS_PaymentSecretP *psp, 638 struct GNUNET_TIME_Relative timeout, 639 uint64_t answer, 640 ANASTASIS_AnswerFeedback af, 641 void *af_cls) 642 { 643 struct GNUNET_HashCode answer_s; 644 645 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 646 "Answer to challenge is %llu\n", 647 (unsigned long long) answer); 648 ANASTASIS_hash_answer (answer, 649 &answer_s); 650 return ANASTASIS_challenge_answer3 (c, 651 psp, 652 timeout, 653 &answer_s, 654 af, 655 af_cls); 656 } 657 658 659 void 660 ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c) 661 { 662 if (NULL != c->tso) 663 { 664 ANASTASIS_truth_solve_cancel (c->tso); 665 c->tso = NULL; 666 } 667 if (NULL != c->tco) 668 { 669 ANASTASIS_truth_challenge_cancel (c->tco); 670 c->tco = NULL; 671 } 672 c->af = NULL; 673 c->af_cls = NULL; 674 } 675 676 677 /** 678 * Function called with the results of a #ANASTASIS_policy_lookup() 679 * 680 * @param cls closure 681 * @param dd details about the lookup operation 682 */ 683 static void 684 policy_lookup_cb (void *cls, 685 const struct ANASTASIS_DownloadDetails *dd) 686 { 687 struct ANASTASIS_Recovery *r = cls; 688 void *plaintext; 689 size_t size_plaintext; 690 json_error_t json_error; 691 const json_t *dec_policies; 692 const json_t *esc_methods; 693 json_t *recovery_document; 694 695 r->plo = NULL; 696 switch (dd->http_status) 697 { 698 case MHD_HTTP_OK: 699 break; 700 case MHD_HTTP_NOT_FOUND: 701 r->csc (r->csc_cls, 702 ANASTASIS_RS_POLICY_UNKNOWN, 703 NULL, 704 0); 705 ANASTASIS_recovery_abort (r); 706 return; 707 case MHD_HTTP_NO_CONTENT: 708 /* Account known, policy expired */ 709 r->csc (r->csc_cls, 710 ANASTASIS_RS_POLICY_GONE, 711 NULL, 712 0); 713 ANASTASIS_recovery_abort (r); 714 return; 715 case MHD_HTTP_INTERNAL_SERVER_ERROR: 716 /* Bad server... */ 717 r->csc (r->csc_cls, 718 ANASTASIS_RS_POLICY_SERVER_ERROR, 719 NULL, 720 0); 721 ANASTASIS_recovery_abort (r); 722 return; 723 case MHD_HTTP_NOT_MODIFIED: 724 /* Should not be possible, we do not cache, fall-through! */ 725 default: 726 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 727 "Unexpected response code %u in %s:%u\n", 728 dd->http_status, 729 __FILE__, 730 __LINE__); 731 r->csc (r->csc_cls, 732 ANASTASIS_RS_POLICY_DOWNLOAD_FAILED, 733 NULL, 734 0); 735 ANASTASIS_recovery_abort (r); 736 return; 737 } 738 if (NULL == dd->details.ok.policy) 739 { 740 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 741 "No recovery data available"); 742 r->csc (r->csc_cls, 743 ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY, 744 NULL, 745 0); 746 ANASTASIS_recovery_abort (r); 747 return; 748 } 749 if (GNUNET_OK != 750 ANASTASIS_CRYPTO_recovery_document_decrypt (&r->id, 751 dd->details.ok.policy, 752 dd->details.ok.policy_size, 753 &plaintext, 754 &size_plaintext)) 755 { 756 GNUNET_break_op (0); 757 r->csc (r->csc_cls, 758 ANASTASIS_RS_POLICY_DECRYPTION_FAILED, 759 NULL, 760 0); 761 ANASTASIS_recovery_abort (r); 762 return; 763 } 764 if (size_plaintext < sizeof (uint32_t)) 765 { 766 GNUNET_break_op (0); 767 r->csc (r->csc_cls, 768 ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION, 769 NULL, 770 0); 771 ANASTASIS_recovery_abort (r); 772 GNUNET_free (plaintext); 773 return; 774 } 775 { 776 uint32_t be_size; 777 uLongf pt_size; 778 char *pt; 779 780 memcpy (&be_size, 781 plaintext, 782 sizeof (uint32_t)); 783 pt_size = ntohl (be_size); 784 pt = GNUNET_malloc_large (pt_size); 785 if (NULL == pt) 786 { 787 GNUNET_break_op (0); 788 r->csc (r->csc_cls, 789 ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG, 790 NULL, 791 0); 792 ANASTASIS_recovery_abort (r); 793 GNUNET_free (plaintext); 794 return; 795 } 796 if (Z_OK != 797 uncompress ((Bytef *) pt, 798 &pt_size, 799 (const Bytef *) plaintext + sizeof (uint32_t), 800 size_plaintext - sizeof (uint32_t))) 801 { 802 GNUNET_break_op (0); 803 r->csc (r->csc_cls, 804 ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION, 805 NULL, 806 0); 807 GNUNET_free (plaintext); 808 GNUNET_free (pt); 809 ANASTASIS_recovery_abort (r); 810 return; 811 } 812 GNUNET_free (plaintext); 813 recovery_document = json_loadb ((char *) pt, 814 pt_size, 815 JSON_DECODE_ANY, 816 &json_error); 817 GNUNET_free (pt); 818 if (NULL == recovery_document) 819 { 820 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 821 "Failed to read JSON input: %s at %d:%s (offset: %d)\n", 822 json_error.text, 823 json_error.line, 824 json_error.source, 825 json_error.position); 826 GNUNET_break_op (0); 827 r->csc (r->csc_cls, 828 ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON, 829 NULL, 830 0); 831 ANASTASIS_recovery_abort (r); 832 return; 833 } 834 835 { 836 const char *secret_name = NULL; 837 struct GNUNET_JSON_Specification spec[] = { 838 GNUNET_JSON_spec_array_const ("policies", 839 &dec_policies), 840 GNUNET_JSON_spec_array_const ("escrow_methods", 841 &esc_methods), 842 GNUNET_JSON_spec_mark_optional ( 843 GNUNET_JSON_spec_string ("secret_name", 844 &secret_name), 845 NULL), 846 GNUNET_JSON_spec_varsize ("encrypted_core_secret", 847 &r->enc_core_secret, 848 &r->enc_core_secret_size), 849 GNUNET_JSON_spec_end () 850 }; 851 852 if (GNUNET_OK != 853 GNUNET_JSON_parse (recovery_document, 854 spec, 855 NULL, NULL)) 856 { 857 GNUNET_break_op (0); 858 json_dumpf (recovery_document, 859 stderr, 860 0); 861 r->csc (r->csc_cls, 862 ANASTASIS_RS_POLICY_MALFORMED_JSON, 863 NULL, 864 0); 865 goto cleanup; 866 } 867 if (NULL != secret_name) 868 { 869 GNUNET_break (NULL == r->secret_name); 870 r->secret_name = GNUNET_strdup (secret_name); 871 r->ri.secret_name = r->secret_name; 872 } 873 } 874 } 875 876 if ( (json_array_size (esc_methods) > UINT_MAX) || 877 (json_array_size (dec_policies) > UINT_MAX) ) 878 { 879 GNUNET_break_op (0); 880 r->csc (r->csc_cls, 881 ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG, 882 NULL, 883 0); 884 goto cleanup; 885 } 886 887 r->ri.version = dd->details.ok.version; 888 r->ri.cs_len 889 = (unsigned int) json_array_size (esc_methods); 890 r->ri.dps_len 891 = (unsigned int) json_array_size (dec_policies); 892 r->ri.dps 893 = GNUNET_new_array (r->ri.dps_len, 894 struct ANASTASIS_DecryptionPolicy *); 895 r->dps 896 = GNUNET_new_array (r->ri.dps_len, 897 struct DecryptionPolicy); 898 r->solved_challenges 899 = GNUNET_new_array (r->ri.cs_len, 900 struct ANASTASIS_Challenge *); 901 r->ri.cs 902 = GNUNET_new_array (r->ri.cs_len, 903 struct ANASTASIS_Challenge *); 904 r->cs 905 = GNUNET_new_array (r->ri.cs_len, 906 struct ANASTASIS_Challenge); 907 for (unsigned int i = 0; i < r->ri.cs_len; i++) 908 { 909 struct ANASTASIS_Challenge *cs = &r->cs[i]; 910 const char *instructions; 911 const char *url; 912 const char *escrow_type; 913 struct GNUNET_JSON_Specification spec[] = { 914 GNUNET_JSON_spec_fixed_auto ("uuid", 915 &cs->ci.uuid), 916 TALER_JSON_spec_web_url ("url", 917 &url), 918 GNUNET_JSON_spec_string ("instructions", 919 &instructions), 920 GNUNET_JSON_spec_fixed_auto ("truth_key", 921 &cs->truth_key), 922 GNUNET_JSON_spec_fixed_auto ("question_salt", 923 &cs->question_salt), 924 GNUNET_JSON_spec_fixed_auto ("provider_salt", 925 &cs->provider_salt), 926 GNUNET_JSON_spec_string ("escrow_type", 927 &escrow_type), 928 GNUNET_JSON_spec_end () 929 }; 930 931 r->ri.cs[i] = cs; 932 cs->recovery = r; 933 if (GNUNET_OK != 934 GNUNET_JSON_parse (json_array_get (esc_methods, 935 i), 936 spec, 937 NULL, NULL)) 938 { 939 GNUNET_break_op (0); 940 r->csc (r->csc_cls, 941 ANASTASIS_RS_POLICY_MALFORMED_JSON, 942 NULL, 943 0); 944 goto cleanup; 945 } 946 cs->url = GNUNET_strdup (url); 947 cs->type = GNUNET_strdup (escrow_type); 948 cs->ci.type = cs->type; 949 cs->ci.provider_url = cs->url; 950 cs->instructions = GNUNET_strdup (instructions); 951 cs->ci.instructions = cs->instructions; 952 } 953 954 for (unsigned int j = 0; j < r->ri.dps_len; j++) 955 { 956 struct DecryptionPolicy *dp = &r->dps[j]; 957 const json_t *uuids; 958 json_t *juuid; 959 size_t n_index; 960 struct GNUNET_JSON_Specification spec[] = { 961 GNUNET_JSON_spec_varsize ("master_key", 962 &dp->emk, 963 &dp->emk_size), 964 GNUNET_JSON_spec_fixed_auto ("master_salt", 965 &dp->master_salt), 966 GNUNET_JSON_spec_array_const ("uuids", 967 &uuids), 968 GNUNET_JSON_spec_end () 969 }; 970 971 r->ri.dps[j] = &r->dps[j].pub_details; 972 if (GNUNET_OK != 973 GNUNET_JSON_parse (json_array_get (dec_policies, 974 j), 975 spec, 976 NULL, NULL)) 977 { 978 GNUNET_break_op (0); 979 r->csc (r->csc_cls, 980 ANASTASIS_RS_POLICY_MALFORMED_JSON, 981 NULL, 982 0); 983 goto cleanup; 984 } 985 986 GNUNET_assert (NULL != dp->emk); 987 GNUNET_assert (dp->emk_size > 0); 988 989 if (json_array_size (uuids) > UINT_MAX) 990 { 991 GNUNET_break_op (0); 992 r->csc (r->csc_cls, 993 ANASTASIS_RS_POLICY_MALFORMED_JSON, 994 NULL, 995 0); 996 goto cleanup; 997 } 998 dp->pub_details.challenges_length 999 = (unsigned int) json_array_size (uuids); 1000 dp->pub_details.challenges 1001 = GNUNET_new_array (dp->pub_details.challenges_length, 1002 struct ANASTASIS_Challenge *); 1003 json_array_foreach (uuids, n_index, juuid) 1004 { 1005 const char *uuid_str = json_string_value (juuid); 1006 struct ANASTASIS_CRYPTO_TruthUUIDP uuid; 1007 bool found = false; 1008 1009 if ( (NULL == uuid_str) || 1010 (GNUNET_OK != 1011 GNUNET_STRINGS_string_to_data ( 1012 uuid_str, 1013 strlen (uuid_str), 1014 &uuid, 1015 sizeof (uuid))) ) 1016 { 1017 GNUNET_break_op (0); 1018 r->csc (r->csc_cls, 1019 ANASTASIS_RS_POLICY_MALFORMED_JSON, 1020 NULL, 1021 0); 1022 goto cleanup; 1023 } 1024 for (unsigned int i = 0; i<r->ri.cs_len; i++) 1025 { 1026 if (0 != 1027 GNUNET_memcmp (&uuid, 1028 &r->cs[i].ci.uuid)) 1029 continue; 1030 found = true; 1031 dp->pub_details.challenges[n_index] = &r->cs[i]; 1032 break; 1033 } 1034 if (! found) 1035 { 1036 GNUNET_break_op (0); 1037 r->csc (r->csc_cls, 1038 ANASTASIS_RS_POLICY_MALFORMED_JSON, 1039 NULL, 1040 0); 1041 goto cleanup; 1042 } 1043 } 1044 } 1045 r->pc (r->pc_cls, 1046 &r->ri); 1047 json_decref (recovery_document); 1048 return; 1049 cleanup: 1050 ANASTASIS_recovery_abort (r); 1051 json_decref (recovery_document); 1052 } 1053 1054 1055 struct ANASTASIS_Recovery * 1056 ANASTASIS_recovery_begin ( 1057 struct GNUNET_CURL_Context *ctx, 1058 const json_t *id_data, 1059 unsigned int version, 1060 const char *anastasis_provider_url, 1061 const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt, 1062 ANASTASIS_PolicyCallback pc, 1063 void *pc_cls, 1064 ANASTASIS_CoreSecretCallback csc, 1065 void *csc_cls) 1066 { 1067 struct ANASTASIS_Recovery *r; 1068 struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; 1069 1070 r = GNUNET_new (struct ANASTASIS_Recovery); 1071 r->csc = csc; 1072 r->csc_cls = csc_cls; 1073 r->pc = pc; 1074 r->pc_cls = pc_cls; 1075 r->ctx = ctx; 1076 r->id_data = json_incref ((json_t *) id_data); 1077 r->provider_url = GNUNET_strdup (anastasis_provider_url); 1078 ANASTASIS_CRYPTO_user_identifier_derive (id_data, 1079 provider_salt, 1080 &r->id); 1081 ANASTASIS_CRYPTO_account_public_key_derive (&r->id, 1082 &pub_key); 1083 r->ri.version = version; 1084 if (0 != version) 1085 { 1086 r->plo = ANASTASIS_policy_lookup_version (r->ctx, 1087 anastasis_provider_url, 1088 &pub_key, 1089 &policy_lookup_cb, 1090 r, 1091 version); 1092 } 1093 else 1094 { 1095 r->plo = ANASTASIS_policy_lookup (r->ctx, 1096 anastasis_provider_url, 1097 &pub_key, 1098 &policy_lookup_cb, 1099 r); 1100 } 1101 if (NULL == r->plo) 1102 { 1103 GNUNET_break (0); 1104 ANASTASIS_recovery_abort (r); 1105 return NULL; 1106 } 1107 return r; 1108 } 1109 1110 1111 json_t * 1112 ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) 1113 { 1114 json_t *dps_arr; 1115 json_t *cs_arr; 1116 1117 dps_arr = json_array (); 1118 GNUNET_assert (NULL != dps_arr); 1119 for (unsigned int i = 0; i<r->ri.dps_len; i++) 1120 { 1121 const struct DecryptionPolicy *dp = &r->dps[i]; 1122 json_t *c_arr; 1123 json_t *dps; 1124 1125 c_arr = json_array (); 1126 GNUNET_assert (NULL != c_arr); 1127 for (unsigned int j = 0; j < dp->pub_details.challenges_length; j++) 1128 { 1129 const struct ANASTASIS_Challenge *c = dp->pub_details.challenges[j]; 1130 json_t *cs; 1131 1132 cs = GNUNET_JSON_PACK ( 1133 GNUNET_JSON_pack_data_auto ("uuid", 1134 &c->ci.uuid)); 1135 GNUNET_assert (0 == 1136 json_array_append_new (c_arr, 1137 cs)); 1138 } 1139 GNUNET_assert (NULL != dp->emk); 1140 dps = GNUNET_JSON_PACK ( 1141 GNUNET_JSON_pack_data_varsize ("encrypted_master_key", 1142 dp->emk, 1143 dp->emk_size), 1144 GNUNET_JSON_pack_data_auto ("master_salt", 1145 &dp->master_salt), 1146 GNUNET_JSON_pack_array_steal ("challenges", 1147 c_arr)); 1148 GNUNET_assert (0 == 1149 json_array_append_new (dps_arr, 1150 dps)); 1151 } 1152 cs_arr = json_array (); 1153 GNUNET_assert (NULL != cs_arr); 1154 for (unsigned int i = 0; i<r->ri.cs_len; i++) 1155 { 1156 const struct ANASTASIS_Challenge *c = &r->cs[i]; 1157 json_t *cs; 1158 1159 cs = GNUNET_JSON_PACK ( 1160 GNUNET_JSON_pack_data_auto ("uuid", 1161 &c->ci.uuid), 1162 GNUNET_JSON_pack_string ("uuid-display", 1163 ANASTASIS_CRYPTO_uuid2s (&c->ci.uuid)), 1164 GNUNET_JSON_pack_data_auto ("truth_key", 1165 &c->truth_key), 1166 GNUNET_JSON_pack_data_auto ("question_salt", 1167 &c->question_salt), 1168 GNUNET_JSON_pack_data_auto ("provider_salt", 1169 &c->provider_salt), 1170 GNUNET_JSON_pack_allow_null ( 1171 GNUNET_JSON_pack_data_varsize ("key_share", 1172 c->ci.solved 1173 ? &c->key_share 1174 : NULL, 1175 sizeof (c->key_share))), 1176 GNUNET_JSON_pack_string ("url", 1177 c->url), 1178 GNUNET_JSON_pack_string ("type", 1179 c->type), 1180 GNUNET_JSON_pack_string ("instructions", 1181 c->instructions), 1182 GNUNET_JSON_pack_bool ("solved", 1183 c->ci.solved), 1184 GNUNET_JSON_pack_bool ("async", 1185 c->ci.async), 1186 GNUNET_JSON_pack_conditional ( 1187 c->ci.have_answer_pin, 1188 GNUNET_JSON_pack_uint64 ("answer-pin", 1189 c->ci.answer_pin))); 1190 GNUNET_assert (0 == 1191 json_array_append_new (cs_arr, 1192 cs)); 1193 } 1194 1195 return GNUNET_JSON_PACK ( 1196 GNUNET_JSON_pack_data_auto ("id", 1197 &r->id), 1198 GNUNET_JSON_pack_array_steal ("decryption_policies", 1199 dps_arr), 1200 GNUNET_JSON_pack_array_steal ("challenges", 1201 cs_arr), 1202 GNUNET_JSON_pack_uint64 ("version", 1203 r->ri.version), 1204 GNUNET_JSON_pack_object_incref ("id_data", 1205 (json_t *) r->id_data), 1206 GNUNET_JSON_pack_string ("provider_url", 1207 r->provider_url), 1208 GNUNET_JSON_pack_allow_null ( 1209 GNUNET_JSON_pack_string ("secret_name", 1210 r->secret_name)), 1211 GNUNET_JSON_pack_data_varsize ("encrypted_core_secret", 1212 r->enc_core_secret, 1213 r->enc_core_secret_size)); 1214 } 1215 1216 1217 /** 1218 * Parse the @a cs_array with information about 1219 * the various challenges and their solution state 1220 * and update @a r accordingly 1221 * 1222 * @param[in,out] r recovery information to update 1223 * @param cs_arr serialized data to parse 1224 * @return #GNUNET_OK on success 1225 */ 1226 static enum GNUNET_GenericReturnValue 1227 parse_cs_array (struct ANASTASIS_Recovery *r, 1228 const json_t *cs_arr) 1229 { 1230 json_t *cs; 1231 size_t n_index; 1232 1233 if (! json_is_array (cs_arr)) 1234 { 1235 GNUNET_break_op (0); 1236 return GNUNET_SYSERR; 1237 } 1238 if (json_array_size (cs_arr) > UINT_MAX) 1239 { 1240 GNUNET_break_op (0); 1241 return GNUNET_SYSERR; 1242 } 1243 r->ri.cs_len 1244 = (unsigned int) json_array_size (cs_arr); 1245 r->solved_challenges 1246 = GNUNET_new_array (r->ri.cs_len, 1247 struct ANASTASIS_Challenge *); 1248 r->ri.cs = GNUNET_new_array (r->ri.cs_len, 1249 struct ANASTASIS_Challenge *); 1250 r->cs = GNUNET_new_array (r->ri.cs_len, 1251 struct ANASTASIS_Challenge); 1252 json_array_foreach (cs_arr, n_index, cs) 1253 { 1254 struct ANASTASIS_Challenge *c = &r->cs[n_index]; 1255 const char *instructions; 1256 const char *url; 1257 const char *escrow_type; 1258 bool no_key_share; 1259 bool no_answer_pin; 1260 struct GNUNET_JSON_Specification spec[] = { 1261 GNUNET_JSON_spec_fixed_auto ("uuid", 1262 &c->ci.uuid), 1263 TALER_JSON_spec_web_url ("url", 1264 &url), 1265 GNUNET_JSON_spec_string ("instructions", 1266 &instructions), 1267 GNUNET_JSON_spec_fixed_auto ("truth_key", 1268 &c->truth_key), 1269 GNUNET_JSON_spec_fixed_auto ("question_salt", 1270 &c->question_salt), 1271 GNUNET_JSON_spec_fixed_auto ("provider_salt", 1272 &c->provider_salt), 1273 GNUNET_JSON_spec_string ("type", 1274 &escrow_type), 1275 GNUNET_JSON_spec_mark_optional ( 1276 GNUNET_JSON_spec_bool ("async", 1277 &c->ci.async), 1278 NULL), 1279 GNUNET_JSON_spec_mark_optional ( 1280 GNUNET_JSON_spec_uint64 ("answer-pin", 1281 &c->ci.answer_pin), 1282 &no_answer_pin), 1283 GNUNET_JSON_spec_mark_optional ( 1284 GNUNET_JSON_spec_fixed_auto ("key_share", 1285 &c->key_share), 1286 &no_key_share), 1287 GNUNET_JSON_spec_end () 1288 }; 1289 1290 r->ri.cs[n_index] = c; 1291 c->recovery = r; 1292 if (GNUNET_OK != 1293 GNUNET_JSON_parse (cs, 1294 spec, 1295 NULL, NULL)) 1296 { 1297 GNUNET_break_op (0); 1298 return GNUNET_SYSERR; 1299 } 1300 c->url = GNUNET_strdup (url); 1301 c->type = GNUNET_strdup (escrow_type); 1302 c->ci.type = c->type; 1303 c->instructions = GNUNET_strdup (instructions); 1304 c->ci.instructions = c->instructions; 1305 c->ci.provider_url = c->url; 1306 c->ci.have_answer_pin = ! no_answer_pin; 1307 if (! no_key_share) 1308 { 1309 c->ci.solved = true; 1310 r->solved_challenges[r->solved_challenge_pos++] = c; 1311 } 1312 } 1313 return GNUNET_OK; 1314 } 1315 1316 1317 /** 1318 * Parse the @a dps_array with our decryption policies 1319 * and update @a r accordingly 1320 * 1321 * @param[in,out] r recovery information to update 1322 * @param dps_arr serialized data to parse 1323 * @return #GNUNET_OK on success 1324 */ 1325 static enum GNUNET_GenericReturnValue 1326 parse_dps_array (struct ANASTASIS_Recovery *r, 1327 const json_t *dps_arr) 1328 { 1329 json_t *dps; 1330 size_t n_index; 1331 1332 if (! json_is_array (dps_arr)) 1333 { 1334 GNUNET_break_op (0); 1335 return GNUNET_SYSERR; 1336 } 1337 if (json_array_size (dps_arr) > UINT_MAX) 1338 { 1339 GNUNET_break_op (0); 1340 return GNUNET_SYSERR; 1341 } 1342 r->ri.dps_len 1343 = (unsigned int) json_array_size (dps_arr); 1344 r->dps = GNUNET_new_array (r->ri.dps_len, 1345 struct DecryptionPolicy); 1346 r->ri.dps = GNUNET_new_array (r->ri.dps_len, 1347 struct ANASTASIS_DecryptionPolicy *); 1348 1349 json_array_foreach (dps_arr, n_index, dps) 1350 { 1351 struct DecryptionPolicy *dp = &r->dps[n_index]; 1352 const json_t *challenges; 1353 struct GNUNET_JSON_Specification spec[] = { 1354 GNUNET_JSON_spec_varsize ("encrypted_master_key", 1355 &dp->emk, 1356 &dp->emk_size), 1357 GNUNET_JSON_spec_fixed_auto ("master_salt", 1358 &dp->master_salt), 1359 GNUNET_JSON_spec_array_const ("challenges", 1360 &challenges), 1361 GNUNET_JSON_spec_end () 1362 }; 1363 const char *err_json_name; 1364 unsigned int err_line; 1365 1366 r->ri.dps[n_index] = &dp->pub_details; 1367 if (GNUNET_OK != 1368 GNUNET_JSON_parse (dps, 1369 spec, 1370 &err_json_name, 1371 &err_line)) 1372 { 1373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1374 "Failed to parse decryption policy JSON entry `%s'\n", 1375 err_json_name); 1376 json_dumpf (dps, 1377 stderr, 1378 JSON_INDENT (2)); 1379 return GNUNET_SYSERR; 1380 } 1381 GNUNET_assert (NULL != dp->emk); 1382 GNUNET_assert (dp->emk_size > 0); 1383 if (json_array_size (challenges) > UINT_MAX) 1384 { 1385 GNUNET_break_op (0); 1386 return GNUNET_SYSERR; 1387 } 1388 dp->pub_details.challenges_length 1389 = (unsigned int) json_array_size (challenges); 1390 dp->pub_details.challenges 1391 = GNUNET_new_array (dp->pub_details.challenges_length, 1392 struct ANASTASIS_Challenge *); 1393 1394 { 1395 json_t *challenge; 1396 size_t c_index; 1397 json_array_foreach (challenges, c_index, challenge) 1398 { 1399 struct ANASTASIS_CRYPTO_TruthUUIDP uuid; 1400 struct GNUNET_JSON_Specification ispec[] = { 1401 GNUNET_JSON_spec_fixed_auto ("uuid", 1402 &uuid), 1403 GNUNET_JSON_spec_end () 1404 }; 1405 bool found = false; 1406 1407 if (GNUNET_OK != 1408 GNUNET_JSON_parse (challenge, 1409 ispec, 1410 NULL, NULL)) 1411 { 1412 GNUNET_break_op (0); 1413 GNUNET_JSON_parse_free (spec); 1414 return GNUNET_SYSERR; 1415 } 1416 for (unsigned int i = 0; i<r->ri.cs_len; i++) 1417 { 1418 if (0 != 1419 GNUNET_memcmp (&uuid, 1420 &r->cs[i].ci.uuid)) 1421 continue; 1422 dp->pub_details.challenges[c_index] = &r->cs[i]; 1423 found = true; 1424 } 1425 if (! found) 1426 { 1427 GNUNET_break_op (0); 1428 GNUNET_JSON_parse_free (spec); 1429 return GNUNET_SYSERR; 1430 } 1431 } 1432 } 1433 /* Do NOT free the spec: we are still using dp->ems. */ 1434 } 1435 return GNUNET_OK; 1436 } 1437 1438 1439 /** 1440 * Asynchronously call "pc" on the recovery information. 1441 * 1442 * @param cls a `struct ANASTASIS_Recovery *` 1443 */ 1444 static void 1445 run_async_pc (void *cls) 1446 { 1447 struct ANASTASIS_Recovery *r = cls; 1448 1449 r->do_async = NULL; 1450 r->pc (r->pc_cls, 1451 &r->ri); 1452 } 1453 1454 1455 struct ANASTASIS_Recovery * 1456 ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx, 1457 const json_t *input) 1458 { 1459 struct ANASTASIS_Recovery *r; 1460 1461 r = GNUNET_new (struct ANASTASIS_Recovery); 1462 r->ctx = ctx; 1463 { 1464 const char *err_json_name; 1465 unsigned int err_line; 1466 uint32_t version; 1467 const json_t *dps_arr; 1468 const json_t *cs_arr; 1469 const json_t *id_data; 1470 const char *provider_url; 1471 const char *secret_name; 1472 void *ecs; 1473 size_t ecs_size; 1474 struct GNUNET_JSON_Specification spec[] = { 1475 GNUNET_JSON_spec_fixed_auto ("id", 1476 &r->id), 1477 TALER_JSON_spec_web_url ("provider_url", 1478 &provider_url), 1479 GNUNET_JSON_spec_mark_optional ( 1480 GNUNET_JSON_spec_string ("secret_name", 1481 &secret_name), 1482 NULL), 1483 GNUNET_JSON_spec_uint32 ("version", 1484 &version), 1485 GNUNET_JSON_spec_array_const ("decryption_policies", 1486 &dps_arr), 1487 GNUNET_JSON_spec_array_const ("challenges", 1488 &cs_arr), 1489 GNUNET_JSON_spec_object_const ("id_data", 1490 &id_data), 1491 GNUNET_JSON_spec_varsize ("encrypted_core_secret", 1492 &ecs, 1493 &ecs_size), 1494 GNUNET_JSON_spec_end () 1495 }; 1496 1497 if (GNUNET_OK != 1498 GNUNET_JSON_parse (input, 1499 spec, 1500 &err_json_name, 1501 &err_line)) 1502 { 1503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1504 "Failed to parse recovery document JSON entry `%s'\n", 1505 err_json_name); 1506 json_dumpf (input, 1507 stderr, 1508 JSON_INDENT (2)); 1509 return NULL; 1510 } 1511 r->ri.version = version; 1512 if ( (GNUNET_OK != 1513 parse_cs_array (r, 1514 cs_arr)) || 1515 (GNUNET_OK != 1516 parse_dps_array (r, 1517 dps_arr)) ) 1518 { 1519 GNUNET_break_op (0); 1520 ANASTASIS_recovery_abort (r); 1521 GNUNET_JSON_parse_free (spec); 1522 return NULL; 1523 } 1524 r->id_data = json_incref ((json_t *) id_data); 1525 r->provider_url = GNUNET_strdup (provider_url); 1526 if (NULL != secret_name) 1527 r->secret_name = GNUNET_strdup (secret_name); 1528 r->ri.secret_name = r->secret_name; 1529 if (0 != ecs_size) 1530 { 1531 r->enc_core_secret = GNUNET_memdup (ecs, 1532 ecs_size); 1533 r->enc_core_secret_size = ecs_size; 1534 } 1535 GNUNET_JSON_parse_free (spec); 1536 } 1537 return r; 1538 } 1539 1540 1541 enum GNUNET_GenericReturnValue 1542 ANASTASIS_recovery_resume (struct ANASTASIS_Recovery *r, 1543 ANASTASIS_PolicyCallback pc, 1544 void *pc_cls, 1545 ANASTASIS_CoreSecretCallback csc, 1546 void *csc_cls) 1547 { 1548 GNUNET_assert (NULL == r->pc); 1549 GNUNET_assert (NULL == r->plo); 1550 GNUNET_assert (NULL == r->do_async); 1551 r->csc = csc; 1552 r->csc_cls = csc_cls; 1553 r->pc = pc; 1554 r->pc_cls = pc_cls; 1555 if (0 == r->ri.dps_len) 1556 { 1557 struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key; 1558 1559 ANASTASIS_CRYPTO_account_public_key_derive (&r->id, 1560 &pub_key); 1561 if (0 != r->ri.version) 1562 { 1563 r->plo = ANASTASIS_policy_lookup_version (r->ctx, 1564 r->provider_url, 1565 &pub_key, 1566 &policy_lookup_cb, 1567 r, 1568 r->ri.version); 1569 } 1570 else 1571 { 1572 r->plo = ANASTASIS_policy_lookup (r->ctx, 1573 r->provider_url, 1574 &pub_key, 1575 &policy_lookup_cb, 1576 r); 1577 } 1578 if (NULL == r->plo) 1579 { 1580 GNUNET_break (0); 1581 return GNUNET_SYSERR; 1582 } 1583 } 1584 else 1585 { 1586 r->do_async = GNUNET_SCHEDULER_add_now (&run_async_pc, 1587 r); 1588 } 1589 return GNUNET_OK; 1590 } 1591 1592 1593 void 1594 ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r) 1595 { 1596 if (NULL != r->do_async) 1597 { 1598 GNUNET_SCHEDULER_cancel (r->do_async); 1599 r->do_async = NULL; 1600 } 1601 if (NULL != r->plo) 1602 { 1603 ANASTASIS_policy_lookup_cancel (r->plo); 1604 r->plo = NULL; 1605 } 1606 GNUNET_free (r->solved_challenges); 1607 for (unsigned int j = 0; j < r->ri.dps_len; j++) 1608 { 1609 GNUNET_free (r->dps[j].pub_details.challenges); 1610 GNUNET_free (r->dps[j].emk); 1611 } 1612 GNUNET_free (r->ri.dps); 1613 for (unsigned int i = 0; i < r->ri.cs_len; i++) 1614 { 1615 struct ANASTASIS_Challenge *cs = &r->cs[i]; 1616 1617 if (NULL != cs->tso) 1618 { 1619 ANASTASIS_truth_solve_cancel (cs->tso); 1620 cs->tso = NULL; 1621 } 1622 GNUNET_free (cs->url); 1623 GNUNET_free (cs->type); 1624 GNUNET_free (cs->instructions); 1625 GNUNET_free (cs->answer); 1626 } 1627 GNUNET_free (r->ri.cs); 1628 GNUNET_free (r->cs); 1629 GNUNET_free (r->dps); 1630 json_decref (r->id_data); 1631 GNUNET_free (r->provider_url); 1632 GNUNET_free (r->secret_name); 1633 GNUNET_free (r->enc_core_secret); 1634 GNUNET_free (r); 1635 }