anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

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 }