anastasis

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

anastasis_recovery.c (44629B)


      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   ANASTASIS_CRYPTO_keyshare_decrypt (&tsr->details.success.eks,
    384                                      &id,
    385                                      c->answer,
    386                                      &c->key_share);
    387   recovery->solved_challenges[recovery->solved_challenge_pos++] = c;
    388   c->ci.solved = true;
    389   csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED;
    390   c->af (c->af_cls,
    391          &csr);
    392 
    393   /* Check if there is a policy for which all challenges have
    394      been satisfied, if so, store it in 'rdps'. */
    395   rdps = NULL;
    396   for (unsigned int i = 0; i < recovery->ri.dps_len; i++)
    397   {
    398     struct DecryptionPolicy *dps = &recovery->dps[i];
    399     bool missing = false;
    400 
    401     for (unsigned int j = 0; j < dps->pub_details.challenges_length; j++)
    402     {
    403       bool found = false;
    404 
    405       for (unsigned int k = 0; k < recovery->solved_challenge_pos; k++)
    406       {
    407         if (dps->pub_details.challenges[j] == recovery->solved_challenges[k])
    408         {
    409           found = true;
    410           break;
    411         }
    412       }
    413       if (! found)
    414       {
    415         missing = true;
    416         break;
    417       }
    418     }
    419     if (! missing)
    420     {
    421       rdps = dps;
    422       break;
    423     }
    424   }
    425   if (NULL == rdps)
    426     return;
    427 
    428   {
    429     void *core_secret;
    430     size_t core_secret_size;
    431     struct ANASTASIS_CRYPTO_KeyShareP
    432       key_shares[rdps->pub_details.challenges_length];
    433     struct ANASTASIS_CRYPTO_PolicyKeyP policy_key;
    434 
    435     for (unsigned int l = 0; l < rdps->pub_details.challenges_length; l++)
    436       for (unsigned int m = 0; m < recovery->solved_challenge_pos; m++)
    437         if (rdps->pub_details.challenges[l] == recovery->solved_challenges[m])
    438           key_shares[l] = recovery->solved_challenges[m]->key_share;
    439     ANASTASIS_CRYPTO_policy_key_derive (key_shares,
    440                                         rdps->pub_details.challenges_length,
    441                                         &rdps->master_salt,
    442                                         &policy_key);
    443     GNUNET_assert (NULL != rdps->emk);
    444     GNUNET_assert (rdps->emk_size > 0);
    445     ANASTASIS_CRYPTO_core_secret_recover (rdps->emk,
    446                                           rdps->emk_size,
    447                                           &policy_key,
    448                                           recovery->enc_core_secret,
    449                                           recovery->enc_core_secret_size,
    450                                           &core_secret,
    451                                           &core_secret_size);
    452     recovery->csc (recovery->csc_cls,
    453                    ANASTASIS_RS_SUCCESS,
    454                    core_secret,
    455                    core_secret_size);
    456     GNUNET_free (core_secret);
    457     ANASTASIS_recovery_abort (recovery);
    458   }
    459 }
    460 
    461 
    462 const struct ANASTASIS_ChallengeDetails *
    463 ANASTASIS_challenge_get_details (struct ANASTASIS_Challenge *challenge)
    464 {
    465   return &challenge->ci;
    466 }
    467 
    468 
    469 enum GNUNET_GenericReturnValue
    470 ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c,
    471                            const struct ANASTASIS_PaymentSecretP *psp,
    472                            ANASTASIS_ChallengeStartFeedback csf,
    473                            void *csf_cls)
    474 {
    475   if (c->ci.solved)
    476   {
    477     GNUNET_break (0);
    478     return GNUNET_NO; /* already solved */
    479   }
    480   if (NULL != c->tco)
    481   {
    482     GNUNET_break (0);
    483     return GNUNET_NO; /* already solving */
    484   }
    485   c->csf = csf;
    486   c->csf_cls = csf_cls;
    487   c->tco = ANASTASIS_truth_challenge (c->recovery->ctx,
    488                                       c->url,
    489                                       &c->ci.uuid,
    490                                       &c->truth_key,
    491                                       psp,
    492                                       &truth_challenge_cb,
    493                                       c);
    494   if (NULL == c->tco)
    495   {
    496     GNUNET_break (0);
    497     return GNUNET_SYSERR;
    498   }
    499   return GNUNET_OK;
    500 }
    501 
    502 
    503 enum GNUNET_GenericReturnValue
    504 ANASTASIS_challenge_answer3 (struct ANASTASIS_Challenge *c,
    505                              const struct ANASTASIS_PaymentSecretP *psp,
    506                              struct GNUNET_TIME_Relative timeout,
    507                              const struct GNUNET_HashCode *hashed_answer,
    508                              ANASTASIS_AnswerFeedback af,
    509                              void *af_cls)
    510 {
    511   if (c->ci.solved)
    512   {
    513     GNUNET_break (0);
    514     return GNUNET_NO; /* already solved */
    515   }
    516   if (NULL != c->tso)
    517   {
    518     GNUNET_break (0);
    519     return GNUNET_NO; /* already solving */
    520   }
    521   c->af = af;
    522   c->af_cls = af_cls;
    523   c->tso = ANASTASIS_truth_solve (c->recovery->ctx,
    524                                   c->url,
    525                                   &c->ci.uuid,
    526                                   &c->truth_key,
    527                                   psp,
    528                                   timeout,
    529                                   hashed_answer,
    530                                   &truth_solve_cb,
    531                                   c);
    532   if (NULL == c->tso)
    533   {
    534     GNUNET_break (0);
    535     return GNUNET_SYSERR;
    536   }
    537   return GNUNET_OK;
    538 }
    539 
    540 
    541 enum GNUNET_GenericReturnValue
    542 ANASTASIS_challenge_answer (
    543   struct ANASTASIS_Challenge *c,
    544   const struct ANASTASIS_PaymentSecretP *psp,
    545   struct GNUNET_TIME_Relative timeout,
    546   const char *answer_str,
    547   ANASTASIS_AnswerFeedback af,
    548   void *af_cls)
    549 {
    550   struct GNUNET_HashCode hashed_answer;
    551 
    552   GNUNET_free (c->answer);
    553   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    554               "Answer to challenge is `%s'\n",
    555               answer_str);
    556   c->answer = GNUNET_strdup (answer_str);
    557   ANASTASIS_CRYPTO_secure_answer_hash (answer_str,
    558                                        &c->ci.uuid,
    559                                        &c->question_salt,
    560                                        &hashed_answer);
    561   return ANASTASIS_challenge_answer3 (c,
    562                                       psp,
    563                                       timeout,
    564                                       &hashed_answer,
    565                                       af,
    566                                       af_cls);
    567 }
    568 
    569 
    570 enum GNUNET_GenericReturnValue
    571 ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c,
    572                              const struct ANASTASIS_PaymentSecretP *psp,
    573                              struct GNUNET_TIME_Relative timeout,
    574                              uint64_t answer,
    575                              ANASTASIS_AnswerFeedback af,
    576                              void *af_cls)
    577 {
    578   struct GNUNET_HashCode answer_s;
    579 
    580   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    581               "Answer to challenge is %llu\n",
    582               (unsigned long long) answer);
    583   ANASTASIS_hash_answer (answer,
    584                          &answer_s);
    585   return ANASTASIS_challenge_answer3 (c,
    586                                       psp,
    587                                       timeout,
    588                                       &answer_s,
    589                                       af,
    590                                       af_cls);
    591 }
    592 
    593 
    594 void
    595 ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c)
    596 {
    597   if (NULL != c->tso)
    598   {
    599     ANASTASIS_truth_solve_cancel (c->tso);
    600     c->tso = NULL;
    601   }
    602   if (NULL != c->tco)
    603   {
    604     ANASTASIS_truth_challenge_cancel (c->tco);
    605     c->tco = NULL;
    606   }
    607   c->af = NULL;
    608   c->af_cls = NULL;
    609 }
    610 
    611 
    612 /**
    613  * Function called with the results of a #ANASTASIS_policy_lookup()
    614  *
    615  * @param cls closure
    616  * @param dd details about the lookup operation
    617  */
    618 static void
    619 policy_lookup_cb (void *cls,
    620                   const struct ANASTASIS_DownloadDetails *dd)
    621 {
    622   struct ANASTASIS_Recovery *r = cls;
    623   void *plaintext;
    624   size_t size_plaintext;
    625   json_error_t json_error;
    626   const json_t *dec_policies;
    627   const json_t *esc_methods;
    628   json_t *recovery_document;
    629 
    630   r->plo = NULL;
    631   switch (dd->http_status)
    632   {
    633   case MHD_HTTP_OK:
    634     break;
    635   case MHD_HTTP_NOT_FOUND:
    636     r->csc (r->csc_cls,
    637             ANASTASIS_RS_POLICY_UNKNOWN,
    638             NULL,
    639             0);
    640     ANASTASIS_recovery_abort (r);
    641     return;
    642   case MHD_HTTP_NO_CONTENT:
    643     /* Account known, policy expired */
    644     r->csc (r->csc_cls,
    645             ANASTASIS_RS_POLICY_GONE,
    646             NULL,
    647             0);
    648     ANASTASIS_recovery_abort (r);
    649     return;
    650   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    651     /* Bad server... */
    652     r->csc (r->csc_cls,
    653             ANASTASIS_RS_POLICY_SERVER_ERROR,
    654             NULL,
    655             0);
    656     ANASTASIS_recovery_abort (r);
    657     return;
    658   case MHD_HTTP_NOT_MODIFIED:
    659   /* Should not be possible, we do not cache, fall-through! */
    660   default:
    661     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    662                 "Unexpected response code %u in %s:%u\n",
    663                 dd->http_status,
    664                 __FILE__,
    665                 __LINE__);
    666     r->csc (r->csc_cls,
    667             ANASTASIS_RS_POLICY_DOWNLOAD_FAILED,
    668             NULL,
    669             0);
    670     ANASTASIS_recovery_abort (r);
    671     return;
    672   }
    673   if (NULL == dd->details.ok.policy)
    674   {
    675     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    676                 "No recovery data available");
    677     r->csc (r->csc_cls,
    678             ANASTASIS_RS_POLICY_DOWNLOAD_NO_POLICY,
    679             NULL,
    680             0);
    681     ANASTASIS_recovery_abort (r);
    682     return;
    683   }
    684   ANASTASIS_CRYPTO_recovery_document_decrypt (&r->id,
    685                                               dd->details.ok.policy,
    686                                               dd->details.ok.policy_size,
    687                                               &plaintext,
    688                                               &size_plaintext);
    689   if (size_plaintext < sizeof (uint32_t))
    690   {
    691     GNUNET_break_op (0);
    692     r->csc (r->csc_cls,
    693             ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION,
    694             NULL,
    695             0);
    696     ANASTASIS_recovery_abort (r);
    697     GNUNET_free (plaintext);
    698     return;
    699   }
    700   {
    701     uint32_t be_size;
    702     uLongf pt_size;
    703     char *pt;
    704 
    705     memcpy (&be_size,
    706             plaintext,
    707             sizeof (uint32_t));
    708     pt_size = ntohl (be_size);
    709     pt = GNUNET_malloc_large (pt_size);
    710     if (NULL == pt)
    711     {
    712       GNUNET_break_op (0);
    713       r->csc (r->csc_cls,
    714               ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG,
    715               NULL,
    716               0);
    717       ANASTASIS_recovery_abort (r);
    718       GNUNET_free (plaintext);
    719       return;
    720     }
    721     if (Z_OK !=
    722         uncompress ((Bytef *) pt,
    723                     &pt_size,
    724                     (const Bytef *) plaintext + sizeof (uint32_t),
    725                     size_plaintext - sizeof (uint32_t)))
    726     {
    727       GNUNET_break_op (0);
    728       r->csc (r->csc_cls,
    729               ANASTASIS_RS_POLICY_DOWNLOAD_INVALID_COMPRESSION,
    730               NULL,
    731               0);
    732       GNUNET_free (plaintext);
    733       GNUNET_free (pt);
    734       ANASTASIS_recovery_abort (r);
    735       return;
    736     }
    737     GNUNET_free (plaintext);
    738     recovery_document = json_loadb ((char *) pt,
    739                                     pt_size,
    740                                     JSON_DECODE_ANY,
    741                                     &json_error);
    742     GNUNET_free (pt);
    743     if (NULL == recovery_document)
    744     {
    745       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    746                   "Failed to read JSON input: %s at %d:%s (offset: %d)\n",
    747                   json_error.text,
    748                   json_error.line,
    749                   json_error.source,
    750                   json_error.position);
    751       GNUNET_break_op (0);
    752       r->csc (r->csc_cls,
    753               ANASTASIS_RS_POLICY_DOWNLOAD_NO_JSON,
    754               NULL,
    755               0);
    756       ANASTASIS_recovery_abort (r);
    757       return;
    758     }
    759 
    760     {
    761       const char *secret_name = NULL;
    762       struct GNUNET_JSON_Specification spec[] = {
    763         GNUNET_JSON_spec_array_const ("policies",
    764                                       &dec_policies),
    765         GNUNET_JSON_spec_array_const ("escrow_methods",
    766                                       &esc_methods),
    767         GNUNET_JSON_spec_mark_optional (
    768           GNUNET_JSON_spec_string ("secret_name",
    769                                    &secret_name),
    770           NULL),
    771         GNUNET_JSON_spec_varsize ("encrypted_core_secret",
    772                                   &r->enc_core_secret,
    773                                   &r->enc_core_secret_size),
    774         GNUNET_JSON_spec_end ()
    775       };
    776 
    777       if (GNUNET_OK !=
    778           GNUNET_JSON_parse (recovery_document,
    779                              spec,
    780                              NULL, NULL))
    781       {
    782         GNUNET_break_op (0);
    783         json_dumpf (recovery_document,
    784                     stderr,
    785                     0);
    786         r->csc (r->csc_cls,
    787                 ANASTASIS_RS_POLICY_MALFORMED_JSON,
    788                 NULL,
    789                 0);
    790         goto cleanup;
    791       }
    792       if (NULL != secret_name)
    793       {
    794         GNUNET_break (NULL == r->secret_name);
    795         r->secret_name = GNUNET_strdup (secret_name);
    796         r->ri.secret_name = r->secret_name;
    797       }
    798     }
    799   }
    800 
    801   if ( (json_array_size (esc_methods) > UINT_MAX) ||
    802        (json_array_size (dec_policies) > UINT_MAX) )
    803   {
    804     GNUNET_break_op (0);
    805     r->csc (r->csc_cls,
    806             ANASTASIS_RS_POLICY_DOWNLOAD_TOO_BIG,
    807             NULL,
    808             0);
    809     goto cleanup;
    810   }
    811 
    812   r->ri.version = dd->details.ok.version;
    813   r->ri.cs_len
    814     = (unsigned int) json_array_size (esc_methods);
    815   r->ri.dps_len
    816     = (unsigned int) json_array_size (dec_policies);
    817   r->ri.dps
    818     = GNUNET_new_array (r->ri.dps_len,
    819                         struct ANASTASIS_DecryptionPolicy *);
    820   r->dps
    821     = GNUNET_new_array (r->ri.dps_len,
    822                         struct DecryptionPolicy);
    823   r->solved_challenges
    824     = GNUNET_new_array (r->ri.cs_len,
    825                         struct ANASTASIS_Challenge *);
    826   r->ri.cs
    827     = GNUNET_new_array (r->ri.cs_len,
    828                         struct ANASTASIS_Challenge *);
    829   r->cs
    830     = GNUNET_new_array (r->ri.cs_len,
    831                         struct ANASTASIS_Challenge);
    832   for (unsigned int i = 0; i < r->ri.cs_len; i++)
    833   {
    834     struct ANASTASIS_Challenge *cs = &r->cs[i];
    835     const char *instructions;
    836     const char *url;
    837     const char *escrow_type;
    838     struct GNUNET_JSON_Specification spec[] = {
    839       GNUNET_JSON_spec_fixed_auto ("uuid",
    840                                    &cs->ci.uuid),
    841       TALER_JSON_spec_web_url ("url",
    842                                &url),
    843       GNUNET_JSON_spec_string ("instructions",
    844                                &instructions),
    845       GNUNET_JSON_spec_fixed_auto ("truth_key",
    846                                    &cs->truth_key),
    847       GNUNET_JSON_spec_fixed_auto ("question_salt",
    848                                    &cs->question_salt),
    849       GNUNET_JSON_spec_fixed_auto ("provider_salt",
    850                                    &cs->provider_salt),
    851       GNUNET_JSON_spec_string ("escrow_type",
    852                                &escrow_type),
    853       GNUNET_JSON_spec_end ()
    854     };
    855 
    856     r->ri.cs[i] = cs;
    857     cs->recovery = r;
    858     if (GNUNET_OK !=
    859         GNUNET_JSON_parse (json_array_get (esc_methods,
    860                                            i),
    861                            spec,
    862                            NULL, NULL))
    863     {
    864       GNUNET_break_op (0);
    865       r->csc (r->csc_cls,
    866               ANASTASIS_RS_POLICY_MALFORMED_JSON,
    867               NULL,
    868               0);
    869       goto cleanup;
    870     }
    871     cs->url = GNUNET_strdup (url);
    872     cs->type = GNUNET_strdup (escrow_type);
    873     cs->ci.type = cs->type;
    874     cs->ci.provider_url = cs->url;
    875     cs->instructions = GNUNET_strdup (instructions);
    876     cs->ci.instructions = cs->instructions;
    877   }
    878 
    879   for (unsigned int j = 0; j < r->ri.dps_len; j++)
    880   {
    881     struct DecryptionPolicy *dp = &r->dps[j];
    882     const json_t *uuids;
    883     json_t *juuid;
    884     size_t n_index;
    885     struct GNUNET_JSON_Specification spec[] = {
    886       GNUNET_JSON_spec_varsize ("master_key",
    887                                 &dp->emk,
    888                                 &dp->emk_size),
    889       GNUNET_JSON_spec_fixed_auto ("master_salt",
    890                                    &dp->master_salt),
    891       GNUNET_JSON_spec_array_const ("uuids",
    892                                     &uuids),
    893       GNUNET_JSON_spec_end ()
    894     };
    895 
    896     r->ri.dps[j] = &r->dps[j].pub_details;
    897     if (GNUNET_OK !=
    898         GNUNET_JSON_parse (json_array_get (dec_policies,
    899                                            j),
    900                            spec,
    901                            NULL, NULL))
    902     {
    903       GNUNET_break_op (0);
    904       r->csc (r->csc_cls,
    905               ANASTASIS_RS_POLICY_MALFORMED_JSON,
    906               NULL,
    907               0);
    908       goto cleanup;
    909     }
    910 
    911     GNUNET_assert (NULL != dp->emk);
    912     GNUNET_assert (dp->emk_size > 0);
    913 
    914     if (json_array_size (uuids) > UINT_MAX)
    915     {
    916       GNUNET_break_op (0);
    917       r->csc (r->csc_cls,
    918               ANASTASIS_RS_POLICY_MALFORMED_JSON,
    919               NULL,
    920               0);
    921       goto cleanup;
    922     }
    923     dp->pub_details.challenges_length
    924       = (unsigned int) json_array_size (uuids);
    925     dp->pub_details.challenges
    926       = GNUNET_new_array (dp->pub_details.challenges_length,
    927                           struct ANASTASIS_Challenge *);
    928     json_array_foreach (uuids, n_index, juuid)
    929     {
    930       const char *uuid_str = json_string_value (juuid);
    931       struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
    932       bool found = false;
    933 
    934       if ( (NULL == uuid_str) ||
    935            (GNUNET_OK !=
    936             GNUNET_STRINGS_string_to_data (
    937               uuid_str,
    938               strlen (uuid_str),
    939               &uuid,
    940               sizeof (uuid))) )
    941       {
    942         GNUNET_break_op (0);
    943         r->csc (r->csc_cls,
    944                 ANASTASIS_RS_POLICY_MALFORMED_JSON,
    945                 NULL,
    946                 0);
    947         goto cleanup;
    948       }
    949       for (unsigned int i = 0; i<r->ri.cs_len; i++)
    950       {
    951         if (0 !=
    952             GNUNET_memcmp (&uuid,
    953                            &r->cs[i].ci.uuid))
    954           continue;
    955         found = true;
    956         dp->pub_details.challenges[n_index] = &r->cs[i];
    957         break;
    958       }
    959       if (! found)
    960       {
    961         GNUNET_break_op (0);
    962         r->csc (r->csc_cls,
    963                 ANASTASIS_RS_POLICY_MALFORMED_JSON,
    964                 NULL,
    965                 0);
    966         goto cleanup;
    967       }
    968     }
    969   }
    970   r->pc (r->pc_cls,
    971          &r->ri);
    972   json_decref (recovery_document);
    973   return;
    974 cleanup:
    975   ANASTASIS_recovery_abort (r);
    976   json_decref (recovery_document);
    977 }
    978 
    979 
    980 struct ANASTASIS_Recovery *
    981 ANASTASIS_recovery_begin (
    982   struct GNUNET_CURL_Context *ctx,
    983   const json_t *id_data,
    984   unsigned int version,
    985   const char *anastasis_provider_url,
    986   const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt,
    987   ANASTASIS_PolicyCallback pc,
    988   void *pc_cls,
    989   ANASTASIS_CoreSecretCallback csc,
    990   void *csc_cls)
    991 {
    992   struct ANASTASIS_Recovery *r;
    993   struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key;
    994 
    995   r = GNUNET_new (struct ANASTASIS_Recovery);
    996   r->csc = csc;
    997   r->csc_cls = csc_cls;
    998   r->pc = pc;
    999   r->pc_cls = pc_cls;
   1000   r->ctx = ctx;
   1001   r->id_data = json_incref ((json_t *) id_data);
   1002   r->provider_url = GNUNET_strdup (anastasis_provider_url);
   1003   ANASTASIS_CRYPTO_user_identifier_derive (id_data,
   1004                                            provider_salt,
   1005                                            &r->id);
   1006   ANASTASIS_CRYPTO_account_public_key_derive (&r->id,
   1007                                               &pub_key);
   1008   r->ri.version = version;
   1009   if (0 != version)
   1010   {
   1011     r->plo = ANASTASIS_policy_lookup_version (r->ctx,
   1012                                               anastasis_provider_url,
   1013                                               &pub_key,
   1014                                               &policy_lookup_cb,
   1015                                               r,
   1016                                               version);
   1017   }
   1018   else
   1019   {
   1020     r->plo = ANASTASIS_policy_lookup (r->ctx,
   1021                                       anastasis_provider_url,
   1022                                       &pub_key,
   1023                                       &policy_lookup_cb,
   1024                                       r);
   1025   }
   1026   if (NULL == r->plo)
   1027   {
   1028     GNUNET_break (0);
   1029     ANASTASIS_recovery_abort (r);
   1030     return NULL;
   1031   }
   1032   return r;
   1033 }
   1034 
   1035 
   1036 json_t *
   1037 ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r)
   1038 {
   1039   json_t *dps_arr;
   1040   json_t *cs_arr;
   1041 
   1042   dps_arr = json_array ();
   1043   GNUNET_assert (NULL != dps_arr);
   1044   for (unsigned int i = 0; i<r->ri.dps_len; i++)
   1045   {
   1046     const struct DecryptionPolicy *dp = &r->dps[i];
   1047     json_t *c_arr;
   1048     json_t *dps;
   1049 
   1050     c_arr = json_array ();
   1051     GNUNET_assert (NULL != c_arr);
   1052     for (unsigned int j = 0; j < dp->pub_details.challenges_length; j++)
   1053     {
   1054       const struct ANASTASIS_Challenge *c = dp->pub_details.challenges[j];
   1055       json_t *cs;
   1056 
   1057       cs = GNUNET_JSON_PACK (
   1058         GNUNET_JSON_pack_data_auto ("uuid",
   1059                                     &c->ci.uuid));
   1060       GNUNET_assert (0 ==
   1061                      json_array_append_new (c_arr,
   1062                                             cs));
   1063     }
   1064     GNUNET_assert (NULL != dp->emk);
   1065     dps = GNUNET_JSON_PACK (
   1066       GNUNET_JSON_pack_data_varsize ("encrypted_master_key",
   1067                                      dp->emk,
   1068                                      dp->emk_size),
   1069       GNUNET_JSON_pack_data_auto ("master_salt",
   1070                                   &dp->master_salt),
   1071       GNUNET_JSON_pack_array_steal ("challenges",
   1072                                     c_arr));
   1073     GNUNET_assert (0 ==
   1074                    json_array_append_new (dps_arr,
   1075                                           dps));
   1076   }
   1077   cs_arr = json_array ();
   1078   GNUNET_assert (NULL != cs_arr);
   1079   for (unsigned int i = 0; i<r->ri.cs_len; i++)
   1080   {
   1081     const struct ANASTASIS_Challenge *c = &r->cs[i];
   1082     json_t *cs;
   1083 
   1084     cs = GNUNET_JSON_PACK (
   1085       GNUNET_JSON_pack_data_auto ("uuid",
   1086                                   &c->ci.uuid),
   1087       GNUNET_JSON_pack_string ("uuid-display",
   1088                                ANASTASIS_CRYPTO_uuid2s (&c->ci.uuid)),
   1089       GNUNET_JSON_pack_data_auto ("truth_key",
   1090                                   &c->truth_key),
   1091       GNUNET_JSON_pack_data_auto ("question_salt",
   1092                                   &c->question_salt),
   1093       GNUNET_JSON_pack_data_auto ("provider_salt",
   1094                                   &c->provider_salt),
   1095       GNUNET_JSON_pack_allow_null (
   1096         GNUNET_JSON_pack_data_varsize ("key_share",
   1097                                        c->ci.solved
   1098                                        ? &c->key_share
   1099                                        : NULL,
   1100                                        sizeof (c->key_share))),
   1101       GNUNET_JSON_pack_string ("url",
   1102                                c->url),
   1103       GNUNET_JSON_pack_string ("type",
   1104                                c->type),
   1105       GNUNET_JSON_pack_string ("instructions",
   1106                                c->instructions),
   1107       GNUNET_JSON_pack_bool ("solved",
   1108                              c->ci.solved),
   1109       GNUNET_JSON_pack_bool ("async",
   1110                              c->ci.async));
   1111     GNUNET_assert (0 ==
   1112                    json_array_append_new (cs_arr,
   1113                                           cs));
   1114   }
   1115 
   1116   return GNUNET_JSON_PACK (
   1117     GNUNET_JSON_pack_data_auto ("id",
   1118                                 &r->id),
   1119     GNUNET_JSON_pack_array_steal ("decryption_policies",
   1120                                   dps_arr),
   1121     GNUNET_JSON_pack_array_steal ("challenges",
   1122                                   cs_arr),
   1123     GNUNET_JSON_pack_uint64 ("version",
   1124                              r->ri.version),
   1125     GNUNET_JSON_pack_object_incref ("id_data",
   1126                                     (json_t *) r->id_data),
   1127     GNUNET_JSON_pack_string ("provider_url",
   1128                              r->provider_url),
   1129     GNUNET_JSON_pack_allow_null (
   1130       GNUNET_JSON_pack_string ("secret_name",
   1131                                r->secret_name)),
   1132     GNUNET_JSON_pack_data_varsize ("encrypted_core_secret",
   1133                                    r->enc_core_secret,
   1134                                    r->enc_core_secret_size));
   1135 }
   1136 
   1137 
   1138 /**
   1139  * Parse the @a cs_array with information about
   1140  * the various challenges and their solution state
   1141  * and update @a r accordingly
   1142  *
   1143  * @param[in,out] r recovery information to update
   1144  * @param cs_arr serialized data to parse
   1145  * @return #GNUNET_OK on success
   1146  */
   1147 static enum GNUNET_GenericReturnValue
   1148 parse_cs_array (struct ANASTASIS_Recovery *r,
   1149                 const json_t *cs_arr)
   1150 {
   1151   json_t *cs;
   1152   size_t n_index;
   1153 
   1154   if (! json_is_array (cs_arr))
   1155   {
   1156     GNUNET_break_op (0);
   1157     return GNUNET_SYSERR;
   1158   }
   1159   if (json_array_size (cs_arr) > UINT_MAX)
   1160   {
   1161     GNUNET_break_op (0);
   1162     return GNUNET_SYSERR;
   1163   }
   1164   r->ri.cs_len
   1165     = (unsigned int) json_array_size (cs_arr);
   1166   r->solved_challenges
   1167     = GNUNET_new_array (r->ri.cs_len,
   1168                         struct ANASTASIS_Challenge *);
   1169   r->ri.cs = GNUNET_new_array (r->ri.cs_len,
   1170                                struct ANASTASIS_Challenge *);
   1171   r->cs = GNUNET_new_array (r->ri.cs_len,
   1172                             struct ANASTASIS_Challenge);
   1173   json_array_foreach (cs_arr, n_index, cs)
   1174   {
   1175     struct ANASTASIS_Challenge *c = &r->cs[n_index];
   1176     const char *instructions;
   1177     const char *url;
   1178     const char *escrow_type;
   1179     bool no_key_share;
   1180     struct GNUNET_JSON_Specification spec[] = {
   1181       GNUNET_JSON_spec_fixed_auto ("uuid",
   1182                                    &c->ci.uuid),
   1183       TALER_JSON_spec_web_url ("url",
   1184                                &url),
   1185       GNUNET_JSON_spec_string ("instructions",
   1186                                &instructions),
   1187       GNUNET_JSON_spec_fixed_auto ("truth_key",
   1188                                    &c->truth_key),
   1189       GNUNET_JSON_spec_fixed_auto ("question_salt",
   1190                                    &c->question_salt),
   1191       GNUNET_JSON_spec_fixed_auto ("provider_salt",
   1192                                    &c->provider_salt),
   1193       GNUNET_JSON_spec_string ("type",
   1194                                &escrow_type),
   1195       GNUNET_JSON_spec_mark_optional (
   1196         GNUNET_JSON_spec_bool ("async",
   1197                                &c->ci.async),
   1198         NULL),
   1199       GNUNET_JSON_spec_mark_optional (
   1200         GNUNET_JSON_spec_fixed_auto ("key_share",
   1201                                      &c->key_share),
   1202         &no_key_share),
   1203       GNUNET_JSON_spec_end ()
   1204     };
   1205 
   1206     r->ri.cs[n_index] = c;
   1207     c->recovery = r;
   1208     if (GNUNET_OK !=
   1209         GNUNET_JSON_parse (cs,
   1210                            spec,
   1211                            NULL, NULL))
   1212     {
   1213       GNUNET_break_op (0);
   1214       return GNUNET_SYSERR;
   1215     }
   1216     c->url = GNUNET_strdup (url);
   1217     c->type = GNUNET_strdup (escrow_type);
   1218     c->ci.type = c->type;
   1219     c->instructions = GNUNET_strdup (instructions);
   1220     c->ci.instructions = c->instructions;
   1221     c->ci.provider_url = c->url;
   1222     if (! no_key_share)
   1223     {
   1224       c->ci.solved = true;
   1225       r->solved_challenges[r->solved_challenge_pos++] = c;
   1226     }
   1227   }
   1228   return GNUNET_OK;
   1229 }
   1230 
   1231 
   1232 /**
   1233  * Parse the @a dps_array with our decryption policies
   1234  * and update @a r accordingly
   1235  *
   1236  * @param[in,out] r recovery information to update
   1237  * @param dps_arr serialized data to parse
   1238  * @return #GNUNET_OK on success
   1239  */
   1240 static enum GNUNET_GenericReturnValue
   1241 parse_dps_array (struct ANASTASIS_Recovery *r,
   1242                  const json_t *dps_arr)
   1243 {
   1244   json_t *dps;
   1245   size_t n_index;
   1246 
   1247   if (! json_is_array (dps_arr))
   1248   {
   1249     GNUNET_break_op (0);
   1250     return GNUNET_SYSERR;
   1251   }
   1252   if (json_array_size (dps_arr) > UINT_MAX)
   1253   {
   1254     GNUNET_break_op (0);
   1255     return GNUNET_SYSERR;
   1256   }
   1257   r->ri.dps_len
   1258     = (unsigned int) json_array_size (dps_arr);
   1259   r->dps = GNUNET_new_array (r->ri.dps_len,
   1260                              struct DecryptionPolicy);
   1261   r->ri.dps = GNUNET_new_array (r->ri.dps_len,
   1262                                 struct ANASTASIS_DecryptionPolicy *);
   1263 
   1264   json_array_foreach (dps_arr, n_index, dps)
   1265   {
   1266     struct DecryptionPolicy *dp = &r->dps[n_index];
   1267     const json_t *challenges;
   1268     struct GNUNET_JSON_Specification spec[] = {
   1269       GNUNET_JSON_spec_varsize ("encrypted_master_key",
   1270                                 &dp->emk,
   1271                                 &dp->emk_size),
   1272       GNUNET_JSON_spec_fixed_auto ("master_salt",
   1273                                    &dp->master_salt),
   1274       GNUNET_JSON_spec_array_const ("challenges",
   1275                                     &challenges),
   1276       GNUNET_JSON_spec_end ()
   1277     };
   1278     const char *err_json_name;
   1279     unsigned int err_line;
   1280 
   1281     r->ri.dps[n_index] = &dp->pub_details;
   1282     if (GNUNET_OK !=
   1283         GNUNET_JSON_parse (dps,
   1284                            spec,
   1285                            &err_json_name,
   1286                            &err_line))
   1287     {
   1288       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1289                   "Failed to parse decryption policy JSON entry `%s'\n",
   1290                   err_json_name);
   1291       json_dumpf (dps,
   1292                   stderr,
   1293                   JSON_INDENT (2));
   1294       return GNUNET_SYSERR;
   1295     }
   1296     GNUNET_assert (NULL != dp->emk);
   1297     GNUNET_assert (dp->emk_size > 0);
   1298     if (json_array_size (challenges) > UINT_MAX)
   1299     {
   1300       GNUNET_break_op (0);
   1301       return GNUNET_SYSERR;
   1302     }
   1303     dp->pub_details.challenges_length
   1304       = (unsigned int) json_array_size (challenges);
   1305     dp->pub_details.challenges
   1306       = GNUNET_new_array (dp->pub_details.challenges_length,
   1307                           struct ANASTASIS_Challenge *);
   1308 
   1309     {
   1310       json_t *challenge;
   1311       size_t c_index;
   1312       json_array_foreach (challenges, c_index, challenge)
   1313       {
   1314         struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
   1315         struct GNUNET_JSON_Specification ispec[] = {
   1316           GNUNET_JSON_spec_fixed_auto ("uuid",
   1317                                        &uuid),
   1318           GNUNET_JSON_spec_end ()
   1319         };
   1320         bool found = false;
   1321 
   1322         if (GNUNET_OK !=
   1323             GNUNET_JSON_parse (challenge,
   1324                                ispec,
   1325                                NULL, NULL))
   1326         {
   1327           GNUNET_break_op (0);
   1328           GNUNET_JSON_parse_free (spec);
   1329           return GNUNET_SYSERR;
   1330         }
   1331         for (unsigned int i = 0; i<r->ri.cs_len; i++)
   1332         {
   1333           if (0 !=
   1334               GNUNET_memcmp (&uuid,
   1335                              &r->cs[i].ci.uuid))
   1336             continue;
   1337           dp->pub_details.challenges[c_index] = &r->cs[i];
   1338           found = true;
   1339         }
   1340         if (! found)
   1341         {
   1342           GNUNET_break_op (0);
   1343           GNUNET_JSON_parse_free (spec);
   1344           return GNUNET_SYSERR;
   1345         }
   1346       }
   1347     }
   1348     /* Do NOT free the spec: we are still using dp->ems. */
   1349   }
   1350   return GNUNET_OK;
   1351 }
   1352 
   1353 
   1354 /**
   1355  * Asynchronously call "pc" on the recovery information.
   1356  *
   1357  * @param cls a `struct ANASTASIS_Recovery *`
   1358  */
   1359 static void
   1360 run_async_pc (void *cls)
   1361 {
   1362   struct ANASTASIS_Recovery *r = cls;
   1363 
   1364   r->do_async = NULL;
   1365   r->pc (r->pc_cls,
   1366          &r->ri);
   1367 }
   1368 
   1369 
   1370 struct ANASTASIS_Recovery *
   1371 ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx,
   1372                                 const json_t *input,
   1373                                 ANASTASIS_PolicyCallback pc,
   1374                                 void *pc_cls,
   1375                                 ANASTASIS_CoreSecretCallback csc,
   1376                                 void *csc_cls)
   1377 {
   1378   struct ANASTASIS_Recovery *r;
   1379 
   1380   r = GNUNET_new (struct ANASTASIS_Recovery);
   1381   r->csc = csc;
   1382   r->csc_cls = csc_cls;
   1383   r->pc = pc;
   1384   r->pc_cls = pc_cls;
   1385   r->ctx = ctx;
   1386   {
   1387     const char *err_json_name;
   1388     unsigned int err_line;
   1389     uint32_t version;
   1390     const json_t *dps_arr;
   1391     const json_t *cs_arr;
   1392     const json_t *id_data;
   1393     const char *provider_url;
   1394     const char *secret_name;
   1395     void *ecs;
   1396     size_t ecs_size;
   1397     struct GNUNET_JSON_Specification spec[] = {
   1398       GNUNET_JSON_spec_fixed_auto ("id",
   1399                                    &r->id),
   1400       TALER_JSON_spec_web_url ("provider_url",
   1401                                &provider_url),
   1402       GNUNET_JSON_spec_mark_optional (
   1403         GNUNET_JSON_spec_string ("secret_name",
   1404                                  &secret_name),
   1405         NULL),
   1406       GNUNET_JSON_spec_uint32 ("version",
   1407                                &version),
   1408       GNUNET_JSON_spec_array_const ("decryption_policies",
   1409                                     &dps_arr),
   1410       GNUNET_JSON_spec_array_const ("challenges",
   1411                                     &cs_arr),
   1412       GNUNET_JSON_spec_object_const ("id_data",
   1413                                      &id_data),
   1414       GNUNET_JSON_spec_varsize ("encrypted_core_secret",
   1415                                 &ecs,
   1416                                 &ecs_size),
   1417       GNUNET_JSON_spec_end ()
   1418     };
   1419 
   1420     if (GNUNET_OK !=
   1421         GNUNET_JSON_parse (input,
   1422                            spec,
   1423                            &err_json_name,
   1424                            &err_line))
   1425     {
   1426       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1427                   "Failed to parse recovery document JSON entry `%s'\n",
   1428                   err_json_name);
   1429       json_dumpf (input,
   1430                   stderr,
   1431                   JSON_INDENT (2));
   1432       return NULL;
   1433     }
   1434     r->ri.version = version;
   1435     if ( (GNUNET_OK !=
   1436           parse_cs_array (r,
   1437                           cs_arr)) ||
   1438          (GNUNET_OK !=
   1439           parse_dps_array (r,
   1440                            dps_arr)) )
   1441     {
   1442       GNUNET_break_op (0);
   1443       ANASTASIS_recovery_abort (r);
   1444       GNUNET_JSON_parse_free (spec);
   1445       return NULL;
   1446     }
   1447     r->id_data = json_incref ((json_t *) id_data);
   1448     r->provider_url = GNUNET_strdup (provider_url);
   1449     if (NULL != secret_name)
   1450       r->secret_name = GNUNET_strdup (secret_name);
   1451     r->ri.secret_name = r->secret_name;
   1452     if (0 != ecs_size)
   1453     {
   1454       r->enc_core_secret = GNUNET_memdup (ecs,
   1455                                           ecs_size);
   1456       r->enc_core_secret_size = ecs_size;
   1457     }
   1458     GNUNET_JSON_parse_free (spec);
   1459   }
   1460   if (0 == r->ri.dps_len)
   1461   {
   1462     struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key;
   1463 
   1464     ANASTASIS_CRYPTO_account_public_key_derive (&r->id,
   1465                                                 &pub_key);
   1466     if (0 != r->ri.version)
   1467     {
   1468       r->plo = ANASTASIS_policy_lookup_version (r->ctx,
   1469                                                 r->provider_url,
   1470                                                 &pub_key,
   1471                                                 &policy_lookup_cb,
   1472                                                 r,
   1473                                                 r->ri.version);
   1474     }
   1475     else
   1476     {
   1477       r->plo = ANASTASIS_policy_lookup (r->ctx,
   1478                                         r->provider_url,
   1479                                         &pub_key,
   1480                                         &policy_lookup_cb,
   1481                                         r);
   1482     }
   1483     if (NULL == r->plo)
   1484     {
   1485       GNUNET_break (0);
   1486       ANASTASIS_recovery_abort (r);
   1487       return NULL;
   1488     }
   1489   }
   1490   else
   1491   {
   1492     r->do_async = GNUNET_SCHEDULER_add_now (&run_async_pc,
   1493                                             r);
   1494   }
   1495   return r;
   1496 }
   1497 
   1498 
   1499 void
   1500 ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r)
   1501 {
   1502   if (NULL != r->do_async)
   1503   {
   1504     GNUNET_SCHEDULER_cancel (r->do_async);
   1505     r->do_async = NULL;
   1506   }
   1507   if (NULL != r->plo)
   1508   {
   1509     ANASTASIS_policy_lookup_cancel (r->plo);
   1510     r->plo = NULL;
   1511   }
   1512   GNUNET_free (r->solved_challenges);
   1513   for (unsigned int j = 0; j < r->ri.dps_len; j++)
   1514   {
   1515     GNUNET_free (r->dps[j].pub_details.challenges);
   1516     GNUNET_free (r->dps[j].emk);
   1517   }
   1518   GNUNET_free (r->ri.dps);
   1519   for (unsigned int i = 0; i < r->ri.cs_len; i++)
   1520   {
   1521     struct ANASTASIS_Challenge *cs = &r->cs[i];
   1522 
   1523     if (NULL != cs->tso)
   1524     {
   1525       ANASTASIS_truth_solve_cancel (cs->tso);
   1526       cs->tso = NULL;
   1527     }
   1528     GNUNET_free (cs->url);
   1529     GNUNET_free (cs->type);
   1530     GNUNET_free (cs->instructions);
   1531     GNUNET_free (cs->answer);
   1532   }
   1533   GNUNET_free (r->ri.cs);
   1534   GNUNET_free (r->cs);
   1535   GNUNET_free (r->dps);
   1536   json_decref (r->id_data);
   1537   GNUNET_free (r->provider_url);
   1538   GNUNET_free (r->secret_name);
   1539   GNUNET_free (r->enc_core_secret);
   1540   GNUNET_free (r);
   1541 }