diff --git a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c index 4aa238dfd..e1f4fdb75 100644 --- a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c +++ b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c @@ -71,7 +71,7 @@ struct AgeRevealContext * The data from the original age-withdraw. Will be retrieved from * the DB via @a ach and @a reserve_pub. */ - struct TALER_EXCHANGEDB_AgeWithdraw *commitment; + struct TALER_EXCHANGEDB_AgeWithdraw commitment; }; @@ -106,11 +106,8 @@ parse_age_withdraw_reveal_json ( error = "disclosed_coin_secrets must be an array"; else if (num_entries == 0) error = "disclosed_coin_secrets must not be empty"; - else if (num_entries > TALER_MAX_FRESH_COINS * (TALER_CNC_KAPPA - 1)) + else if (num_entries > TALER_MAX_FRESH_COINS) error = "maximum number of coins that can be withdrawn has been exceeded"; - else if (0 != num_entries % (TALER_CNC_KAPPA - 1)) - error = "the size of disclosed_coin_secrets must be a multiple of " - TALER_CNC_KAPPA_MINUS_ONE_STR; if (NULL != error) { @@ -120,29 +117,26 @@ parse_age_withdraw_reveal_json ( return GNUNET_SYSERR; } - actx->num_secrets = num_entries; - actx->num_coins = num_entries / (TALER_CNC_KAPPA - 1); + actx->num_secrets = num_entries * (TALER_CNC_KAPPA - 1); + actx->num_coins = num_entries; } /* Continue parsing the parts */ { unsigned int idx = 0; + unsigned int k = 0; + json_t *array = NULL; json_t *value = NULL; /* Parse diclosed keys */ actx->disclosed_coin_secrets = - GNUNET_new_array (num_entries, + GNUNET_new_array (actx->num_secrets, struct TALER_PlanchetMasterSecretP); - json_array_foreach (j_disclosed_coin_secrets, idx, value) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto (NULL, &actx->disclosed_coin_secrets[idx]), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (value, spec, NULL, NULL)) + json_array_foreach (j_disclosed_coin_secrets, idx, array) { + if (! json_is_array (array) || + (TALER_CNC_KAPPA - 1 != json_array_size (array))) { char msg[256] = {0}; GNUNET_snprintf (msg, @@ -153,6 +147,32 @@ parse_age_withdraw_reveal_json ( TALER_EC_GENERIC_PARAMETER_MALFORMED, msg); goto EXIT; + + } + + json_array_foreach (array, k, value) + { + struct TALER_PlanchetMasterSecretP *sec = + &actx->disclosed_coin_secrets[2 * idx + k]; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, sec), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (value, spec, NULL, NULL)) + { + char msg[256] = {0}; + GNUNET_snprintf (msg, + sizeof(msg), + "couldn't parse entry no. %d in array disclosed_coin_secrets[%d]", + k + 1, + idx + 1); + *mhd_ret = TALER_MHD_reply_with_ec (connection, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + msg); + goto EXIT; + } } }; } @@ -182,7 +202,7 @@ find_original_commitment ( struct MHD_Connection *connection, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_ReservePublicKeyP *reserve_pub, - struct TALER_EXCHANGEDB_AgeWithdraw **commitment, + struct TALER_EXCHANGEDB_AgeWithdraw *commitment, MHD_RESULT *result) { enum GNUNET_DB_QueryStatus qs; @@ -192,7 +212,7 @@ find_original_commitment ( qs = TEH_plugin->get_age_withdraw (TEH_plugin->cls, reserve_pub, h_commitment, - *commitment); + commitment); switch (qs) { case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: @@ -262,7 +282,13 @@ calculate_blinded_hash ( connection, result); if (NULL == denom_key) + { + GNUNET_break_op (0); + *result = TALER_MHD_reply_with_ec (connection, + TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, + NULL); return GNUNET_SYSERR; + } /* calculate age commitment hash */ { @@ -351,7 +377,7 @@ calculate_blinded_hash ( GNUNET_assert (GNUNET_OK == ret); } - return GNUNET_SYSERR; + return ret; } @@ -417,9 +443,9 @@ verify_commitment_and_max_age ( { size_t i = 0; /* either 0 or 1, to index into coin_evs */ - for (size_t gamma = 0; gammanoreveal_index) + if (k == (size_t) commitment->noreveal_index) { GNUNET_CRYPTO_hash_context_read (hash_context, &commitment->h_coin_evs[coin_idx], @@ -432,7 +458,7 @@ verify_commitment_and_max_age ( const struct TALER_PlanchetMasterSecretP *secret; struct TALER_BlindedCoinHashP bch; - GNUNET_assert (i<2); + GNUNET_assert (2>i); GNUNET_assert ((TALER_CNC_KAPPA - 1) * num_coins > j); secret = &disclosed_coin_secrets[j]; @@ -478,7 +504,6 @@ verify_commitment_and_max_age ( } } - return ret; } @@ -572,7 +597,7 @@ TEH_handler_age_withdraw_reveal ( if (GNUNET_OK != verify_commitment_and_max_age ( rc->connection, - actx.commitment, + &actx.commitment, actx.disclosed_coin_secrets, actx.num_coins, &result)) @@ -580,7 +605,7 @@ TEH_handler_age_withdraw_reveal ( /* Finally, return the signatures */ result = reply_age_withdraw_reveal_success (rc->connection, - actx.commitment); + &actx.commitment); } while(0); diff --git a/src/exchangedb/0003-age_withdraw.sql b/src/exchangedb/0003-age_withdraw.sql index 1d296b057..9816e466c 100644 --- a/src/exchangedb/0003-age_withdraw.sql +++ b/src/exchangedb/0003-age_withdraw.sql @@ -29,6 +29,8 @@ BEGIN '(age_withdraw_id BIGINT GENERATED BY DEFAULT AS IDENTITY' ',h_commitment BYTEA NOT NULL CONSTRAINT h_commitment_length CHECK(LENGTH(h_commitment)=64)' ',max_age SMALLINT NOT NULL CONSTRAINT max_age_positive CHECK(max_age>=0)' + ',amount_with_fee_val INT8 NOT NULL' + ',amount_with_fee_frac INT4 NOT NULL' ',reserve_pub BYTEA NOT NULL CONSTRAINT reserve_pub_length CHECK(LENGTH(reserve_pub)=32)' ',reserve_sig BYTEA NOT NULL CONSTRAINT reserve_sig_length CHECK(LENGTH(reserve_sig)=64)' ',noreveal_index SMALLINT NOT NULL CONSTRAINT noreveal_index_positive CHECK(noreveal_index>=0)' diff --git a/src/exchangedb/exchange_do_age_withdraw.sql b/src/exchangedb/exchange_do_age_withdraw.sql index 2230d4bff..49a1433fd 100644 --- a/src/exchangedb/exchange_do_age_withdraw.sql +++ b/src/exchangedb/exchange_do_age_withdraw.sql @@ -143,6 +143,8 @@ WHERE INSERT INTO exchange.age_withdraw (h_commitment ,max_age + ,amount_with_fee_val + ,amount_with_fee_frac ,reserve_pub ,reserve_sig ,noreveal_index @@ -152,6 +154,8 @@ INSERT INTO exchange.age_withdraw VALUES (h_commitment ,maximum_age_committed + ,amount_val + ,amount_frac ,rpub ,rsig ,noreveal_index diff --git a/src/exchangedb/pg_do_age_withdraw.c b/src/exchangedb/pg_do_age_withdraw.c index c79b2b3de..4fb52d466 100644 --- a/src/exchangedb/pg_do_age_withdraw.c +++ b/src/exchangedb/pg_do_age_withdraw.c @@ -52,15 +52,15 @@ TEH_PG_do_age_withdraw ( GNUNET_PQ_query_param_auto_from_type (&commitment->h_commitment), GNUNET_PQ_query_param_uint16 (&commitment->max_age), GNUNET_PQ_query_param_uint16 (&commitment->noreveal_index), - GNUNET_PQ_query_param_array_auto_from_type (commitment->num_coins, - commitment->h_coin_evs, - pg->conn), + TALER_PQ_query_param_array_blinded_coin_hash (commitment->num_coins, + commitment->h_coin_evs, + pg->conn), GNUNET_PQ_query_param_array_uint64 (commitment->num_coins, commitment->denom_serials, pg->conn), - GNUNET_PQ_query_param_array_auto_from_type (commitment->num_coins, - commitment->denom_sigs, - pg->conn), + TALER_PQ_query_param_array_blinded_denom_sig (commitment->num_coins, + commitment->denom_sigs, + pg->conn), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { diff --git a/src/exchangedb/pg_get_age_withdraw.c b/src/exchangedb/pg_get_age_withdraw.c index 5e123ca9a..a66051c71 100644 --- a/src/exchangedb/pg_get_age_withdraw.c +++ b/src/exchangedb/pg_get_age_withdraw.c @@ -52,27 +52,26 @@ TEH_PG_get_age_withdraw ( &aw->amount_with_fee), GNUNET_PQ_result_spec_uint16 ("noreveal_index", &aw->noreveal_index), - GNUNET_PQ_result_spec_array_fixed_size ( + TALER_PQ_result_spec_array_blinded_coin_hash ( pg->conn, - "h_coin_evs", - sizeof(struct TALER_BlindedPlanchet), + "h_blind_evs", &aw->num_coins, - (void **) &aw->h_coin_evs), - GNUNET_PQ_result_spec_array_fixed_size ( + &aw->h_coin_evs), + TALER_PQ_result_spec_array_blinded_denom_sig ( pg->conn, "denom_sigs", - sizeof(struct TALER_DenominationSignature), - NULL, - (void **) &aw->denom_sigs), - GNUNET_PQ_result_spec_array_fixed_size ( + NULL, /* we assume that this is the same size as h_coin_evs */ + &aw->denom_sigs), + TALER_PQ_result_spec_array_denom_hash ( pg->conn, "denom_pub_hashes", - sizeof(struct TALER_DenominationHashP), - NULL, - (void **) &aw->denom_pub_hashes), + NULL, /* we assume that this is the same size as h_coin_evs */ + &aw->denom_pub_hashes), GNUNET_PQ_result_spec_end }; + GNUNET_assert (NULL != aw); + /* Used in #postgres_get_age_withdraw() to locate the response for a /reserve/$RESERVE_PUB/age-withdraw request using the hash of the blinded message. Also needed to ensure @@ -87,12 +86,12 @@ TEH_PG_get_age_withdraw ( ",amount_with_fee_val" ",amount_with_fee_frac" ",noreveal_index" - ",h_coin_evs" + ",h_blind_evs" ",denom_sigs" ",ARRAY(" " SELECT denominations.denom_pub_hash FROM (" - " SELECT UNNEST(denomination_serials) AS id," - " generate_subscripts(denominations_serials, 1) AS nr" /* for order */ + " SELECT UNNEST(denom_serials) AS id," + " generate_subscripts(denom_serials, 1) AS nr" /* for order */ " ) AS denoms" " LEFT JOIN denominations ON denominations.denominations_serial=denoms.id" ") AS denom_pub_hashes" diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index e8d789162..29fc005e8 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3066,6 +3066,7 @@ typedef void * @param coin_inputs The input for the coins to withdraw, same as in the previous call to /age-withdraw * @param noreveal_index The index into each of the kappa coin candidates, that should not be revealed to the exchange * @param h_commitment The commmitment from the previous call to /age-withdraw + * @param reserve_pub The public key of the reserve the original call to /age-withdraw was made to * @param res_cb A callback for the result, maybe NULL * @param res_cb_cls A closure for @e res_cb, maybe NULL * @return a handle for this request; NULL if the argument was invalid. @@ -3080,6 +3081,7 @@ TALER_EXCHANGE_age_withdraw_reveal ( num_coins], uint8_t noreveal_index, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + const struct TALER_ReservePublicKeyP *reserve_pub, TALER_EXCHANGE_AgeWithdrawRevealCallback res_cb, void *res_cb_cls); diff --git a/src/lib/exchange_api_age_withdraw_reveal.c b/src/lib/exchange_api_age_withdraw_reveal.c index 75707a4e4..1e804bc84 100644 --- a/src/lib/exchange_api_age_withdraw_reveal.c +++ b/src/lib/exchange_api_age_withdraw_reveal.c @@ -47,6 +47,9 @@ struct TALER_EXCHANGE_AgeWithdrawRevealHandle /* The age-withdraw commitment */ struct TALER_AgeWithdrawCommitmentHashP h_commitment; + /* The reserve's public key */ + const struct TALER_ReservePublicKeyP *reserve_pub; + /* Number of coins */ size_t num_coins; @@ -231,7 +234,7 @@ handle_age_withdraw_reveal_finished ( break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, the exchange basically just says - that it doesn't know this age-withraw commitment. */ + that it doesn't know this age-withdraw commitment. */ awr.hr.ec = TALER_JSON_get_error_code (j_response); awr.hr.hint = TALER_JSON_get_error_hint (j_response); break; @@ -299,7 +302,7 @@ prepare_url ( *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "age-withraw/%s/reveal", + "age-withdraw/%s/reveal", pub_str); awrh->request_url = TALER_url_join (exchange_url, @@ -343,6 +346,9 @@ perform_protocol ( } \ } while(0) + j_array_of_secrets = json_array (); + FAIL_IF (NULL == j_array_of_secrets); + for (size_t n = 0; n < awrh->num_coins; n++) { const struct TALER_PlanchetMasterSecretP *secrets = @@ -369,6 +375,8 @@ perform_protocol ( j_secrets)); } j_request_body = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("reserve_pub", + awrh->reserve_pub), GNUNET_JSON_pack_array_steal ("disclosed_coin_secrets", j_array_of_secrets)); FAIL_IF (NULL == j_request_body); @@ -418,6 +426,7 @@ TALER_EXCHANGE_age_withdraw_reveal ( num_coins], uint8_t noreveal_index, const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + const struct TALER_ReservePublicKeyP *reserve_pub, TALER_EXCHANGE_AgeWithdrawRevealCallback reveal_cb, void *reveal_cb_cls) { @@ -429,6 +438,7 @@ TALER_EXCHANGE_age_withdraw_reveal ( awrh->coins_input = coins_input; awrh->callback = reveal_cb; awrh->callback_cls = reveal_cb_cls; + awrh->reserve_pub = reserve_pub; if (GNUNET_OK != prepare_url (exchange_url, diff --git a/src/testing/test_exchange_api_age_restriction.c b/src/testing/test_exchange_api_age_restriction.c index 56e46b22a..cdfb58e2f 100644 --- a/src/testing/test_exchange_api_age_restriction.c +++ b/src/testing/test_exchange_api_age_restriction.c @@ -290,7 +290,7 @@ run (void *cls, MHD_HTTP_CONFLICT, "EUR:10", NULL), - TALER_TESTING_cmd_age_withdraw ("age-withdraw-coin-1", + TALER_TESTING_cmd_age_withdraw ("age-withdraw-coins-1", "create-reserve-kyc-1", 8, MHD_HTTP_OK, @@ -298,6 +298,10 @@ run (void *cls, "EUR:5", "EUR:5", NULL), + /* FIXME[oec]: failing */ + TALER_TESTING_cmd_age_withdraw_reveal ("age-withdraw-coins-reveal-1", + "age-withdraw-coins-1", + MHD_HTTP_OK), TALER_TESTING_cmd_end (), }; diff --git a/src/testing/testing_api_cmd_age_withdraw.c b/src/testing/testing_api_cmd_age_withdraw.c index 98a5e1d85..8849cd313 100644 --- a/src/testing/testing_api_cmd_age_withdraw.c +++ b/src/testing/testing_api_cmd_age_withdraw.c @@ -629,8 +629,8 @@ age_withdraw_reveal_run ( * Get the command and state for the previous call to "age witdraw" */ age_withdraw_cmd = - TALER_TESTING_interpreter_get_command (is, - awrs->age_withdraw_reference); + TALER_TESTING_interpreter_lookup_command (is, + awrs->age_withdraw_reference); if (NULL == age_withdraw_cmd) { GNUNET_break (0); @@ -649,6 +649,7 @@ age_withdraw_reveal_run ( aws->coin_inputs, aws->noreveal_index, &aws->h_commitment, + &aws->reserve_pub, age_withdraw_reveal_cb, awrs); }