diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/exchange_api_melt.c | 230 | ||||
| -rw-r--r-- | src/lib/exchange_api_refresh_common.c | 364 | ||||
| -rw-r--r-- | src/lib/exchange_api_refresh_common.h | 26 | ||||
| -rw-r--r-- | src/lib/exchange_api_refreshes_reveal.c | 59 | 
4 files changed, 274 insertions, 405 deletions
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index f375171b..dc9a400d 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015-2021 Taler Systems SA +  Copyright (C) 2015-2022 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 @@ -73,7 +73,23 @@ struct TALER_EXCHANGE_MeltHandle    /**     * Actual information about the melt operation.     */ -  struct MeltData *md; +  struct MeltData md; + +  /** +   * The secret the entire melt operation is seeded from. +   */ +  const struct TALER_PlanchetSecretsP *ps; + +  /** +   * Details about the characteristics of the requested melt operation. +   */ +  const struct TALER_EXCHANGE_RefreshData *rd; + +  /** +   * Array of `num_fresh_coins` contributory values of +   * the exchange to the melt operation. +   */ +  struct TALER_ExchangeWithdrawValues *alg_values;    /**     * Public key of the coin being melted. @@ -106,9 +122,12 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,    struct TALER_ExchangeSignatureP exchange_sig;    const struct TALER_EXCHANGE_Keys *key_state;    struct GNUNET_JSON_Specification spec[] = { -    GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig), -    GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub), -    GNUNET_JSON_spec_uint32 ("noreveal_index", noreveal_index), +    GNUNET_JSON_spec_fixed_auto ("exchange_sig", +                                 &exchange_sig), +    GNUNET_JSON_spec_fixed_auto ("exchange_pub", +                                 exchange_pub), +    GNUNET_JSON_spec_uint32 ("noreveal_index", +                             noreveal_index),      GNUNET_JSON_spec_end ()    };    struct TALER_RefreshMeltConfirmationPS confirm; @@ -338,6 +357,12 @@ handle_melt_finished (void *cls,      {        mh->melt_cb (mh->melt_cb_cls,                     &hr, +                   (0 == hr.http_status) +                   ? 0 +                   : mh->rd->fresh_pks_len, +                   (0 == hr.http_status) +                   ? NULL +                   : mh->alg_values,                     noreveal_index,                     (0 == hr.http_status)                     ? NULL @@ -419,40 +444,37 @@ handle_melt_finished (void *cls,    if (NULL != mh->melt_cb)      mh->melt_cb (mh->melt_cb_cls,                   &hr, +                 0, +                 NULL,                   UINT32_MAX,                   NULL);    TALER_EXCHANGE_melt_cancel (mh);  } -struct TALER_EXCHANGE_MeltHandle * -TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, -                     const json_t *refresh_data, -                     TALER_EXCHANGE_MeltCallback melt_cb, -                     void *melt_cb_cls) +static enum GNUNET_GenericReturnValue +start_melt (struct TALER_EXCHANGE_MeltHandle *mh)  {    const struct TALER_EXCHANGE_Keys *key_state;    const struct TALER_EXCHANGE_DenomPublicKey *dki;    json_t *melt_obj; -  struct TALER_EXCHANGE_MeltHandle *mh;    CURL *eh;    struct GNUNET_CURL_Context *ctx; -  struct MeltData *md;    struct TALER_CoinSpendSignatureP confirm_sig;    char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];    struct TALER_DenominationHash h_denom_pub;    struct TALER_CoinSpendPublicKeyP coin_pub; -  GNUNET_assert (GNUNET_YES == -                 TEAH_handle_is_ready (exchange)); -  md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data, -                                              exchange->key_data.currency); -  if (NULL == md) +  if (GNUNET_OK != +      TALER_EXCHANGE_get_melt_data_ (mh->ps, +                                     mh->rd, +                                     mh->alg_values, +                                     &mh->md))    {      GNUNET_break (0); -    return NULL; +    return GNUNET_SYSERR;    } -  TALER_denom_pub_hash (&md->melted_coin.pub_key, +  TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,                          &h_denom_pub);    TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee,                            &md->melted_coin.fee_melt, @@ -489,29 +511,19 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,                       pub_str);    } -  key_state = TALER_EXCHANGE_get_keys (exchange); +  ctx = TEAH_handle_to_context (mh->exchange); +  key_state = TALER_EXCHANGE_get_keys (mh->exchange);    dki = TALER_EXCHANGE_get_denomination_key (key_state, -                                             &md->melted_coin.pub_key); +                                             &mh->md.melted_coin.pub_key);    /* and now we can at last begin the actual request handling */ -  mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle); -  mh->exchange = exchange; -  mh->coin_pub = coin_pub; -  mh->dki = *dki; -  memset (&mh->dki.key, -          0, -          sizeof (mh->dki.key)); /* lifetime not warranted, so better -                                    not copy the pointers */ -  mh->melt_cb = melt_cb; -  mh->melt_cb_cls = melt_cb_cls; -  mh->md = md; -  mh->url = TEAH_path_to_url (exchange, + +  mh->url = TEAH_path_to_url (mh->exchange,                                arg_str);    if (NULL == mh->url)    {      json_decref (melt_obj); -    GNUNET_free (mh); -    return NULL; +    return GNUNET_SYSERR;    }    eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);    if ( (NULL == eh) || @@ -524,17 +536,154 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,      if (NULL != eh)        curl_easy_cleanup (eh);      json_decref (melt_obj); -    GNUNET_free (mh->url); -    GNUNET_free (mh); -    return NULL; +    return GNUNET_SYSERR;    }    json_decref (melt_obj); -  ctx = TEAH_handle_to_context (exchange);    mh->job = GNUNET_CURL_job_add2 (ctx,                                    eh,                                    mh->ctx.headers,                                    &handle_melt_finished,                                    mh); +  return GNUNET_OK; +} + + +static void +fail_mh (struct TALER_EXCHANGE_MeltHandle *mh) +{ +  // FIXME: do return more than NULLs if +  // the /csr failed! +  mh->melt_cb (mh->melt_cb_cls, +               NULL, +               0, +               NULL, +               UINT32_MAX, +               NULL); +  TALER_EXCHANGE_melt_cancel (mh); +} + + +/** + * Callbacks of this type are used to serve the result of submitting a + * CS R request to a exchange. + * + * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *` + * @param csrr response details + */ +static void +csr_cb (void *cls, +        const struct TALER_EXCHANGE_CsRResponse *csrr) +{ +  struct TALER_EXCHANGE_MeltHandle *mh = cls; +  unsigned int nks_off = 0; + +  for (unsigned int i = 0; i<rd->fresh_pks_len; i++) +  { +    const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i]; +    struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i]; + +    switch (fresh_pk->cipher) +    { +    case TALER_DENOMINATION_INVALID: +      GNUNET_break (0); +      fail_mh (mh). +      return; +    case TALER_DENOMINATION_RSA: +      GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher); +      break; +    case TALER_DENOMINATION_CS: +      GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher); +      *wv = csrr->details.success.alg_values[nks_off]; +      nks_off++; +      break; +    } +  } +  if (GNUNET_OK != +      start_melt (mh)) +  { +    GNUNET_break (0); +    fail_mh (mh); +    return; +  } +} + + +struct TALER_EXCHANGE_MeltHandle * +TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, +                     const struct TALER_PlanchetSecretsP *ps, +                     const struct TALER_EXCHANGE_RefreshData *rd, +                     TALER_EXCHANGE_MeltCallback melt_cb, +                     void *melt_cb_cls) +s +{ +  const struct TALER_EXCHANGE_NonceKey *nks[GNUNET_NZL (rd->refresh_pks_len)]; +  unsigned int nks_off = 0; + +  if (0 == rd->refresh_pks_len) +  { +    GNUNET_break (0); +    return NULL; +  } +  GNUNET_assert (GNUNET_YES == +                 TEAH_handle_is_ready (exchange)); +  mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle); +  mh->exchange = exchange; +  mh->rd = rd; +  mh->ps = ps; +  mh->melt_cb = melt_cb; +  mh->melt_cb_cls = melt_cb_cls; +  mh->alg_values = GNUNET_new_array (struct TALER_ExchangeWithdrawValues, +                                     rd->fresh_pks_len); +  for (unsigned int i = 0; i<rd->fresh_pks_len; i++) +  { +    const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i]; +    struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i]; + +    switch (fresh_pk->cipher) +    { +    case TALER_DENOMINATION_INVALID: +      GNUNET_break (0); +      GNUNET_free (mh->alg_values); +      GNUNET_free (mh); +      return NULL; +    case TALER_DENOMINATION_RSA: +      wv->cipher = TALER_DENOMINATION_RSA; +      break; +    case TALER_DENOMINATION_CS: +      wv->cipher = TALER_DENOMINATION_CS; +      nks[nks_off].pk = fresh_pk; +      // derive nonce for refresh by index and ps; +      // FIXME: include fresh_pk or not? +      TALER_CRYPTO_XXX (ps, +                        fresh_pk, +                        i, +                        &nks[nks_off].nonce); +      nks_off++; +      break; +    } +  } +  if (0 != nks_off) +  { +    mh->csr = TALER_EXCHANGE_csr (exchange, +                                  nks_off, +                                  nks, +                                  &csr_cb, +                                  mh); +    if (NULL == mh->csr) +    { +      GNUNET_break (0); +      TALER_EXCHANGE_melt_cancel (mh->csr); +      return NULL; +    } +    return mh; +  } +  if (GNUNET_OK != +      start_melt (mh)) +  { +    GNUNET_break (0); +    TALER_EXCHANGE_melt_cancel (mh->csr); +    return NULL; +  }    return mh;  } @@ -547,8 +696,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)      GNUNET_CURL_job_cancel (mh->job);      mh->job = NULL;    } -  TALER_EXCHANGE_free_melt_data_ (mh->md); /* does not free 'md' itself */ -  GNUNET_free (mh->md); +  TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */    GNUNET_free (mh->url);    TALER_curl_easy_post_finished (&mh->ctx);    GNUNET_free (mh); diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 65c7d6ba..cf04bca5 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -23,24 +23,11 @@  #include "exchange_api_refresh_common.h" -/** - * Free all information associated with a melted coin session. - * - * @param mc melted coin to release, the pointer itself is NOT - *           freed (as it is typically not allocated by itself) - */ -static void -free_melted_coin (struct MeltedCoin *mc) -{ -  TALER_denom_pub_free (&mc->pub_key); -  TALER_denom_sig_free (&mc->sig); -} - -  void  TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)  { -  free_melted_coin (&md->melted_coin); +  TALER_denom_pub_free (&md->melted_coin.pub_key); +  TALER_denom_sig_free (&md->melted_coin.sig);    if (NULL != md->fresh_pks)    {      for (unsigned int i = 0; i<md->num_fresh_coins; i++) @@ -55,296 +42,12 @@ TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)  } -/** - * Serialize information about a coin we are melting. - * - * @param mc information to serialize - * @return NULL on error - */ -static json_t * -serialize_melted_coin (const struct MeltedCoin *mc) -{ -  json_t *tprivs; - -  tprivs = json_array (); -  GNUNET_assert (NULL != tprivs); -  for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) -    GNUNET_assert (0 == -                   json_array_append_new ( -                     tprivs, -                     GNUNET_JSON_PACK ( -                       GNUNET_JSON_pack_data_auto ( -                         "transfer_priv", -                         &mc->transfer_priv[i])))); -  return GNUNET_JSON_PACK ( -    GNUNET_JSON_pack_data_auto ("coin_priv", -                                &mc->coin_priv), -    TALER_JSON_pack_denom_sig ("denom_sig", -                               &mc->sig), -    TALER_JSON_pack_denom_pub ("denom_pub", -                               &mc->pub_key), -    TALER_JSON_pack_amount ("melt_amount_with_fee", -                            &mc->melt_amount_with_fee), -    TALER_JSON_pack_amount ("original_value", -                            &mc->original_value), -    TALER_JSON_pack_amount ("melt_fee", -                            &mc->fee_melt), -    GNUNET_JSON_pack_timestamp ("expire_deposit", -                                mc->expire_deposit), -    GNUNET_JSON_pack_array_steal ("transfer_privs", -                                  tprivs)); -} - - -/** - * Deserialize information about a coin we are melting. - * - * @param[out] mc information to deserialize - * @param currency expected currency - * @param in JSON object to read data from - * @return #GNUNET_NO to report errors - */ -static enum GNUNET_GenericReturnValue -deserialize_melted_coin (struct MeltedCoin *mc, -                         const char *currency, -                         const json_t *in) -{ -  json_t *trans_privs; -  struct GNUNET_JSON_Specification spec[] = { -    GNUNET_JSON_spec_fixed_auto ("coin_priv", -                                 &mc->coin_priv), -    TALER_JSON_spec_denom_sig ("denom_sig", -                               &mc->sig), -    TALER_JSON_spec_denom_pub ("denom_pub", -                               &mc->pub_key), -    TALER_JSON_spec_amount ("melt_amount_with_fee", -                            currency, -                            &mc->melt_amount_with_fee), -    TALER_JSON_spec_amount ("original_value", -                            currency, -                            &mc->original_value), -    TALER_JSON_spec_amount ("melt_fee", -                            currency, -                            &mc->fee_melt), -    GNUNET_JSON_spec_timestamp ("expire_deposit", -                                &mc->expire_deposit), -    GNUNET_JSON_spec_json ("transfer_privs", -                           &trans_privs), -    GNUNET_JSON_spec_end () -  }; - -  if (GNUNET_OK != -      GNUNET_JSON_parse (in, -                         spec, -                         NULL, NULL)) -  { -    GNUNET_break_op (0); -    return GNUNET_NO; -  } -  if (TALER_CNC_KAPPA != json_array_size (trans_privs)) -  { -    GNUNET_JSON_parse_free (spec); -    GNUNET_break_op (0); -    return GNUNET_NO; -  } -  for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) -  { -    struct GNUNET_JSON_Specification spec[] = { -      GNUNET_JSON_spec_fixed_auto ("transfer_priv", -                                   &mc->transfer_priv[i]), -      GNUNET_JSON_spec_end () -    }; - -    if (GNUNET_OK != -        GNUNET_JSON_parse (json_array_get (trans_privs, -                                           i), -                           spec, -                           NULL, NULL)) -    { -      GNUNET_break_op (0); -      GNUNET_JSON_parse_free (spec); -      return GNUNET_NO; -    } -  } -  json_decref (trans_privs); -  return GNUNET_OK; -} - - -/** - * Serialize melt data. - * - * @param md data to serialize - * @return serialized melt data - */ -static json_t * -serialize_melt_data (const struct MeltData *md) -{ -  json_t *fresh_coins; - -  fresh_coins = json_array (); -  GNUNET_assert (NULL != fresh_coins); -  for (int i = 0; i<md->num_fresh_coins; i++) -  { -    json_t *planchet_secrets; - -    planchet_secrets = json_array (); -    GNUNET_assert (NULL != planchet_secrets); -    for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++) -    { -      json_t *ps; - -      ps = GNUNET_JSON_PACK ( -        GNUNET_JSON_pack_data_auto ("ps", -                                    &md->fresh_coins[j][i])); -      GNUNET_assert (0 == -                     json_array_append_new (planchet_secrets, -                                            ps)); -    } -    GNUNET_assert (0 == -                   json_array_append_new ( -                     fresh_coins, -                     GNUNET_JSON_PACK ( -                       TALER_JSON_pack_denom_pub ("denom_pub", -                                                  &md->fresh_pks[i]), -                       GNUNET_JSON_pack_array_steal ("planchet_secrets", -                                                     planchet_secrets))) -                   ); -  } -  return GNUNET_JSON_PACK ( -    GNUNET_JSON_pack_array_steal ("fresh_coins", -                                  fresh_coins), -    GNUNET_JSON_pack_object_steal ("melted_coin", -                                   serialize_melted_coin (&md->melted_coin)), -    GNUNET_JSON_pack_data_auto ("rc", -                                &md->rc)); -} - - -struct MeltData * -TALER_EXCHANGE_deserialize_melt_data_ (const json_t *melt_data, -                                       const char *currency) -{ -  struct MeltData *md = GNUNET_new (struct MeltData); -  json_t *fresh_coins; -  json_t *melted_coin; -  struct GNUNET_JSON_Specification spec[] = { -    GNUNET_JSON_spec_fixed_auto ("rc", -                                 &md->rc), -    GNUNET_JSON_spec_json ("melted_coin", -                           &melted_coin), -    GNUNET_JSON_spec_json ("fresh_coins", -                           &fresh_coins), -    GNUNET_JSON_spec_end () -  }; -  bool ok; - -  if (GNUNET_OK != -      GNUNET_JSON_parse (melt_data, -                         spec, -                         NULL, NULL)) -  { -    GNUNET_break (0); -    GNUNET_JSON_parse_free (spec); -    GNUNET_free (md); -    return NULL; -  } -  if (! (json_is_array (fresh_coins) && -         json_is_object (melted_coin)) ) -  { -    GNUNET_break (0); -    GNUNET_JSON_parse_free (spec); -    return NULL; -  } -  if (GNUNET_OK != -      deserialize_melted_coin (&md->melted_coin, -                               currency, -                               melted_coin)) -  { -    GNUNET_break (0); -    GNUNET_JSON_parse_free (spec); -    return NULL; -  } -  md->num_fresh_coins = json_array_size (fresh_coins); -  md->fresh_pks = GNUNET_new_array (md->num_fresh_coins, -                                    struct TALER_DenominationPublicKey); -  for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++) -    md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins, -                                           struct TALER_PlanchetSecretsP); -  ok = true; -  for (unsigned int i = 0; i<md->num_fresh_coins; i++) -  { -    const json_t *ji = json_array_get (fresh_coins, -                                       i); -    json_t *planchet_secrets; -    struct GNUNET_JSON_Specification ispec[] = { -      GNUNET_JSON_spec_json ("planchet_secrets", -                             &planchet_secrets), -      TALER_JSON_spec_denom_pub ("denom_pub", -                                 &md->fresh_pks[i]), -      GNUNET_JSON_spec_end () -    }; - -    if (GNUNET_OK != -        GNUNET_JSON_parse (ji, -                           ispec, -                           NULL, NULL)) -    { -      GNUNET_break (0); -      ok = false; -      break; -    } -    if ( (! json_is_array (planchet_secrets)) || -         (TALER_CNC_KAPPA != json_array_size (planchet_secrets)) ) -    { -      GNUNET_break (0); -      ok = false; -      GNUNET_JSON_parse_free (ispec); -      break; -    } -    for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++) -    { -      struct GNUNET_JSON_Specification jspec[] = { -        GNUNET_JSON_spec_fixed_auto ("ps", -                                     &md->fresh_coins[j][i]), -        GNUNET_JSON_spec_end () -      }; - -      if (GNUNET_OK != -          GNUNET_JSON_parse (json_array_get (planchet_secrets, -                                             j), -                             jspec, -                             NULL, NULL)) -      { -        GNUNET_break (0); -        ok = false; -        break; -      } -    } -    json_decref (planchet_secrets); -    if (! ok) -      break; -  } - -  GNUNET_JSON_parse_free (spec); -  if (! ok) -  { -    TALER_EXCHANGE_free_melt_data_ (md); -    GNUNET_free (md); -    return NULL; -  } -  return md; -} - - -json_t * -TALER_EXCHANGE_refresh_prepare ( -  const struct TALER_CoinSpendPrivateKeyP *melt_priv, -  const struct TALER_Amount *melt_amount, -  const struct TALER_DenominationSignature *melt_sig, -  const struct TALER_EXCHANGE_DenomPublicKey *melt_pk, -  unsigned int fresh_pks_len, -  const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks) +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_get_melt_data_ ( +  const struct TALER_PlanchetSecretsP *ps, +  const struct struct TALER_EXCHANGE_RefreshData *rd, +  const struct TALER_ExchangeWithdrawValues *alg_values, +  struct MeltData *md)  {    struct MeltData md;    json_t *ret; @@ -359,68 +62,68 @@ TALER_EXCHANGE_refresh_prepare (    memset (&md,            0,            sizeof (md)); -  md.num_fresh_coins = fresh_pks_len; -  md.melted_coin.coin_priv = *melt_priv; -  md.melted_coin.melt_amount_with_fee = *melt_amount; -  md.melted_coin.fee_melt = melt_pk->fee_refresh; -  md.melted_coin.original_value = melt_pk->value; -  md.melted_coin.expire_deposit -    = melt_pk->expire_deposit; +  md.num_fresh_coins = rd->fresh_pks_len; +  md.melted_coin.coin_priv = rd->melt_priv; +  md.melted_coin.melt_amount_with_fee = rd->melt_amount; +  md.melted_coin.fee_melt = rd->melt_pk->fee_refresh; +  md.melted_coin.original_value = rd->melt_pk->value; +  md.melted_coin.expire_deposit = rd->melt_pk->expire_deposit;    GNUNET_assert (GNUNET_OK ==                   TALER_amount_set_zero (melt_amount->currency,                                          &total));    TALER_denom_pub_deep_copy (&md.melted_coin.pub_key, -                             &melt_pk->key); +                             &rd->melt_pk->key);    TALER_denom_sig_deep_copy (&md.melted_coin.sig, -                             melt_sig); -  md.fresh_pks = GNUNET_new_array (fresh_pks_len, +                             rd->melt_sig); +  md.fresh_pks = GNUNET_new_array (rd->fresh_pks_len,                                     struct TALER_DenominationPublicKey); -  for (unsigned int i = 0; i<fresh_pks_len; i++) +  for (unsigned int i = 0; i<rd->fresh_pks_len; i++)    {      TALER_denom_pub_deep_copy (&md.fresh_pks[i],                                 &fresh_pks[i].key);      if ( (0 >            TALER_amount_add (&total,                              &total, -                            &fresh_pks[i].value)) || +                            &rd->fresh_pks[i].value)) ||           (0 >            TALER_amount_add (&total,                              &total, -                            &fresh_pks[i].fee_withdraw)) ) +                            &rd->fresh_pks[i].fee_withdraw)) )      {        GNUNET_break (0);        TALER_EXCHANGE_free_melt_data_ (&md); -      return NULL; +      return GNUNET_SYSERR;      }    }    /* verify that melt_amount is above total cost */    if (1 ==        TALER_amount_cmp (&total, -                        melt_amount) ) +                        rd->melt_amount) )    {      /* Eh, this operation is more expensive than the         @a melt_amount. This is not OK. */      GNUNET_break (0);      TALER_EXCHANGE_free_melt_data_ (&md); -    return NULL; +    return GNUNET_SYSERR;    }    /* build up coins */    for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)    { +    // FIXME: derive!      GNUNET_CRYPTO_ecdhe_key_create (        &md.melted_coin.transfer_priv[i].ecdhe_priv);      GNUNET_CRYPTO_ecdhe_key_get_public (        &md.melted_coin.transfer_priv[i].ecdhe_priv,        &rce[i].transfer_pub.ecdhe_pub); -    TALER_link_derive_transfer_secret  (melt_priv, -                                        &md.melted_coin.transfer_priv[i], -                                        &trans_sec[i]); -    md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len, +    TALER_link_derive_transfer_secret (&rd->melt_priv, +                                       &md.melted_coin.transfer_priv[i], +                                       &trans_sec[i]); +    md.fresh_coins[i] = GNUNET_new_array (rd->fresh_pks_len,                                            struct TALER_PlanchetSecretsP); -    rce[i].new_coins = GNUNET_new_array (fresh_pks_len, +    rce[i].new_coins = GNUNET_new_array (rd->fresh_pks_len,                                           struct TALER_RefreshCoinData); -    for (unsigned int j = 0; j<fresh_pks_len; j++) +    for (unsigned int j = 0; j<rd->fresh_pks_len; j++)      {        struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j];        struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j]; @@ -458,15 +161,12 @@ TALER_EXCHANGE_refresh_prepare (                                  fresh_pks_len,                                  rce,                                  &coin_pub, -                                melt_amount); -  /* finally, serialize everything */ -  ret = serialize_melt_data (&md); +                                &rd->melt_amount);    for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)    {      for (unsigned int j = 0; j < fresh_pks_len; j++)        GNUNET_free (rce[i].new_coins[j].coin_ev);      GNUNET_free (rce[i].new_coins);    } -  TALER_EXCHANGE_free_melt_data_ (&md); -  return ret; +  return GNUNET_OK;  } diff --git a/src/lib/exchange_api_refresh_common.h b/src/lib/exchange_api_refresh_common.h index 1c037d96..653d4886 100644 --- a/src/lib/exchange_api_refresh_common.h +++ b/src/lib/exchange_api_refresh_common.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015-2020 Taler Systems SA +  Copyright (C) 2015-2022 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 @@ -103,6 +103,12 @@ struct MeltData    struct TALER_DenominationPublicKey *fresh_pks;    /** +   * Array of @e num_fresh_coins with exchange contributions +   * made during the refresh. +   */ +  struct TALER_ExchangeWithdrawValues *exchange_vals; + +  /**     * Arrays of @e num_fresh_coins with information about the fresh     * coins to be created, for each cut-and-choose dimension.     */ @@ -111,15 +117,19 @@ struct MeltData  /** - * Deserialize melt data. + * Compute the melt data from the refresh data and secret.   * - * @param data json data to deserialize - * @param currency expected currency for the coins - * @return deserialized melt data, NULL on error + * @param ps secret internals of the refresh-reveal operation + * @param rd refresh data with the characteristics of the operation + * @param alg_values contributions from the exchange into the melt + * @param[out] rd where to write the derived melt data   */ -struct MeltData * -TALER_EXCHANGE_deserialize_melt_data_ (const json_t *data, -                                       const char *currency); +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_get_melt_data_ ( +  const struct TALER_PlanchetSecretsP *ps, +  const struct struct TALER_EXCHANGE_RefreshData *rd, +  const struct TALER_ExchangeWithdrawValues *alg_values, +  struct MeltData *md);  /** diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c index 82f92322..cdfb5140 100644 --- a/src/lib/exchange_api_refreshes_reveal.c +++ b/src/lib/exchange_api_refreshes_reveal.c @@ -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. @@ -95,12 +95,14 @@ struct TALER_EXCHANGE_RefreshesRevealHandle   *   * @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] sigs array of length `num_fresh_coins`, initialized to contain the coin private keys + * @param[out] sigs array of length `num_fresh_coins`, initialized to contain signatures   * @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_CoinSpendPrivateKeyP *coin_privs,                     struct TALER_DenominationSignature *sigs)  {    json_t *jsona; @@ -165,6 +167,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,      /* needed to verify the signature, and we didn't store it earlier,         hence recomputing it here... */ +    coin_privs[i] = fc->coin_priv;      GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,                                          &coin_pub.eddsa_pub);      /* FIXME-Oec: Age commitment hash. */ @@ -223,13 +226,15 @@ handle_refresh_reveal_finished (void *cls,    case MHD_HTTP_OK:      {        struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins]; -      int ret; +      struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins]; +      enum GNUNET_GenericReturnValue ret;        memset (sigs,                0,                sizeof (sigs));        ret = refresh_reveal_ok (rrh,                                 j, +                               coin_privs,                                 sigs);        if (GNUNET_OK != ret)        { @@ -241,7 +246,7 @@ handle_refresh_reveal_finished (void *cls,          rrh->reveal_cb (rrh->reveal_cb_cls,                          &hr,                          rrh->md->num_fresh_coins, -                        rrh->md->fresh_coins[rrh->noreveal_index], +                        coin_privs,                          sigs);          rrh->reveal_cb = NULL;        } @@ -298,7 +303,10 @@ handle_refresh_reveal_finished (void *cls,  struct TALER_EXCHANGE_RefreshesRevealHandle *  TALER_EXCHANGE_refreshes_reveal (    struct TALER_EXCHANGE_Handle *exchange, -  const json_t *refresh_data, +  const struct TALER_PlanchetSecretsP *ps, +  const struct TALER_EXCHANGE_RefreshData *rd, +  unsigned int num_coins, +  const struct TALER_ExchangeWithdrawValues *alg_values,    uint32_t noreveal_index,    TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,    void *reveal_cb_cls) @@ -311,10 +319,11 @@ TALER_EXCHANGE_refreshes_reveal (    json_t *link_sigs;    CURL *eh;    struct GNUNET_CURL_Context *ctx; -  struct MeltData *md; +  struct MeltData md;    struct TALER_TransferPublicKeyP transfer_pub;    char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32]; +  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 @@ -330,9 +339,11 @@ TALER_EXCHANGE_refreshes_reveal (      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_ (ps, +                                     rd, +                                     alg_values, +                                     &md))    {      GNUNET_break (0);      return NULL; @@ -340,33 +351,31 @@ TALER_EXCHANGE_refreshes_reveal (    /* now transfer_pub */    GNUNET_CRYPTO_ecdhe_key_get_public ( -    &md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv, +    &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_ExchangeWithdrawValues alg_values;      struct TALER_PlanchetDetail pd;      struct TALER_CoinPubHash c_hash; -    TALER_denom_pub_hash (&md->fresh_pks[i], +    TALER_denom_pub_hash (&md.fresh_pks[i],                            &denom_hash);      GNUNET_assert (0 ==                     json_array_append_new (new_denoms_h,                                            GNUNET_JSON_from_data_auto (                                              &denom_hash))); -    // TODO: implement cipher handling -    alg_values.cipher = TALER_DENOMINATION_RSA;      if (GNUNET_OK != -        TALER_planchet_prepare (&md->fresh_pks[i], -                                &alg_values, -                                &md->fresh_coins[noreveal_index][i], +        TALER_planchet_prepare (&md.fresh_pks[i], +                                &rrh->exchange_vals[i], +                                &md.fresh_coins[noreveal_index][i],                                  &c_hash,                                  &pd))      { @@ -374,6 +383,7 @@ TALER_EXCHANGE_refreshes_reveal (        GNUNET_break (0);        json_decref (new_denoms_h);        json_decref (coin_evs); +      TALER_EXCHANGE_free_melt_data_ (&md);        return NULL;      }      GNUNET_assert (0 == @@ -394,7 +404,7 @@ TALER_EXCHANGE_refreshes_reveal (                                blinded_msg,                                pd.blinded_planchet.details.rsa_blinded_planchet.                                blinded_msg_size, -                              &md->melted_coin.coin_priv, +                              &md.melted_coin.coin_priv,                                &link_sig);        GNUNET_assert (0 ==                       json_array_append_new ( @@ -417,7 +427,7 @@ TALER_EXCHANGE_refreshes_reveal (      GNUNET_assert (0 ==                     json_array_append_new (transfer_privs,                                            GNUNET_JSON_from_data_auto ( -                                            &md->melted_coin.transfer_priv[j]))); +                                            &md.melted_coin.transfer_priv[j])));    }    /* build main JSON request */ @@ -436,9 +446,8 @@ 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'; @@ -459,6 +468,7 @@ TALER_EXCHANGE_refreshes_reveal (    if (NULL == rrh->url)    {      json_decref (reveal_obj); +    TALER_EXCHANGE_free_melt_data_ (&md);      GNUNET_free (rrh);      return NULL;    } @@ -473,6 +483,7 @@ TALER_EXCHANGE_refreshes_reveal (      if (NULL != eh)        curl_easy_cleanup (eh);      json_decref (reveal_obj); +    TALER_EXCHANGE_free_melt_data_ (&md);      GNUNET_free (rrh->url);      GNUNET_free (rrh);      return NULL; @@ -499,8 +510,8 @@ TALER_EXCHANGE_refreshes_reveal_cancel (    }    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->exchange_vals);    GNUNET_free (rrh);  }  | 
