summaryrefslogtreecommitdiff
path: root/src/lib/exchange_api_refreshes_reveal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/exchange_api_refreshes_reveal.c')
-rw-r--r--src/lib/exchange_api_refreshes_reveal.c320
1 files changed, 180 insertions, 140 deletions
diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c
index 2b7fcf8cf..69c53a6c9 100644
--- a/src/lib/exchange_api_refreshes_reveal.c
+++ b/src/lib/exchange_api_refreshes_reveal.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015-2021 Taler Systems SA
+ Copyright (C) 2015-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -40,11 +40,6 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
{
/**
- * The connection to exchange this request handle will use
- */
- struct TALER_EXCHANGE_Handle *exchange;
-
- /**
* The url for this request.
*/
char *url;
@@ -61,6 +56,11 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
struct GNUNET_CURL_Job *job;
/**
+ * Exchange-contributed values to the operation.
+ */
+ struct TALER_ExchangeWithdrawValues *alg_values;
+
+ /**
* Function to call with the result.
*/
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb;
@@ -73,7 +73,7 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
/**
* Actual information about the melt operation.
*/
- struct MeltData *md;
+ struct MeltData md;
/**
* The index selected by the exchange in cut-and-choose to not be revealed.
@@ -84,29 +84,28 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
/**
- * We got a 200 OK response for the /refreshes/$RCH/reveal operation.
- * Extract the coin signatures and return them to the caller.
- * The signatures we get from the exchange is for the blinded value.
- * Thus, we first must unblind them and then should verify their
- * validity.
+ * We got a 200 OK response for the /refreshes/$RCH/reveal operation. Extract
+ * the coin signatures and return them to the caller. The signatures we get
+ * from the exchange is for the blinded value. Thus, we first must unblind
+ * them and then should verify their validity.
*
* If everything checks out, we return the unblinded signatures
* to the application via the callback.
*
* @param rrh operation handle
* @param json reply from the exchange
- * @param[out] sigs array of length `num_fresh_coins`, initialized to contain RSA signatures
+ * @param[out] rcis array of length `num_fresh_coins`, initialized to contain the coin data
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
static enum GNUNET_GenericReturnValue
refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
const json_t *json,
- struct TALER_DenominationSignature *sigs)
+ struct TALER_EXCHANGE_RevealedCoinInfo *rcis)
{
- json_t *jsona;
+ const json_t *jsona;
struct GNUNET_JSON_Specification outer_spec[] = {
- GNUNET_JSON_spec_json ("ev_sigs",
- &jsona),
+ GNUNET_JSON_spec_array_const ("ev_sigs",
+ &jsona),
GNUNET_JSON_spec_end ()
};
@@ -118,39 +117,44 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if (! json_is_array (jsona))
- {
- /* We expected an array of coins */
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (outer_spec);
- return GNUNET_SYSERR;
- }
- if (rrh->md->num_fresh_coins != json_array_size (jsona))
+ if (rrh->md.num_fresh_coins != json_array_size (jsona))
{
/* Number of coins generated does not match our expectation */
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
- for (unsigned int i = 0; i<rrh->md->num_fresh_coins; i++)
+ for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
{
- const struct TALER_PlanchetSecretsP *fc;
- struct TALER_DenominationPublicKey *pk;
+ struct TALER_EXCHANGE_RevealedCoinInfo *rci = &rcis[i];
+ const struct FreshCoinData *fcd = &rrh->md.fcds[i];
+ const struct TALER_DenominationPublicKey *pk;
json_t *jsonai;
struct TALER_BlindedDenominationSignature blind_sig;
struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_CoinPubHash coin_hash;
+ struct TALER_CoinPubHashP coin_hash;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_blinded_denom_sig ("ev_sig",
&blind_sig),
GNUNET_JSON_spec_end ()
};
struct TALER_FreshCoin coin;
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+ const struct TALER_AgeCommitmentHash *pah = NULL;
- fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
- pk = &rrh->md->fresh_pks[i];
+ rci->ps = fcd->ps[rrh->noreveal_index];
+ rci->bks = fcd->bks[rrh->noreveal_index];
+ rci->age_commitment_proof = NULL;
+ pk = &fcd->fresh_pk;
jsonai = json_array_get (jsona, i);
GNUNET_assert (NULL != jsonai);
+ if (NULL != rrh->md.melted_coin.age_commitment_proof)
+ {
+ rci->age_commitment_proof
+ = fcd->age_commitment_proofs[rrh->noreveal_index];
+ TALER_age_commitment_hash (&rci->age_commitment_proof->commitment,
+ &rci->h_age_commitment);
+ pah = &rci->h_age_commitment;
+ }
if (GNUNET_OK !=
GNUNET_JSON_parse (jsonai,
@@ -158,34 +162,41 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
+ TALER_planchet_setup_coin_priv (&rci->ps,
+ &rrh->alg_values[i],
+ &rci->coin_priv);
+ TALER_planchet_blinding_secret_create (&rci->ps,
+ &rrh->alg_values[i],
+ &bks);
/* needed to verify the signature, and we didn't store it earlier,
hence recomputing it here... */
- GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ GNUNET_CRYPTO_eddsa_key_get_public (&rci->coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
- /* FIXME-Oec: Age commitment hash. */
- TALER_coin_pub_hash (&coin_pub,
- NULL, /* FIXME-Oec */
- &coin_hash);
+ TALER_coin_pub_hash (
+ &coin_pub,
+ pah,
+ &coin_hash);
if (GNUNET_OK !=
- TALER_planchet_to_coin (pk,
- &blind_sig,
- fc,
- &coin_hash,
- &coin))
+ TALER_planchet_to_coin (
+ pk,
+ &blind_sig,
+ &bks,
+ &rci->coin_priv,
+ pah,
+ &coin_hash,
+ &rrh->alg_values[i],
+ &coin))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
- GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
GNUNET_JSON_parse_free (spec);
- sigs[i] = coin.sig;
+ rci->sig = coin.sig;
}
- GNUNET_JSON_parse_free (outer_spec);
return GNUNET_OK;
}
@@ -205,96 +216,101 @@ handle_refresh_reveal_finished (void *cls,
{
struct TALER_EXCHANGE_RefreshesRevealHandle *rrh = cls;
const json_t *j = response;
- struct TALER_EXCHANGE_HttpResponse hr = {
- .reply = j,
- .http_status = (unsigned int) response_code
+ struct TALER_EXCHANGE_RevealResult rr = {
+ .hr.reply = j,
+ .hr.http_status = (unsigned int) response_code
};
rrh->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
- struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
- int ret;
+ struct TALER_EXCHANGE_RevealedCoinInfo rcis[rrh->md.num_fresh_coins];
+ enum GNUNET_GenericReturnValue ret;
- memset (sigs,
+ memset (rcis,
0,
- sizeof (sigs));
+ sizeof (rcis));
ret = refresh_reveal_ok (rrh,
j,
- sigs);
+ rcis);
if (GNUNET_OK != ret)
{
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ rr.hr.http_status = 0;
+ rr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
}
else
{
+ GNUNET_assert (rrh->noreveal_index < TALER_CNC_KAPPA);
+ rr.details.ok.num_coins = rrh->md.num_fresh_coins;
+ rr.details.ok.coins = rcis;
rrh->reveal_cb (rrh->reveal_cb_cls,
- &hr,
- rrh->md->num_fresh_coins,
- rrh->md->fresh_coins[rrh->noreveal_index],
- sigs);
+ &rr);
rrh->reveal_cb = NULL;
}
- for (unsigned int i = 0; i<rrh->md->num_fresh_coins; i++)
- TALER_denom_sig_free (&sigs[i]);
+ for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
+ {
+ TALER_denom_sig_free (&rcis[i].sig);
+ TALER_age_commitment_proof_free (rcis[i].age_commitment_proof);
+ }
TALER_EXCHANGE_refreshes_reveal_cancel (rrh);
return;
}
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ rr.hr.ec = TALER_JSON_get_error_code (j);
+ rr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_CONFLICT:
/* Nothing really to verify, exchange says our reveal is inconsistent
with our commitment, so either side is buggy; we
should pass the JSON reply to the application */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ rr.hr.ec = TALER_JSON_get_error_code (j);
+ rr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_GONE:
/* Server claims key expired or has been revoked */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ rr.hr.ec = TALER_JSON_get_error_code (j);
+ rr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ rr.hr.ec = TALER_JSON_get_error_code (j);
+ rr.hr.hint = TALER_JSON_get_error_hint (j);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ rr.hr.ec = TALER_JSON_get_error_code (j);
+ rr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange refreshes reveal\n",
(unsigned int) response_code,
- (int) hr.ec);
+ (int) rr.hr.ec);
break;
}
if (NULL != rrh->reveal_cb)
rrh->reveal_cb (rrh->reveal_cb_cls,
- &hr,
- 0,
- NULL,
- NULL);
+ &rr);
TALER_EXCHANGE_refreshes_reveal_cancel (rrh);
}
struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal (
- struct TALER_EXCHANGE_Handle *exchange,
- const json_t *refresh_data,
+ struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ const struct TALER_RefreshMasterSecretP *rms,
+ const struct TALER_EXCHANGE_RefreshData *rd,
+ unsigned int num_coins,
+ const struct TALER_ExchangeWithdrawValues alg_values[static num_coins],
uint32_t noreveal_index,
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
void *reveal_cb_cls)
@@ -305,12 +321,13 @@ TALER_EXCHANGE_refreshes_reveal (
json_t *coin_evs;
json_t *reveal_obj;
json_t *link_sigs;
+ json_t *old_age_commitment = NULL;
CURL *eh;
- struct GNUNET_CURL_Context *ctx;
- struct MeltData *md;
- struct TALER_TransferPublicKeyP transfer_pub;
+ struct MeltData md;
char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32];
+ bool send_rms = false;
+ GNUNET_assert (num_coins == rd->fresh_pks_len);
if (noreveal_index >= TALER_CNC_KAPPA)
{
/* We check this here, as it would be really bad to below just
@@ -320,73 +337,59 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_break (0);
return NULL;
}
- if (GNUNET_YES !=
- TEAH_handle_is_ready (exchange))
- {
- GNUNET_break (0);
- return NULL;
- }
- md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data,
- exchange->key_data.currency);
- if (NULL == md)
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_get_melt_data_ (rms,
+ rd,
+ alg_values,
+ &md))
{
GNUNET_break (0);
return NULL;
}
- /* now transfer_pub */
- GNUNET_CRYPTO_ecdhe_key_get_public (
- &md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv,
- &transfer_pub.ecdhe_pub);
-
/* now new_denoms */
GNUNET_assert (NULL != (new_denoms_h = json_array ()));
GNUNET_assert (NULL != (coin_evs = json_array ()));
GNUNET_assert (NULL != (link_sigs = json_array ()));
- for (unsigned int i = 0; i<md->num_fresh_coins; i++)
+ for (unsigned int i = 0; i<md.num_fresh_coins; i++)
{
- struct TALER_DenominationHash denom_hash;
- struct TALER_PlanchetDetail pd;
- struct TALER_CoinPubHash c_hash;
+ const struct TALER_RefreshCoinData *rcd = &md.rcd[noreveal_index][i];
+ struct TALER_DenominationHashP denom_hash;
- TALER_denom_pub_hash (&md->fresh_pks[i],
+ if (GNUNET_CRYPTO_BSA_CS ==
+ md.fcds[i].fresh_pk.bsign_pub_key->cipher)
+ send_rms = true;
+ TALER_denom_pub_hash (&md.fcds[i].fresh_pk,
&denom_hash);
GNUNET_assert (0 ==
json_array_append_new (new_denoms_h,
GNUNET_JSON_from_data_auto (
&denom_hash)));
-
- if (GNUNET_OK !=
- TALER_planchet_prepare (&md->fresh_pks[i],
- &md->fresh_coins[noreveal_index][i],
- &c_hash,
- &pd))
- {
- /* This should have been noticed during the preparation stage. */
- GNUNET_break (0);
- json_decref (new_denoms_h);
- json_decref (coin_evs);
- return NULL;
- }
GNUNET_assert (0 ==
- json_array_append_new (coin_evs,
- GNUNET_JSON_from_data (pd.coin_ev,
- pd.coin_ev_size)));
+ json_array_append_new (
+ coin_evs,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_blinded_planchet (
+ NULL,
+ &rcd->blinded_planchet))));
{
struct TALER_CoinSpendSignatureP link_sig;
-
- TALER_wallet_link_sign (&denom_hash,
- &transfer_pub,
- pd.coin_ev,
- pd.coin_ev_size,
- &md->melted_coin.coin_priv,
- &link_sig);
+ struct TALER_BlindedCoinHashP bch;
+
+ TALER_coin_ev_hash (&rcd->blinded_planchet,
+ &denom_hash,
+ &bch);
+ TALER_wallet_link_sign (
+ &denom_hash,
+ &md.transfer_pub[noreveal_index],
+ &bch,
+ &md.melted_coin.coin_priv,
+ &link_sig);
GNUNET_assert (0 ==
json_array_append_new (
link_sigs,
GNUNET_JSON_from_data_auto (&link_sig)));
}
- GNUNET_free (pd.coin_ev);
}
/* build array of transfer private keys */
@@ -395,20 +398,46 @@ TALER_EXCHANGE_refreshes_reveal (
{
if (j == noreveal_index)
{
- /* This is crucial: exclude the transfer key for the
- noreval index! */
+ /* This is crucial: exclude the transfer key for the noreval index! */
continue;
}
GNUNET_assert (0 ==
json_array_append_new (transfer_privs,
GNUNET_JSON_from_data_auto (
- &md->melted_coin.transfer_priv[j])));
+ &md.transfer_priv[j])));
+ }
+
+ /* build array of old age commitment, if applicable */
+ if (NULL != rd->melt_age_commitment_proof)
+ {
+ GNUNET_assert (NULL != rd->melt_h_age_commitment);
+ GNUNET_assert (NULL != (old_age_commitment = json_array ()));
+
+ for (size_t i = 0; i < rd->melt_age_commitment_proof->commitment.num; i++)
+ {
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = json_array_append_new (
+ old_age_commitment,
+ GNUNET_JSON_from_data_auto (
+ &rd->melt_age_commitment_proof->commitment.keys[i]));
+ GNUNET_assert (0 == ret);
+ }
}
/* build main JSON request */
reveal_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("transfer_pub",
- &transfer_pub),
+ &md.transfer_pub[noreveal_index]),
+ GNUNET_JSON_pack_allow_null (
+ send_rms
+ ? GNUNET_JSON_pack_data_auto ("rms",
+ rms)
+ : GNUNET_JSON_pack_string ("rms",
+ NULL)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_array_steal ("old_age_commitment",
+ old_age_commitment)),
GNUNET_JSON_pack_array_steal ("transfer_privs",
transfer_privs),
GNUNET_JSON_pack_array_steal ("link_sigs",
@@ -421,32 +450,40 @@ TALER_EXCHANGE_refreshes_reveal (
char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2];
char *end;
- end = GNUNET_STRINGS_data_to_string (&md->rc,
- sizeof (struct
- TALER_RefreshCommitmentP),
+ end = GNUNET_STRINGS_data_to_string (&md.rc,
+ sizeof (md.rc),
pub_str,
sizeof (pub_str));
*end = '\0';
GNUNET_snprintf (arg_str,
sizeof (arg_str),
- "/refreshes/%s/reveal",
+ "refreshes/%s/reveal",
pub_str);
}
/* finally, we can actually issue the request */
rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshesRevealHandle);
- rrh->exchange = exchange;
rrh->noreveal_index = noreveal_index;
rrh->reveal_cb = reveal_cb;
rrh->reveal_cb_cls = reveal_cb_cls;
rrh->md = md;
- rrh->url = TEAH_path_to_url (rrh->exchange,
- arg_str);
+ rrh->alg_values
+ = GNUNET_new_array (md.num_fresh_coins,
+ struct TALER_ExchangeWithdrawValues);
+ for (unsigned int i = 0; i<md.num_fresh_coins; i++)
+ TALER_denom_ewv_copy (&rrh->alg_values[i],
+ &alg_values[i]);
+ rrh->url = TALER_url_join (url,
+ arg_str,
+ NULL);
if (NULL == rrh->url)
{
json_decref (reveal_obj);
+ TALER_EXCHANGE_free_melt_data_ (&md);
+ GNUNET_free (rrh->alg_values);
GNUNET_free (rrh);
return NULL;
}
+
eh = TALER_EXCHANGE_curl_easy_get_ (rrh->url);
if ( (NULL == eh) ||
(GNUNET_OK !=
@@ -458,12 +495,13 @@ TALER_EXCHANGE_refreshes_reveal (
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (reveal_obj);
+ TALER_EXCHANGE_free_melt_data_ (&md);
+ GNUNET_free (rrh->alg_values);
GNUNET_free (rrh->url);
GNUNET_free (rrh);
return NULL;
}
json_decref (reveal_obj);
- ctx = TEAH_handle_to_context (rrh->exchange);
rrh->job = GNUNET_CURL_job_add2 (ctx,
eh,
rrh->ctx.headers,
@@ -482,10 +520,12 @@ TALER_EXCHANGE_refreshes_reveal_cancel (
GNUNET_CURL_job_cancel (rrh->job);
rrh->job = NULL;
}
+ for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
+ TALER_denom_ewv_free (&rrh->alg_values[i]);
+ GNUNET_free (rrh->alg_values);
GNUNET_free (rrh->url);
TALER_curl_easy_post_finished (&rrh->ctx);
- TALER_EXCHANGE_free_melt_data_ (rrh->md); /* does not free 'md' itself */
- GNUNET_free (rrh->md);
+ TALER_EXCHANGE_free_melt_data_ (&rrh->md);
GNUNET_free (rrh);
}