diff options
Diffstat (limited to 'src/lib/anastasis_recovery.c')
-rw-r--r-- | src/lib/anastasis_recovery.c | 618 |
1 files changed, 331 insertions, 287 deletions
diff --git a/src/lib/anastasis_recovery.c b/src/lib/anastasis_recovery.c index ac10418..f164c93 100644 --- a/src/lib/anastasis_recovery.c +++ b/src/lib/anastasis_recovery.c @@ -3,14 +3,14 @@ Copyright (C) 2020, 2021 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Affero General Public License along with + You should have received a copy of the GNU General Public License along with Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> */ /** @@ -47,7 +47,7 @@ struct ANASTASIS_Challenge /** * Salt; used to derive hash from security question answers. */ - struct ANASTASIS_CRYPTO_QuestionSaltP salt; + struct ANASTASIS_CRYPTO_QuestionSaltP question_salt; /** * Provider salt; used to derive our key material from our identity @@ -63,16 +63,27 @@ struct ANASTASIS_Challenge /** * Callback which gives back the instructions and a status code of - * the request to the user when answering a challenge was initiated. + * the request to the user when answering a challenge. */ ANASTASIS_AnswerFeedback af; /** - * Closure for the challenge callback + * Closure for @e af. */ void *af_cls; /** + * Callback which gives back the instructions and a status code of + * the request to the user when initiating a challenge. + */ + ANASTASIS_ChallengeStartFeedback csf; + + /** + * Closure for @e csf. + */ + void *csf_cls; + + /** * Defines the base URL of the Anastasis provider used for the challenge. */ char *url; @@ -99,9 +110,14 @@ struct ANASTASIS_Challenge struct ANASTASIS_Recovery *recovery; /** - * keyshare lookup operation + * Handle for the /truth/$TID/challenge request. + */ + struct ANASTASIS_TruthChallengeOperation *tco; + + /** + * Handle for the /truth/$TID/solve request. */ - struct ANASTASIS_KeyShareLookupOperation *kslo; + struct ANASTASIS_TruthSolveOperation *tso; }; @@ -118,14 +134,19 @@ struct DecryptionPolicy struct ANASTASIS_DecryptionPolicy pub_details; /** - * Encrypted masterkey (encrypted with the policy key). + * Encrypted master key (encrypted with the policy key). */ - struct ANASTASIS_CRYPTO_EncryptedMasterKeyP emk; + void *emk; + + /** + * Size of the encrypted master key. + */ + size_t emk_size; /** * Salt used to decrypt master key. */ - struct ANASTASIS_CRYPTO_MasterSaltP salt; + struct ANASTASIS_CRYPTO_MasterSaltP master_salt; }; @@ -233,161 +254,140 @@ struct ANASTASIS_Recovery /** - * Function called with the results of a #ANASTASIS_keyshare_lookup(). + * Function called with the results of a #ANASTASIS_challenge_start(). * * @param cls closure * @param dd details about the lookup operation */ static void -keyshare_lookup_cb (void *cls, - const struct ANASTASIS_KeyShareDownloadDetails *dd) +truth_challenge_cb (void *cls, + const struct ANASTASIS_TruthChallengeDetails *tcd) { struct ANASTASIS_Challenge *c = cls; - struct ANASTASIS_Recovery *recovery = c->recovery; - struct ANASTASIS_CRYPTO_UserIdentifierP id; - struct DecryptionPolicy *rdps; - - c->kslo = NULL; - switch (dd->status) + struct ANASTASIS_ChallengeStartResponse csr = { + .challenge = c, + .ec = tcd->ec, + .http_status = tcd->http_status + }; + + c->tco = NULL; + switch (tcd->http_status) { - case ANASTASIS_KSD_SUCCESS: - break; - case ANASTASIS_KSD_PAYMENT_REQUIRED: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED, - .challenge = c, - .details.payment_required.taler_pay_uri - = dd->details.payment_required.taler_pay_uri, - .details.payment_required.payment_secret - = dd->details.payment_required.payment_secret - }; - - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_INVALID_ANSWER: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS, - .challenge = c, - .details.open_challenge.body - = dd->details.open_challenge.body, - .details.open_challenge.content_type - = dd->details.open_challenge.content_type, - .details.open_challenge.body_size - = dd->details.open_challenge.body_size, - .details.open_challenge.http_status - = dd->details.open_challenge.http_status - }; - - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_REDIRECT_FOR_AUTHENTICATION, - .challenge = c, - .details.redirect_url - = dd->details.redirect_url - }; - - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_TRUTH_UNKNOWN: + case MHD_HTTP_OK: + switch (tcd->details.success.cs) { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_TRUTH_UNKNOWN, - .challenge = c - }; - - c->af (c->af_cls, - &csr); - return; + case ANASTASIS_CS_FILE_WRITTEN: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED; + csr.details.tan_filename + = tcd->details.success.details.challenge_filename; + break; + case ANASTASIS_CS_TAN_SENT: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED; + csr.details.tan_address_hint + = tcd->details.success.details.tan_address_hint; + break; + case ANASTASIS_CS_TAN_ALREADY_SENT: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT; + break; + case ANASTASIS_CS_WIRE_FUNDS: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED; + csr.details.bank_transfer_required + = tcd->details.success.details.wire_funds; + break; } - case ANASTASIS_KSD_RATE_LIMIT_EXCEEDED: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_RATE_LIMIT_EXCEEDED, - .challenge = c - }; + break; + case MHD_HTTP_PAYMENT_REQUIRED: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED; + csr.details.payment_required.taler_pay_uri + = tcd->details.payment_required.payment_request; + csr.details.payment_required.payment_secret + = tcd->details.payment_required.ps; + break; + case MHD_HTTP_NOT_FOUND: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN; + break; + default: + csr.cs = ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE; + break; + } + c->csf (c->csf_cls, + &csr); +} - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_SERVER_ERROR: - case ANASTASIS_KSD_CLIENT_FAILURE: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE, - .challenge = c, - .details.server_failure.ec - = dd->details.server_failure.ec, - .details.server_failure.http_status - = dd->details.server_failure.http_status - }; - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_AUTHENTICATION_TIMEOUT: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_AUTH_TIMEOUT, - .challenge = c, - .details.server_failure.ec - = dd->details.server_failure.ec, - .details.server_failure.http_status - = dd->details.server_failure.http_status - }; +/** + * Function called with the results of a #ANASTASIS_truth_solve(). + * + * @param cls closure + * @param tsr details about the solution response + */ +static void +truth_solve_cb (void *cls, + const struct ANASTASIS_TruthSolveReply *tsr) +{ + struct ANASTASIS_Challenge *c = cls; + struct ANASTASIS_Recovery *recovery = c->recovery; + struct ANASTASIS_CRYPTO_UserIdentifierP id; + struct DecryptionPolicy *rdps; + struct ANASTASIS_ChallengeAnswerResponse csr = { + .challenge = c, + .ec = tsr->ec, + .http_status = tsr->http_status + }; - c->ci.async = true; - c->af (c->af_cls, - &csr); - return; - } - case ANASTASIS_KSD_EXTERNAL_CHALLENGE_INSTRUCTIONS: - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_EXTERNAL_INSTRUCTIONS, - .challenge = c, - .details.external_challenge = dd->details.external_challenge - }; - c->af (c->af_cls, - &csr); - return; - } + c->tso = NULL; + switch (tsr->http_status) + { + case MHD_HTTP_OK: + break; + case MHD_HTTP_PAYMENT_REQUIRED: + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_PAYMENT_REQUIRED; + csr.details.payment_required.taler_pay_uri + = tsr->details.payment_required.payment_request; + csr.details.payment_required.payment_secret + = tsr->details.payment_required.ps; + c->af (c->af_cls, + &csr); + return; + case MHD_HTTP_FORBIDDEN: + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_INVALID_ANSWER; + c->af (c->af_cls, + &csr); + return; + case MHD_HTTP_NOT_FOUND: + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_TRUTH_UNKNOWN; + c->af (c->af_cls, + &csr); + return; + case MHD_HTTP_TOO_MANY_REQUESTS: + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_RATE_LIMIT_EXCEEDED; + csr.details.rate_limit_exceeded.request_limit + = tsr->details.too_many_requests.request_limit; + csr.details.rate_limit_exceeded.request_frequency + = tsr->details.too_many_requests.request_frequency; + c->af (c->af_cls, + &csr); + return; + default: + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE; + c->af (c->af_cls, + &csr); + return; } - GNUNET_assert (NULL != dd); ANASTASIS_CRYPTO_user_identifier_derive (recovery->id_data, &c->provider_salt, &id); - ANASTASIS_CRYPTO_keyshare_decrypt (&dd->details.eks, + ANASTASIS_CRYPTO_keyshare_decrypt (&tsr->details.success.eks, &id, c->answer, &c->key_share); recovery->solved_challenges[recovery->solved_challenge_pos++] = c; - - { - struct ANASTASIS_ChallengeStartResponse csr = { - .cs = ANASTASIS_CHALLENGE_STATUS_SOLVED, - .challenge = c - }; - - c->ci.solved = true; - c->af (c->af_cls, - &csr); - } - + c->ci.solved = true; + csr.cs = ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED; + c->af (c->af_cls, + &csr); /* Check if there is a policy for which all challenges have been satisfied, if so, store it in 'rdps'. */ @@ -437,9 +437,12 @@ keyshare_lookup_cb (void *cls, key_shares[l] = recovery->solved_challenges[m]->key_share; ANASTASIS_CRYPTO_policy_key_derive (key_shares, rdps->pub_details.challenges_length, - &rdps->salt, + &rdps->master_salt, &policy_key); - ANASTASIS_CRYPTO_core_secret_recover (&rdps->emk, + GNUNET_assert (NULL != rdps->emk); + GNUNET_assert (rdps->emk_size > 0); + ANASTASIS_CRYPTO_core_secret_recover (rdps->emk, + rdps->emk_size, &policy_key, recovery->enc_core_secret, recovery->enc_core_secret_size, @@ -462,36 +465,70 @@ ANASTASIS_challenge_get_details (struct ANASTASIS_Challenge *challenge) } -int +enum GNUNET_GenericReturnValue ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c, const struct ANASTASIS_PaymentSecretP *psp, - struct GNUNET_TIME_Relative timeout, - const struct GNUNET_HashCode *hashed_answer, - ANASTASIS_AnswerFeedback af, - void *af_cls) + ANASTASIS_ChallengeStartFeedback csf, + void *csf_cls) { if (c->ci.solved) { GNUNET_break (0); return GNUNET_NO; /* already solved */ } - if (NULL != c->kslo) + if (NULL != c->tco) + { + GNUNET_break (0); + return GNUNET_NO; /* already solving */ + } + c->csf = csf; + c->csf_cls = csf_cls; + c->tco = ANASTASIS_truth_challenge (c->recovery->ctx, + c->url, + &c->ci.uuid, + &c->truth_key, + psp, + &truth_challenge_cb, + c); + if (NULL == c->tco) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +ANASTASIS_challenge_answer3 (struct ANASTASIS_Challenge *c, + const struct ANASTASIS_PaymentSecretP *psp, + struct GNUNET_TIME_Relative timeout, + const struct GNUNET_HashCode *hashed_answer, + ANASTASIS_AnswerFeedback af, + void *af_cls) +{ + if (c->ci.solved) + { + GNUNET_break (0); + return GNUNET_NO; /* already solved */ + } + if (NULL != c->tso) { GNUNET_break (0); return GNUNET_NO; /* already solving */ } c->af = af; c->af_cls = af_cls; - c->kslo = ANASTASIS_keyshare_lookup (c->recovery->ctx, - c->url, - &c->ci.uuid, - &c->truth_key, - psp, - timeout, - hashed_answer, - &keyshare_lookup_cb, - c); - if (NULL == c->kslo) + c->tso = ANASTASIS_truth_solve (c->recovery->ctx, + c->url, + &c->ci.uuid, + &c->truth_key, + psp, + timeout, + hashed_answer, + &truth_solve_cb, + c); + if (NULL == c->tso) { GNUNET_break (0); return GNUNET_SYSERR; @@ -500,7 +537,7 @@ ANASTASIS_challenge_start (struct ANASTASIS_Challenge *c, } -int +enum GNUNET_GenericReturnValue ANASTASIS_challenge_answer ( struct ANASTASIS_Challenge *c, const struct ANASTASIS_PaymentSecretP *psp, @@ -512,21 +549,24 @@ ANASTASIS_challenge_answer ( struct GNUNET_HashCode hashed_answer; GNUNET_free (c->answer); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Answer to challenge is `%s'\n", + answer_str); c->answer = GNUNET_strdup (answer_str); ANASTASIS_CRYPTO_secure_answer_hash (answer_str, &c->ci.uuid, - &c->salt, + &c->question_salt, &hashed_answer); - return ANASTASIS_challenge_start (c, - psp, - timeout, - &hashed_answer, - af, - af_cls); + return ANASTASIS_challenge_answer3 (c, + psp, + timeout, + &hashed_answer, + af, + af_cls); } -int +enum GNUNET_GenericReturnValue ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c, const struct ANASTASIS_PaymentSecretP *psp, struct GNUNET_TIME_Relative timeout, @@ -536,27 +576,33 @@ ANASTASIS_challenge_answer2 (struct ANASTASIS_Challenge *c, { struct GNUNET_HashCode answer_s; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Answer to challenge is %llu\n", + (unsigned long long) answer); ANASTASIS_hash_answer (answer, &answer_s); - return ANASTASIS_challenge_start (c, - psp, - timeout, - &answer_s, - af, - af_cls); + return ANASTASIS_challenge_answer3 (c, + psp, + timeout, + &answer_s, + af, + af_cls); } void ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c) { - if (NULL == c->kslo) + if (NULL != c->tso) { - GNUNET_break (0); - return; + ANASTASIS_truth_solve_cancel (c->tso); + c->tso = NULL; + } + if (NULL != c->tco) + { + ANASTASIS_truth_challenge_cancel (c->tco); + c->tco = NULL; } - ANASTASIS_keyshare_lookup_cancel (c->kslo); - c->kslo = NULL; c->af = NULL; c->af_cls = NULL; } @@ -566,23 +612,22 @@ ANASTASIS_challenge_abort (struct ANASTASIS_Challenge *c) * Function called with the results of a #ANASTASIS_policy_lookup() * * @param cls closure - * @param http_status HTTp status code. * @param dd details about the lookup operation */ static void policy_lookup_cb (void *cls, - unsigned int http_status, const struct ANASTASIS_DownloadDetails *dd) { struct ANASTASIS_Recovery *r = cls; void *plaintext; size_t size_plaintext; json_error_t json_error; - json_t *dec_policies; - json_t *esc_methods; + const json_t *dec_policies; + const json_t *esc_methods; + json_t *recovery_document; r->plo = NULL; - switch (http_status) + switch (dd->http_status) { case MHD_HTTP_OK: break; @@ -614,7 +659,7 @@ policy_lookup_cb (void *cls, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u in %s:%u\n", - http_status, + dd->http_status, __FILE__, __LINE__); r->csc (r->csc_cls, @@ -624,7 +669,7 @@ policy_lookup_cb (void *cls, ANASTASIS_recovery_abort (r); return; } - if (NULL == dd->policy) + if (NULL == dd->details.ok.policy) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No recovery data available"); @@ -636,8 +681,8 @@ policy_lookup_cb (void *cls, return; } ANASTASIS_CRYPTO_recovery_document_decrypt (&r->id, - dd->policy, - dd->policy_size, + dd->details.ok.policy, + dd->details.ok.policy_size, &plaintext, &size_plaintext); if (size_plaintext < sizeof (uint32_t)) @@ -652,7 +697,6 @@ policy_lookup_cb (void *cls, return; } { - json_t *recovery_document; uint32_t be_size; uLongf pt_size; char *pt; @@ -715,13 +759,14 @@ policy_lookup_cb (void *cls, { const char *secret_name = NULL; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_json ("policies", - &dec_policies), - GNUNET_JSON_spec_json ("escrow_methods", - &esc_methods), + GNUNET_JSON_spec_array_const ("policies", + &dec_policies), + GNUNET_JSON_spec_array_const ("escrow_methods", + &esc_methods), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("secret_name", - &secret_name)), + &secret_name), + NULL), GNUNET_JSON_spec_varsize ("encrypted_core_secret", &r->enc_core_secret, &r->enc_core_secret_size), @@ -752,10 +797,9 @@ policy_lookup_cb (void *cls, r->ri.secret_name = r->secret_name; } } - json_decref (recovery_document); } - r->ri.version = dd->version; + r->ri.version = dd->details.ok.version; r->ri.cs_len = json_array_size (esc_methods); r->ri.dps_len = json_array_size (dec_policies); r->ri.dps = GNUNET_new_array (r->ri.dps_len, @@ -777,14 +821,14 @@ policy_lookup_cb (void *cls, struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("uuid", &cs->ci.uuid), - GNUNET_JSON_spec_string ("url", + TALER_JSON_spec_web_url ("url", &url), GNUNET_JSON_spec_string ("instructions", &instructions), GNUNET_JSON_spec_fixed_auto ("truth_key", &cs->truth_key), - GNUNET_JSON_spec_fixed_auto ("salt", - &cs->salt), + GNUNET_JSON_spec_fixed_auto ("question_salt", + &cs->question_salt), GNUNET_JSON_spec_fixed_auto ("provider_salt", &cs->provider_salt), GNUNET_JSON_spec_string ("escrow_type", @@ -801,13 +845,12 @@ policy_lookup_cb (void *cls, NULL, NULL)) { GNUNET_break_op (0); - json_decref (esc_methods); - json_decref (dec_policies); r->csc (r->csc_cls, ANASTASIS_RS_POLICY_MALFORMED_JSON, NULL, 0); ANASTASIS_recovery_abort (r); + json_decref (recovery_document); return; } cs->url = GNUNET_strdup (url); @@ -817,43 +860,44 @@ policy_lookup_cb (void *cls, cs->instructions = GNUNET_strdup (instructions); cs->ci.instructions = cs->instructions; } - json_decref (esc_methods); for (unsigned int j = 0; j < r->ri.dps_len; j++) { struct DecryptionPolicy *dp = &r->dps[j]; - json_t *uuids = NULL; + const json_t *uuids; json_t *uuid; size_t n_index; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("master_key", - &dp->emk), - GNUNET_JSON_spec_fixed_auto ("salt", - &dp->salt), - GNUNET_JSON_spec_json ("uuids", - &uuids), + GNUNET_JSON_spec_varsize ("master_key", + &dp->emk, + &dp->emk_size), + GNUNET_JSON_spec_fixed_auto ("master_salt", + &dp->master_salt), + GNUNET_JSON_spec_array_const ("uuids", + &uuids), GNUNET_JSON_spec_end () }; r->ri.dps[j] = &r->dps[j].pub_details; - if ( (GNUNET_OK != - GNUNET_JSON_parse (json_array_get (dec_policies, - j), - spec, - NULL, NULL)) || - (! json_is_array (uuids)) ) + if (GNUNET_OK != + GNUNET_JSON_parse (json_array_get (dec_policies, + j), + spec, + NULL, NULL)) { GNUNET_break_op (0); - json_decref (uuids); - json_decref (dec_policies); r->csc (r->csc_cls, ANASTASIS_RS_POLICY_MALFORMED_JSON, NULL, 0); ANASTASIS_recovery_abort (r); + json_decref (recovery_document); return; } + GNUNET_assert (NULL != dp->emk); + GNUNET_assert (dp->emk_size > 0); + dp->pub_details.challenges_length = json_array_size (uuids); dp->pub_details.challenges = GNUNET_new_array (dp->pub_details.challenges_length, @@ -873,13 +917,12 @@ policy_lookup_cb (void *cls, sizeof (uuid))) ) { GNUNET_break_op (0); - json_decref (dec_policies); - json_decref (uuids); r->csc (r->csc_cls, ANASTASIS_RS_POLICY_MALFORMED_JSON, NULL, 0); ANASTASIS_recovery_abort (r); + json_decref (recovery_document); return; } for (unsigned int i = 0; i<r->ri.cs_len; i++) @@ -895,21 +938,19 @@ policy_lookup_cb (void *cls, if (! found) { GNUNET_break_op (0); - json_decref (dec_policies); - json_decref (uuids); r->csc (r->csc_cls, ANASTASIS_RS_POLICY_MALFORMED_JSON, NULL, 0); ANASTASIS_recovery_abort (r); + json_decref (recovery_document); return; } } - json_decref (uuids); } - json_decref (dec_policies); r->pc (r->pc_cls, &r->ri); + json_decref (recovery_document); } @@ -997,11 +1038,13 @@ ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) json_array_append_new (c_arr, cs)); } + GNUNET_assert (NULL != dp->emk); dps = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("emk", - &dp->emk), - GNUNET_JSON_pack_data_auto ("salt", - &dp->salt), + GNUNET_JSON_pack_data_varsize ("encrypted_master_key", + dp->emk, + dp->emk_size), + GNUNET_JSON_pack_data_auto ("master_salt", + &dp->master_salt), GNUNET_JSON_pack_array_steal ("challenges", c_arr)); GNUNET_assert (0 == @@ -1018,10 +1061,12 @@ ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) cs = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("uuid", &c->ci.uuid), + GNUNET_JSON_pack_string ("uuid-display", + ANASTASIS_CRYPTO_uuid2s (&c->ci.uuid)), GNUNET_JSON_pack_data_auto ("truth_key", &c->truth_key), - GNUNET_JSON_pack_data_auto ("salt", - &c->salt), + GNUNET_JSON_pack_data_auto ("question_salt", + &c->question_salt), GNUNET_JSON_pack_data_auto ("provider_salt", &c->provider_salt), GNUNET_JSON_pack_allow_null ( @@ -1048,9 +1093,9 @@ ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) return GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("id", &r->id), - GNUNET_JSON_pack_array_steal ("dps", + GNUNET_JSON_pack_array_steal ("decryption_policies", dps_arr), - GNUNET_JSON_pack_array_steal ("cs", + GNUNET_JSON_pack_array_steal ("challenges", cs_arr), GNUNET_JSON_pack_uint64 ("version", r->ri.version), @@ -1061,22 +1106,24 @@ ANASTASIS_recovery_serialize (const struct ANASTASIS_Recovery *r) GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("secret_name", r->secret_name)), - GNUNET_JSON_pack_data_varsize ("core_secret", + GNUNET_JSON_pack_data_varsize ("encrypted_core_secret", r->enc_core_secret, r->enc_core_secret_size)); } /** - * Parse the @a cs_array and update @a r accordingly + * Parse the @a cs_array with information about + * the various challenges and their solution state + * and update @a r accordingly * * @param[in,out] r recovery information to update * @param cs_arr serialized data to parse * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue parse_cs_array (struct ANASTASIS_Recovery *r, - json_t *cs_arr) + const json_t *cs_arr) { json_t *cs; unsigned int n_index; @@ -1099,27 +1146,30 @@ parse_cs_array (struct ANASTASIS_Recovery *r, const char *instructions; const char *url; const char *escrow_type; + bool no_key_share; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("uuid", &c->ci.uuid), - GNUNET_JSON_spec_string ("url", + TALER_JSON_spec_web_url ("url", &url), GNUNET_JSON_spec_string ("instructions", &instructions), GNUNET_JSON_spec_fixed_auto ("truth_key", &c->truth_key), - GNUNET_JSON_spec_fixed_auto ("salt", - &c->salt), + GNUNET_JSON_spec_fixed_auto ("question_salt", + &c->question_salt), GNUNET_JSON_spec_fixed_auto ("provider_salt", &c->provider_salt), GNUNET_JSON_spec_string ("type", &escrow_type), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_bool ("async", - &c->ci.async)), + &c->ci.async), + NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_fixed_auto ("key_share", - &c->key_share)), + &c->key_share), + &no_key_share), GNUNET_JSON_spec_end () }; @@ -1139,34 +1189,27 @@ parse_cs_array (struct ANASTASIS_Recovery *r, c->instructions = GNUNET_strdup (instructions); c->ci.instructions = c->instructions; c->ci.provider_url = c->url; + if (! no_key_share) { - json_t *ks; - - ks = json_object_get (cs, - "key_share"); - if ( (NULL != ks) && - (! json_is_null (ks)) ) - { - c->ci.solved = true; - r->solved_challenges[r->solved_challenge_pos++] = c; - } + c->ci.solved = true; + r->solved_challenges[r->solved_challenge_pos++] = c; } } - return GNUNET_OK; } /** - * Parse the @a dps_array and update @a r accordingly + * Parse the @a dps_array with our decryption policies + * and update @a r accordingly * * @param[in,out] r recovery information to update * @param dps_arr serialized data to parse * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue parse_dps_array (struct ANASTASIS_Recovery *r, - json_t *dps_arr) + const json_t *dps_arr) { json_t *dps; unsigned int n_index; @@ -1185,14 +1228,15 @@ parse_dps_array (struct ANASTASIS_Recovery *r, json_array_foreach (dps_arr, n_index, dps) { struct DecryptionPolicy *dp = &r->dps[n_index]; - json_t *challenges; + const json_t *challenges; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("emk", - &dp->emk), - GNUNET_JSON_spec_fixed_auto ("salt", - &dp->salt), - GNUNET_JSON_spec_json ("challenges", - &challenges), + GNUNET_JSON_spec_varsize ("encrypted_master_key", + &dp->emk, + &dp->emk_size), + GNUNET_JSON_spec_fixed_auto ("master_salt", + &dp->master_salt), + GNUNET_JSON_spec_array_const ("challenges", + &challenges), GNUNET_JSON_spec_end () }; const char *err_json_name; @@ -1213,12 +1257,8 @@ parse_dps_array (struct ANASTASIS_Recovery *r, JSON_INDENT (2)); return GNUNET_SYSERR; } - if (! json_is_array (challenges)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } + GNUNET_assert (NULL != dp->emk); + GNUNET_assert (dp->emk_size > 0); dp->pub_details.challenges_length = json_array_size (challenges); dp->pub_details.challenges = GNUNET_new_array ( dp->pub_details.challenges_length, @@ -1263,7 +1303,7 @@ parse_dps_array (struct ANASTASIS_Recovery *r, } } } - GNUNET_JSON_parse_free (spec); + /* Do NOT free the spec: we are still using dp->ems. */ } return GNUNET_OK; } @@ -1305,9 +1345,9 @@ ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx, const char *err_json_name; unsigned int err_line; uint32_t version; - json_t *dps_arr; - json_t *cs_arr; - json_t *id_data; + const json_t *dps_arr; + const json_t *cs_arr; + const json_t *id_data; const char *provider_url; const char *secret_name; void *ecs; @@ -1315,20 +1355,21 @@ ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx, struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("id", &r->id), - GNUNET_JSON_spec_string ("provider_url", + TALER_JSON_spec_web_url ("provider_url", &provider_url), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("secret_name", - &secret_name)), + &secret_name), + NULL), GNUNET_JSON_spec_uint32 ("version", &version), - GNUNET_JSON_spec_json ("dps", - &dps_arr), - GNUNET_JSON_spec_json ("cs", - &cs_arr), - GNUNET_JSON_spec_json ("id_data", - &id_data), - GNUNET_JSON_spec_varsize ("core_secret", + GNUNET_JSON_spec_array_const ("decryption_policies", + &dps_arr), + GNUNET_JSON_spec_array_const ("challenges", + &cs_arr), + GNUNET_JSON_spec_object_const ("id_data", + &id_data), + GNUNET_JSON_spec_varsize ("encrypted_core_secret", &ecs, &ecs_size), GNUNET_JSON_spec_end () @@ -1361,7 +1402,7 @@ ANASTASIS_recovery_deserialize (struct GNUNET_CURL_Context *ctx, GNUNET_JSON_parse_free (spec); return NULL; } - r->id_data = json_incref (id_data); + r->id_data = json_incref ((json_t *) id_data); r->provider_url = GNUNET_strdup (provider_url); if (NULL != secret_name) r->secret_name = GNUNET_strdup (secret_name); @@ -1428,16 +1469,19 @@ ANASTASIS_recovery_abort (struct ANASTASIS_Recovery *r) } GNUNET_free (r->solved_challenges); for (unsigned int j = 0; j < r->ri.dps_len; j++) + { GNUNET_free (r->dps[j].pub_details.challenges); + GNUNET_free (r->dps[j].emk); + } GNUNET_free (r->ri.dps); for (unsigned int i = 0; i < r->ri.cs_len; i++) { - struct ANASTASIS_Challenge *cs = r->ri.cs[i]; + struct ANASTASIS_Challenge *cs = &r->cs[i]; - if (NULL != cs->kslo) + if (NULL != cs->tso) { - ANASTASIS_keyshare_lookup_cancel (cs->kslo); - cs->kslo = NULL; + ANASTASIS_truth_solve_cancel (cs->tso); + cs->tso = NULL; } GNUNET_free (cs->url); GNUNET_free (cs->type); |