From 7e669bcf6b6336ec429da949bcb4aa456971dba2 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 30 Jul 2021 10:38:27 +0200 Subject: folding history in preparation of GNU Anastasis v0.0.0 release --- src/lib/anastasis_backup.c | 979 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 979 insertions(+) create mode 100644 src/lib/anastasis_backup.c (limited to 'src/lib/anastasis_backup.c') diff --git a/src/lib/anastasis_backup.c b/src/lib/anastasis_backup.c new file mode 100644 index 0000000..ea55e6a --- /dev/null +++ b/src/lib/anastasis_backup.c @@ -0,0 +1,979 @@ +/* + This file is part of Anastasis + Copyright (C) 2020, 2021 Taler Systems SA + + 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 + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Anastasis; see the file COPYING.GPL. If not, see +*/ +/** + * @brief anastasis client api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + */ +#include "platform.h" +#include "anastasis.h" +#include +#include + + +struct ANASTASIS_Truth +{ + /** + * Identification of the truth. + */ + struct ANASTASIS_CRYPTO_TruthUUIDP uuid; + + /** + * Keyshare of this truth, used to generate policy keys + */ + struct ANASTASIS_CRYPTO_KeyShareP key_share; + + /** + * Nonce used for the symmetric encryption. + */ + struct ANASTASIS_CRYPTO_NonceP nonce; + + /** + * Key used to encrypt this truth + */ + struct ANASTASIS_CRYPTO_TruthKeyP truth_key; + + /** + * Server salt used to derive user identifier + */ + struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt; + + /** + * Server salt used to derive hash from security answer + */ + struct ANASTASIS_CRYPTO_QuestionSaltP salt; + + /** + * Url of the server + */ + char *url; + + /** + * Method used for this truth + */ + char *type; + + /** + * Instructions for the user to recover this truth. + */ + char *instructions; + + /** + * Mime type of the truth, NULL if not given. + */ + char *mime_type; + +}; + + +struct ANASTASIS_Truth * +ANASTASIS_truth_from_json (const json_t *json) +{ + struct ANASTASIS_Truth *t = GNUNET_new (struct ANASTASIS_Truth); + const char *url; + const char *type; + const char *instructions; + const char *mime_type = NULL; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("url", + &url), + GNUNET_JSON_spec_string ("type", + &type), + GNUNET_JSON_spec_string ("instructions", + &instructions), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("mime_type", + &mime_type)), + GNUNET_JSON_spec_fixed_auto ("uuid", + &t->uuid), + GNUNET_JSON_spec_fixed_auto ("nonce", + &t->nonce), + GNUNET_JSON_spec_fixed_auto ("key_share", + &t->key_share), + GNUNET_JSON_spec_fixed_auto ("truth_key", + &t->truth_key), + GNUNET_JSON_spec_fixed_auto ("salt", + &t->salt), + GNUNET_JSON_spec_fixed_auto ("provider_salt", + &t->provider_salt), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + GNUNET_free (t); + return NULL; + } + t->url = GNUNET_strdup (url); + t->type = GNUNET_strdup (type); + t->instructions = GNUNET_strdup (instructions); + if (NULL != mime_type) + t->mime_type = GNUNET_strdup (mime_type); + return t; +} + + +json_t * +ANASTASIS_truth_to_json (const struct ANASTASIS_Truth *t) +{ + return json_pack ( + "{s:o,s:o,s:o,s:o,s:o" + ",s:o,s:s,s:s,s:s,s:s?}", + "uuid", + GNUNET_JSON_from_data_auto (&t->uuid), + "key_share", + GNUNET_JSON_from_data_auto (&t->key_share), + "truth_key", + GNUNET_JSON_from_data_auto (&t->truth_key), + "salt", + GNUNET_JSON_from_data_auto (&t->salt), + "nonce", + GNUNET_JSON_from_data_auto (&t->nonce), + "provider_salt", + GNUNET_JSON_from_data_auto (&t->provider_salt), + "url", + t->url, + "type", + t->type, + "instructions", + t->instructions, + "mime_type", + t->mime_type); +} + + +struct ANASTASIS_TruthUpload +{ + + /** + * User identifier used for the keyshare encryption + */ + struct ANASTASIS_CRYPTO_UserIdentifierP id; + + /** + * CURL Context for the Post Request + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Callback which sends back the generated truth object later used to build the policy + */ + ANASTASIS_TruthCallback tc; + + /** + * Closure for the Callback + */ + void *tc_cls; + + /** + * Reference to the Truthstore Operation + */ + struct ANASTASIS_TruthStoreOperation *tso; + + /** + * The truth we are uploading. + */ + struct ANASTASIS_Truth *t; + +}; + + +/** + * Function called with the result of trying to upload truth. + * + * @param cls our `struct ANASTASIS_TruthUpload` + * @param ud details about the upload result + */ +static void +truth_store_callback (void *cls, + const struct ANASTASIS_UploadDetails *ud) +{ + struct ANASTASIS_TruthUpload *tu = cls; + + tu->tso = NULL; + tu->tc (tu->tc_cls, + tu->t, + ud); + tu->t = NULL; + ANASTASIS_truth_upload_cancel (tu); +} + + +struct ANASTASIS_TruthUpload * +ANASTASIS_truth_upload3 (struct GNUNET_CURL_Context *ctx, + const struct ANASTASIS_CRYPTO_UserIdentifierP *user_id, + struct ANASTASIS_Truth *t, + const void *truth_data, + size_t truth_data_size, + uint32_t payment_years_requested, + struct GNUNET_TIME_Relative pay_timeout, + ANASTASIS_TruthCallback tc, + void *tc_cls) +{ + struct ANASTASIS_TruthUpload *tu; + struct ANASTASIS_CRYPTO_EncryptedKeyShareP encrypted_key_share; + struct GNUNET_HashCode nt; + void *encrypted_truth; + size_t encrypted_truth_size; + + tu = GNUNET_new (struct ANASTASIS_TruthUpload); + tu->tc = tc; + tu->tc_cls = tc_cls; + tu->ctx = ctx; + tu->id = *user_id; + tu->tc = tc; + tu->tc_cls = tc_cls; + tu->t = t; + + if (0 == strcmp ("question", + t->type)) + { + char *answer; + + answer = GNUNET_strndup (truth_data, + truth_data_size); + ANASTASIS_CRYPTO_secure_answer_hash (answer, + &t->uuid, + &t->salt, + &nt); + ANASTASIS_CRYPTO_keyshare_encrypt (&t->key_share, + &tu->id, + answer, + &encrypted_key_share); + GNUNET_free (answer); + truth_data = &nt; + truth_data_size = sizeof (nt); + } + else + { + ANASTASIS_CRYPTO_keyshare_encrypt (&t->key_share, + &tu->id, + NULL, + &encrypted_key_share); + } + ANASTASIS_CRYPTO_truth_encrypt (&t->nonce, + &t->truth_key, + truth_data, + truth_data_size, + &encrypted_truth, + &encrypted_truth_size); + tu->tso = ANASTASIS_truth_store (tu->ctx, + t->url, + &t->uuid, + t->type, + &encrypted_key_share, + t->mime_type, + encrypted_truth_size, + encrypted_truth, + payment_years_requested, + pay_timeout, + &truth_store_callback, + tu); + GNUNET_free (encrypted_truth); + if (NULL == tu->tso) + { + GNUNET_break (0); + ANASTASIS_truth_free (t); + ANASTASIS_truth_upload_cancel (tu); + return NULL; + } + return tu; +} + + +struct ANASTASIS_TruthUpload * +ANASTASIS_truth_upload2 ( + struct GNUNET_CURL_Context *ctx, + const struct ANASTASIS_CRYPTO_UserIdentifierP *user_id, + const char *provider_url, + const char *type, + const char *instructions, + const char *mime_type, + const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt, + const void *truth_data, + size_t truth_data_size, + uint32_t payment_years_requested, + struct GNUNET_TIME_Relative pay_timeout, + const struct ANASTASIS_CRYPTO_NonceP *nonce, + const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid, + const struct ANASTASIS_CRYPTO_QuestionSaltP *salt, + const struct ANASTASIS_CRYPTO_TruthKeyP *truth_key, + const struct ANASTASIS_CRYPTO_KeyShareP *key_share, + ANASTASIS_TruthCallback tc, + void *tc_cls) +{ + struct ANASTASIS_Truth *t; + + t = GNUNET_new (struct ANASTASIS_Truth); + t->url = GNUNET_strdup (provider_url); + t->type = GNUNET_strdup (type); + t->instructions = (NULL != instructions) + ? GNUNET_strdup (instructions) + : NULL; + t->mime_type = (NULL != mime_type) + ? GNUNET_strdup (mime_type) + : NULL; + t->provider_salt = *provider_salt; + t->salt = *salt; + t->nonce = *nonce; + t->uuid = *uuid; + t->truth_key = *truth_key; + t->key_share = *key_share; + return ANASTASIS_truth_upload3 (ctx, + user_id, + t, + truth_data, + truth_data_size, + payment_years_requested, + pay_timeout, + tc, + tc_cls); +} + + +struct ANASTASIS_TruthUpload * +ANASTASIS_truth_upload ( + struct GNUNET_CURL_Context *ctx, + const struct ANASTASIS_CRYPTO_UserIdentifierP *user_id, + const char *provider_url, + const char *type, + const char *instructions, + const char *mime_type, + const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt, + const void *truth_data, + size_t truth_data_size, + uint32_t payment_years_requested, + struct GNUNET_TIME_Relative pay_timeout, + ANASTASIS_TruthCallback tc, + void *tc_cls) +{ + struct ANASTASIS_CRYPTO_QuestionSaltP question_salt; + struct ANASTASIS_CRYPTO_TruthUUIDP uuid; + struct ANASTASIS_CRYPTO_TruthKeyP truth_key; + struct ANASTASIS_CRYPTO_KeyShareP key_share; + struct ANASTASIS_CRYPTO_NonceP nonce; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &nonce, + sizeof (nonce)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &question_salt, + sizeof (question_salt)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &uuid, + sizeof (uuid)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, + &truth_key, + sizeof (truth_key)); + ANASTASIS_CRYPTO_keyshare_create (&key_share); + return ANASTASIS_truth_upload2 (ctx, + user_id, + provider_url, + type, + instructions, + mime_type, + provider_salt, + truth_data, + truth_data_size, + payment_years_requested, + pay_timeout, + &nonce, + &uuid, + &question_salt, + &truth_key, + &key_share, + tc, + tc_cls); +} + + +void +ANASTASIS_truth_upload_cancel (struct ANASTASIS_TruthUpload *tu) +{ + if (NULL != tu->tso) + { + ANASTASIS_truth_store_cancel (tu->tso); + tu->tso = NULL; + } + if (NULL != tu->t) + { + ANASTASIS_truth_free (tu->t); + tu->t = NULL; + } + GNUNET_free (tu); +} + + +void +ANASTASIS_truth_free (struct ANASTASIS_Truth *t) +{ + GNUNET_free (t->url); + GNUNET_free (t->type); + GNUNET_free (t->instructions); + GNUNET_free (t->mime_type); + GNUNET_free (t); +} + + +struct ANASTASIS_Policy +{ + /** + * Encrypted policy master key + */ + struct ANASTASIS_CRYPTO_PolicyKeyP policy_key; + + /** + * Salt used to encrypt the master key + */ + struct ANASTASIS_CRYPTO_MasterSaltP salt; + + /** + * Array of truths + */ + struct ANASTASIS_Truth **truths; + + /** + * Length of @ truths array. + */ + uint32_t truths_length; + +}; + + +/** + * Duplicate truth object. + * + * @param t object to duplicate + * @return copy of @a t + */ +static struct ANASTASIS_Truth * +truth_dup (const struct ANASTASIS_Truth *t) +{ + struct ANASTASIS_Truth *d = GNUNET_new (struct ANASTASIS_Truth); + + *d = *t; + d->url = GNUNET_strdup (t->url); + d->type = GNUNET_strdup (t->type); + d->instructions = GNUNET_strdup (t->instructions); + if (NULL != t->mime_type) + d->mime_type = GNUNET_strdup (t->mime_type); + return d; +} + + +struct ANASTASIS_Policy * +ANASTASIS_policy_create (const struct ANASTASIS_Truth *truths[], + unsigned int truths_len) +{ + struct ANASTASIS_Policy *p; + + p = GNUNET_new (struct ANASTASIS_Policy); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &p->salt, + sizeof (p->salt)); + { + struct ANASTASIS_CRYPTO_KeyShareP key_shares[truths_len]; + + for (unsigned int i = 0; i < truths_len; i++) + key_shares[i] = truths[i]->key_share; + ANASTASIS_CRYPTO_policy_key_derive (key_shares, + truths_len, + &p->salt, + &p->policy_key); + } + p->truths = GNUNET_new_array (truths_len, + struct ANASTASIS_Truth *); + for (unsigned int i = 0; itruths[i] = truth_dup (truths[i]); + p->truths_length = truths_len; + return p; +} + + +void +ANASTASIS_policy_destroy (struct ANASTASIS_Policy *p) +{ + for (unsigned int i = 0; itruths_length; i++) + ANASTASIS_truth_free (p->truths[i]); + GNUNET_free (p->truths); + GNUNET_free (p); +} + + +/** + * State for a "policy store" CMD. + */ +struct PolicyStoreState +{ + /** + * User identifier used as entropy source for the account public key + */ + struct ANASTASIS_CRYPTO_UserIdentifierP id; + + /** + * Hash of the current upload. Used to check the server's response. + */ + struct GNUNET_HashCode curr_hash; + + /** + * Payment identifier. + */ + struct ANASTASIS_PaymentSecretP payment_secret; + + /** + * Server salt. Points into a truth object from which we got the + * salt. + */ + struct ANASTASIS_CRYPTO_ProviderSaltP server_salt; + + /** + * The /policy POST operation handle. + */ + struct ANASTASIS_PolicyStoreOperation *pso; + + /** + * URL of the anastasis backend. + */ + char *anastasis_url; + + /** + * Payment request returned by this provider, if any. + */ + char *payment_request; + + /** + * reference to SecretShare + */ + struct ANASTASIS_SecretShare *ss; + + /** + * Version of the policy created at the provider. + */ + unsigned long long policy_version; + + /** + * When will the policy expire at the provider. + */ + struct GNUNET_TIME_Absolute policy_expiration; + +}; + +/** +* Defines a recovery document upload process (recovery document consists of multiple policies) +*/ +struct ANASTASIS_SecretShare +{ + /** + * Closure for the Result Callback + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Callback which gives back the result of the POST Request + */ + ANASTASIS_ShareResultCallback src; + + /** + * Closure for the Result Callback + */ + void *src_cls; + + /** + * References for the upload states and operations (size of truths passed) + */ + struct PolicyStoreState *pss; + + /** + * Closure for the Result Callback + */ + unsigned int pss_length; +}; + + +/** + * Callback to process a POST /policy request + * + * @param cls closure + * @param ec anastasis-specific error code + * @param obj the decoded response body + */ +static void +policy_store_cb (void *cls, + const struct ANASTASIS_UploadDetails *ud) +{ + struct PolicyStoreState *pss = cls; + struct ANASTASIS_SecretShare *ss = pss->ss; + enum ANASTASIS_UploadStatus us; + + pss->pso = NULL; + if (NULL == ud) + us = ANASTASIS_US_HTTP_ERROR; + else + us = ud->us; + if ( (ANASTASIS_US_SUCCESS == us) && + (0 != GNUNET_memcmp (&pss->curr_hash, + ud->details.success.curr_backup_hash)) ) + { + GNUNET_break_op (0); + us = ANASTASIS_US_SERVER_ERROR; + } + switch (us) + { + case ANASTASIS_US_SUCCESS: + pss->policy_version = ud->details.success.policy_version; + pss->policy_expiration = ud->details.success.policy_expiration; + break; + case ANASTASIS_US_PAYMENT_REQUIRED: + pss->payment_request = GNUNET_strdup (ud->details.payment.payment_request); + pss->payment_secret = ud->details.payment.ps; + break; + case ANASTASIS_US_HTTP_ERROR: + case ANASTASIS_US_CLIENT_ERROR: + case ANASTASIS_US_SERVER_ERROR: + { + struct ANASTASIS_ShareResult sr = { + .ss = ANASTASIS_SHARE_STATUS_PROVIDER_FAILED, + .details.provider_failure.provider_url = pss->anastasis_url, + .details.provider_failure.http_status = ud->http_status, + .details.provider_failure.ec = us, + }; + + ss->src (ss->src_cls, + &sr); + ANASTASIS_secret_share_cancel (ss); + return; + } + case ANASTASIS_US_CONFLICTING_TRUTH: + GNUNET_break (0); + break; + } + for (unsigned int i = 0; ipss_length; i++) + if (NULL != ss->pss[i].pso) + /* some upload is still pending, let's wait for it to finish */ + return; + + { + struct ANASTASIS_SharePaymentRequest spr[GNUNET_NZL (ss->pss_length)]; + struct ANASTASIS_ProviderSuccessStatus apss[GNUNET_NZL (ss->pss_length)]; + unsigned int off = 0; + unsigned int voff = 0; + struct ANASTASIS_ShareResult sr; + + for (unsigned int i = 0; ipss_length; i++) + { + struct PolicyStoreState *pssi = &ss->pss[i]; + + if (NULL == pssi->payment_request) + { + apss[voff].policy_version = pssi->policy_version; + apss[voff].provider_url = pssi->anastasis_url; + apss[voff].policy_expiration = pssi->policy_expiration; + voff++; + } + else + { + spr[off].payment_request_url = pssi->payment_request; + spr[off].provider_url = pssi->anastasis_url; + spr[off].payment_secret = pssi->payment_secret; + off++; + } + } + if (off > 0) + { + sr.ss = ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED; + sr.details.payment_required.payment_requests = spr; + sr.details.payment_required.payment_requests_length = off; + } + else + { + sr.ss = ANASTASIS_SHARE_STATUS_SUCCESS; + sr.details.success.pss = apss; + sr.details.success.num_providers = voff; + } + ss->src (ss->src_cls, + &sr); + } + ANASTASIS_secret_share_cancel (ss); +} + + +struct ANASTASIS_SecretShare * +ANASTASIS_secret_share (struct GNUNET_CURL_Context *ctx, + const json_t *id_data, + const struct ANASTASIS_ProviderDetails providers[], + unsigned int pss_length, + const struct ANASTASIS_Policy *policies[], + unsigned int policies_len, + uint32_t payment_years_requested, + struct GNUNET_TIME_Relative pay_timeout, + ANASTASIS_ShareResultCallback src, + void *src_cls, + const char *secret_name, + const void *core_secret, + size_t core_secret_size) +{ + struct ANASTASIS_SecretShare *ss; + struct ANASTASIS_CRYPTO_EncryptedMasterKeyP + encrypted_master_keys[GNUNET_NZL (policies_len)]; + void *encrypted_core_secret; + json_t *dec_policies; + json_t *esc_methods; + size_t recovery_document_size; + char *recovery_document_str; + + if (0 == pss_length) + { + GNUNET_break (0); + return NULL; + } + ss = GNUNET_new (struct ANASTASIS_SecretShare); + ss->src = src; + ss->src_cls = src_cls; + ss->pss = GNUNET_new_array (pss_length, + struct PolicyStoreState); + ss->pss_length = pss_length; + ss->ctx = ctx; + + { + struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[GNUNET_NZL (policies_len)]; + + for (unsigned int i = 0; i < policies_len; i++) + policy_keys[i] = policies[i]->policy_key; + ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys, + policies_len, + core_secret, + core_secret_size, + &encrypted_core_secret, + encrypted_master_keys); + } + dec_policies = json_array (); + GNUNET_assert (NULL != dec_policies); + for (unsigned int k = 0; k < policies_len; k++) + { + const struct ANASTASIS_Policy *policy = policies[k]; + json_t *uuids = json_array (); + + GNUNET_assert (NULL != uuids); + for (unsigned int b = 0; b < policy->truths_length; b++) + GNUNET_assert (0 == + json_array_append_new ( + uuids, + GNUNET_JSON_from_data_auto ( + &policy->truths[b]->uuid))); + if (0 != + json_array_append_new ( + dec_policies, + json_pack ("{s:o, s:o, s:o}", + "master_key", + GNUNET_JSON_from_data_auto ( + &encrypted_master_keys[k]), + "uuids", + uuids, + "salt", + GNUNET_JSON_from_data_auto (&policy->salt)))) + { + GNUNET_break (0); + json_decref (dec_policies); + ANASTASIS_secret_share_cancel (ss); + return NULL; + } + } + + esc_methods = json_array (); + for (unsigned int k = 0; k < policies_len; k++) + { + const struct ANASTASIS_Policy *policy = policies[k]; + + for (unsigned int l = 0; l < policy->truths_length; l++) + { + const struct ANASTASIS_Truth *pt = policy->truths[l]; + bool unique = true; + + /* Only append each truth once */ + for (unsigned int k2 = 0; k2 < k; k2++) + { + const struct ANASTASIS_Policy *p2 = policies[k2]; + for (unsigned int l2 = 0; l2 < p2->truths_length; l2++) + if (0 == + GNUNET_memcmp (&pt->uuid, + &p2->truths[l2]->uuid)) + { + unique = false; + break; + } + if (! unique) + break; + } + if (! unique) + continue; + + if (0 != + json_array_append_new ( + esc_methods, + json_pack ("{s:o," /* truth uuid */ + " s:s," /* provider url */ + " s:s," /* instructions */ + " s:o," /* truth key */ + " s:o," /* truth salt */ + " s:o," /* provider salt */ + " s:s}", /* escrow method */ + "uuid", + GNUNET_JSON_from_data_auto ( + &pt->uuid), + "url", + pt->url, + "instructions", + pt->instructions, + "truth_key", GNUNET_JSON_from_data_auto ( + &pt->truth_key), + "salt", GNUNET_JSON_from_data_auto ( + &pt->salt), + "provider_salt", GNUNET_JSON_from_data_auto ( + &pt->provider_salt), + "escrow_type", + pt->type))) + { + GNUNET_break (0); + json_decref (esc_methods); + json_decref (dec_policies); + ANASTASIS_secret_share_cancel (ss); + return NULL; + } + } + } + + { + json_t *recovery_document; + size_t rd_size; + char *rd_str; + Bytef *cbuf; + uLongf cbuf_size; + int ret; + uint32_t be_size; + + recovery_document = json_pack ( + "{s:s?, s:o, s:o, s:o}", + "secret_name", secret_name, + "policies", dec_policies, + "escrow_methods", esc_methods, + "encrypted_core_secret", GNUNET_JSON_from_data (encrypted_core_secret, + core_secret_size)); + GNUNET_assert (NULL != recovery_document); + GNUNET_free (encrypted_core_secret); + + rd_str = json_dumps (recovery_document, + JSON_COMPACT | JSON_SORT_KEYS); + GNUNET_assert (NULL != rd_str); + json_decref (recovery_document); + rd_size = strlen (rd_str); + cbuf_size = compressBound (rd_size); + be_size = htonl ((uint32_t) rd_size); + cbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t)); + memcpy (cbuf, + &be_size, + sizeof (uint32_t)); + ret = compress (cbuf + sizeof (uint32_t), + &cbuf_size, + (const Bytef *) rd_str, + rd_size); + if (Z_OK != ret) + { + /* compression failed!? */ + GNUNET_break (0); + free (rd_str); + GNUNET_free (cbuf); + ANASTASIS_secret_share_cancel (ss); + return NULL; + } + free (rd_str); + recovery_document_size = (size_t) (cbuf_size + sizeof (uint32_t)); + recovery_document_str = (char *) cbuf; + } + + for (unsigned int l = 0; l < ss->pss_length; l++) + { + struct PolicyStoreState *pss = &ss->pss[l]; + void *recovery_data; + size_t recovery_data_size; + struct ANASTASIS_CRYPTO_AccountPrivateKeyP anastasis_priv; + + pss->ss = ss; + pss->anastasis_url = GNUNET_strdup (providers[l].provider_url); + pss->server_salt = providers[l].provider_salt; + pss->payment_secret = providers[l].payment_secret; + ANASTASIS_CRYPTO_user_identifier_derive (id_data, + &pss->server_salt, + &pss->id); + ANASTASIS_CRYPTO_account_private_key_derive (&pss->id, + &anastasis_priv); + ANASTASIS_CRYPTO_recovery_document_encrypt (&pss->id, + recovery_document_str, + recovery_document_size, + &recovery_data, + &recovery_data_size); + GNUNET_CRYPTO_hash (recovery_data, + recovery_data_size, + &pss->curr_hash); + pss->pso = ANASTASIS_policy_store ( + ss->ctx, + pss->anastasis_url, + &anastasis_priv, + recovery_data, + recovery_data_size, + payment_years_requested, + (! GNUNET_is_zero (&pss->payment_secret)) + ? &pss->payment_secret + : NULL, + pay_timeout, + &policy_store_cb, + pss); + GNUNET_free (recovery_data); + if (NULL == pss->pso) + { + GNUNET_break (0); + ANASTASIS_secret_share_cancel (ss); + GNUNET_free (recovery_document_str); + return NULL; + } + } + GNUNET_free (recovery_document_str); + return ss; +} + + +void +ANASTASIS_secret_share_cancel (struct ANASTASIS_SecretShare *ss) +{ + for (unsigned int i = 0; ipss_length; i++) + { + struct PolicyStoreState *pssi = &ss->pss[i]; + + if (NULL != pssi->pso) + { + ANASTASIS_policy_store_cancel (pssi->pso); + pssi->pso = NULL; + } + GNUNET_free (pssi->anastasis_url); + GNUNET_free (pssi->payment_request); + } + GNUNET_free (ss->pss); + GNUNET_free (ss); +} -- cgit v1.2.3