donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 7bbe26d72edb5c2f64aac77dbd437c6e7c6080cd
parent dbf3f42140ee5c0a5c00656697e45c397a49c9bf
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 23 Sep 2025 16:47:28 +0200

switch to 32-byte nonces, fixes #10450

Diffstat:
Msrc/donau/donau-httpd_batch-submit.c | 5+++--
Msrc/donau/test_donau_httpd.conf | 16++++++++--------
Msrc/donaudb/0002-donau_receipts_submitted.sql | 2+-
Msrc/donaudb/donau_do_insert_submitted_receipts.sql | 8+++++---
Msrc/donaudb/pg_insert_submitted_receipts.c | 13++++++-------
Msrc/include/donau_crypto_lib.h | 4++--
Msrc/testing/test_donau_api.conf | 3+--
Msrc/testing/testing_api_cmd_issue_receipts.c | 198+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/util/donau-secmod-cs.c | 3++-
9 files changed, 132 insertions(+), 120 deletions(-)

diff --git a/src/donau/donau-httpd_batch-submit.c b/src/donau/donau-httpd_batch-submit.c @@ -154,8 +154,9 @@ DH_handler_submit_receipts_post (struct DH_RequestContext *rc, /* Check nonce unique*/ for (size_t j = i + 1; j < num_dr; j++) { - if (irc.donation_receipts[i].nonce.value == - irc.donation_receipts[j].nonce.value) + if (0 == + GNUNET_memcmp (&irc.donation_receipts[i].nonce, + &irc.donation_receipts[j].nonce)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Donation receipt nonce is not unique!\n"); diff --git a/src/donau/test_donau_httpd.conf b/src/donau/test_donau_httpd.conf @@ -10,7 +10,7 @@ CURRENCY_ROUND_UNIT = EUR:0.01 SERVE = tcp # Base url of the Donau -DOMAIN = "Bern" +LEGAL_DOMAIN = "Bern" BASE_URL = "http://localhost:8080/" # Directory with our terms of service. @@ -57,8 +57,8 @@ IDLE_RESERVE_EXPIRATION_TIME = 4 weeks [donaudb-postgres] CONFIG = "postgres:///donaucheck" -# Coins for the tests. -[coin_eur_ct_1_rsa] +# Docos for the tests. +[doco_eur_ct_1_rsa] value = EUR:0.01 duration_withdraw = 1 year duration_spend = 2 years @@ -70,7 +70,7 @@ fee_refund = EUR:0.01 CIPHER = RSA rsa_keysize = 1024 -[coin_eur_ct_1_cs] +[doco_eur_ct_1_cs] value = EUR:0.01 duration_withdraw = 1 year duration_spend = 2 years @@ -81,7 +81,7 @@ fee_refresh = EUR:0.01 fee_refund = EUR:0.01 CIPHER = CS -[coin_eur_ct_10_rsa] +[doco_eur_ct_10_rsa] value = EUR:0.10 duration_withdraw = 1 year duration_spend = 2 years @@ -93,7 +93,7 @@ fee_refund = EUR:0.01 CIPHER = RSA rsa_keysize = 1024 -[coin_eur_ct_10_cs] +[doco_eur_ct_10_cs] value = EUR:0.10 duration_withdraw = 1 year duration_spend = 2 years @@ -104,7 +104,7 @@ fee_refresh = EUR:0.03 fee_refund = EUR:0.01 CIPHER = CS -[coin_eur_1_rsa] +[doco_eur_1_rsa] value = EUR:1 duration_withdraw = 1 year duration_spend = 2 years @@ -116,7 +116,7 @@ fee_refund = EUR:0.01 CIPHER = RSA rsa_keysize = 1024 -[coin_eur_1_cs] +[doco_eur_1_cs] value = EUR:1 duration_withdraw = 1 year duration_spend = 2 years diff --git a/src/donaudb/0002-donau_receipts_submitted.sql b/src/donaudb/0002-donau_receipts_submitted.sql @@ -17,7 +17,7 @@ CREATE TABLE receipts_submitted (receipt_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE ,h_tax_number BYTEA NOT NULL - ,nonce INT4 NOT NULL UNIQUE + ,nonce BYTEA NOT NULL UNIQUE CHECK (LENGTH(nonce)=32) ,h_donation_unit_pub BYTEA NOT NULL REFERENCES donation_units (h_donation_unit_pub) ,donation_unit_sig BYTEA NOT NULL UNIQUE ,donation_year INT8 NOT NULL diff --git a/src/donaudb/donau_do_insert_submitted_receipts.sql b/src/donaudb/donau_do_insert_submitted_receipts.sql @@ -13,10 +13,12 @@ -- You should have received a copy of the GNU General Public License along with -- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -- -CREATE OR REPLACE FUNCTION do_insert_submitted_receipts( + +DROP FUNCTION IF EXISTS do_insert_submitted_receipts; +CREATE FUNCTION do_insert_submitted_receipts( IN in_h_tax_number BYTEA, IN ina_h_donation_unit_pubs BYTEA[], - IN ina_nonces INT4[], + IN ina_nonces BYTEA[], IN ina_donation_unit_sigs BYTEA[], IN in_donation_year INT8, -- @@ -26,7 +28,7 @@ LANGUAGE plpgsql AS $$ DECLARE i INT4; - ini_nonce INT4; + ini_nonce BYTEA; ini_h_donation_unit_pub BYTEA; ini_donation_unit_sig BYTEA; BEGIN diff --git a/src/donaudb/pg_insert_submitted_receipts.c b/src/donaudb/pg_insert_submitted_receipts.c @@ -27,6 +27,7 @@ #include "donau_service.h" #include "donau_pq_lib.h" + enum GNUNET_DB_QueryStatus DH_PG_insert_submitted_receipts ( void *cls, @@ -37,16 +38,16 @@ DH_PG_insert_submitted_receipts ( { struct PostgresClosure *pg = cls; struct GNUNET_HashCode h_donation_unit_pubs[GNUNET_NZL (num_dr)]; - uint32_t nonces[GNUNET_NZL (num_dr)]; + struct DONAU_UniqueDonorIdentifierNonce nonces[GNUNET_NZL (num_dr)]; struct DONAU_DonationUnitSignature donation_unit_sigs[GNUNET_NZL (num_dr)]; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (h_donor_tax_id), GNUNET_PQ_query_param_array_auto_from_type (num_dr, h_donation_unit_pubs, pg->conn), - GNUNET_PQ_query_param_array_uint32 (num_dr, - nonces, - pg->conn), + GNUNET_PQ_query_param_array_auto_from_type (num_dr, + nonces, + pg->conn), DONAU_PQ_query_param_array_donation_unit_sig (num_dr, donation_unit_sigs, pg->conn), @@ -68,20 +69,18 @@ DH_PG_insert_submitted_receipts ( const struct DONAU_DonationReceipt *dr = &donation_receipts[i]; h_donation_unit_pubs[i] = dr->h_donation_unit_pub.hash; - nonces[i] = dr->nonce.value; + nonces[i] = dr->nonce; donation_unit_sigs[i] = dr->donation_unit_sig; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Do insert submitted receipt\n"); } - PREPARE (pg, "call_insert_submitted_receipts", "SELECT " " out_conflict AS conflicted" " FROM do_insert_submitted_receipts" "($1,$2,$3,$4,$5);"); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_insert_submitted_receipts", params, diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -186,7 +186,7 @@ struct DONAU_UniqueDonorIdentifierNonce /** * Actual nonce value. */ - uint32_t value; + uint32_t value[32 / 4]; }; /** @@ -252,7 +252,7 @@ struct DONAU_BearerToken /** * The token of variable length. */ - char *token; + const char *token; }; diff --git a/src/testing/test_donau_api.conf b/src/testing/test_donau_api.conf @@ -17,7 +17,7 @@ TERMS_ETAG = tos PRIVACY_ETAG = 0 PORT = 8080 DB = postgres -DOMAIN = "Bern" +LEGAL_DOMAIN = "Bern" BASE_URL = "http://localhost:8080/" SERVE = tcp EXPIRE_LEGAL = 5 @@ -53,4 +53,3 @@ KEY_DIR = ${PWD}/test_donau_api_home/exchange-secmod-eddsa/keys OVERLAP_DURATION = 0 SM_PRIV_KEY = ${DONAU_RUNTIME_DIR}donau-secmod-eddsa/secmod-private-key UNIXPATH = ${DONAU_RUNTIME_DIR}donau-secmod-eddsa/server.sock - diff --git a/src/testing/testing_api_cmd_issue_receipts.c b/src/testing/testing_api_cmd_issue_receipts.c @@ -54,7 +54,7 @@ struct StatusState unsigned int expected_response_code; /** - */ + */ bool uses_cs; /** @@ -190,43 +190,46 @@ issue_receipts_status_cb (void *cls, TALER_TESTING_interpreter_fail (ss->is); return; } - struct DONAU_BlindedDonationUnitSignature *blinded_sigs = - biresp->details.ok.blinded_sigs; - for (size_t i = 0; i < ss->num_bkp; i++) { - GNUNET_assert (GNUNET_OK == - DONAU_donation_unit_sig_unblind ( - &ss->receipts[i].donation_unit_sig, - &blinded_sigs[i], - &ss->blinding_secrets[i], - &ss->h_udis[i], - ss->alg_values[i], - &ss->selected_pks[i])); - - /* check udi message */ - struct DONAU_UniqueDonorIdentifierHashP checkudi_hash; - DONAU_unique_donor_id_hash ( - &ss->h_donor_tax_id, - &ss->receipts[i].nonce, - &checkudi_hash); - GNUNET_assert (0 == GNUNET_CRYPTO_hash_cmp (&checkudi_hash.hash, - &ss->h_udis[i].hash)); - /* check signature */ - if (GNUNET_OK != DONAU_donation_receipt_verify ( - &ss->selected_pks[i], - &checkudi_hash, - &ss->receipts[i].donation_unit_sig)) - { - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Donation receipt signature invalid!\n"); - } - else + struct DONAU_BlindedDonationUnitSignature *blinded_sigs = + biresp->details.ok.blinded_sigs; + for (size_t i = 0; i < ss->num_bkp; i++) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "!!!!!Donation receipt signature valid!\n"); - } + struct DONAU_UniqueDonorIdentifierHashP checkudi_hash; + GNUNET_assert (GNUNET_OK == + DONAU_donation_unit_sig_unblind ( + &ss->receipts[i].donation_unit_sig, + &blinded_sigs[i], + &ss->blinding_secrets[i], + &ss->h_udis[i], + ss->alg_values[i], + &ss->selected_pks[i])); + + /* check udi message */ + DONAU_unique_donor_id_hash ( + &ss->h_donor_tax_id, + &ss->receipts[i].nonce, + &checkudi_hash); + GNUNET_assert (0 == GNUNET_CRYPTO_hash_cmp (&checkudi_hash.hash, + &ss->h_udis[i].hash)); + /* check signature */ + if (GNUNET_OK != + DONAU_donation_receipt_verify ( + &ss->selected_pks[i], + &checkudi_hash, + &ss->receipts[i].donation_unit_sig)) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Donation receipt signature invalid!\n"); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Donation receipt signature valid!\n"); + } + } } TALER_TESTING_interpreter_next (ss->is); } @@ -285,41 +288,43 @@ cs_stage_two_callback ( return; } - struct DONAU_DonationUnitPublicKey *cs_pk = - &csr_data->ss->keys->donation_unit_keys[csr_data->position].key; - struct DONAU_BatchIssueValues *alg_values = GNUNET_new (struct - DONAU_BatchIssueValues); - struct DONAU_BudiMasterSecretP ps; - struct DONAU_UniqueDonorIdentifierHashP *udi_hash = - &csr_data->ss->h_udis[csr_data->position]; - union GNUNET_CRYPTO_BlindingSecretP *blinding_secret = - &csr_data->ss->blinding_secrets[csr_data->position]; - struct DONAU_UniqueDonorIdentifierNonce *udi_nonce = - &csr_data->ss->receipts[csr_data->position].nonce; - - GNUNET_assert (GNUNET_CRYPTO_BSA_CS == cs_pk->bsign_pub_key->cipher); - - DONAU_donation_unit_ewv_copy (alg_values, - &csrresp->details.ok. - alg_values); - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, - &ps, - sizeof (ps)); - DONAU_budi_secret_create (&ps, - alg_values, - blinding_secret); - GNUNET_assert (GNUNET_OK == - DONAU_donation_unit_blind ( - cs_pk, - blinding_secret, - &csr_data->nonce, /* nonce only needed for cs */ - udi_nonce, - &csr_data->ss->h_donor_tax_id, - alg_values, - udi_hash, - blinded_udi)); - csr_data->ss->alg_values[csr_data->position] = alg_values; - csr_data->ss->cs_pending--; + { + struct DONAU_DonationUnitPublicKey *cs_pk = + &csr_data->ss->keys->donation_unit_keys[csr_data->position].key; + struct DONAU_BatchIssueValues *alg_values = GNUNET_new (struct + DONAU_BatchIssueValues); + struct DONAU_BudiMasterSecretP ps; + struct DONAU_UniqueDonorIdentifierHashP *udi_hash = + &csr_data->ss->h_udis[csr_data->position]; + union GNUNET_CRYPTO_BlindingSecretP *blinding_secret = + &csr_data->ss->blinding_secrets[csr_data->position]; + struct DONAU_UniqueDonorIdentifierNonce *udi_nonce = + &csr_data->ss->receipts[csr_data->position].nonce; + + GNUNET_assert (GNUNET_CRYPTO_BSA_CS == cs_pk->bsign_pub_key->cipher); + + DONAU_donation_unit_ewv_copy (alg_values, + &csrresp->details.ok. + alg_values); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, + &ps, + sizeof (ps)); + DONAU_budi_secret_create (&ps, + alg_values, + blinding_secret); + GNUNET_assert (GNUNET_OK == + DONAU_donation_unit_blind ( + cs_pk, + blinding_secret, + &csr_data->nonce, /* nonce only needed for cs */ + udi_nonce, + &csr_data->ss->h_donor_tax_id, + alg_values, + udi_hash, + blinded_udi)); + csr_data->ss->alg_values[csr_data->position] = alg_values; + csr_data->ss->cs_pending--; + } if (0 == csr_data->ss->cs_pending) phase_two (csr_data->ss); } @@ -423,16 +428,18 @@ status_run (void *cls, GNUNET_new_array (ss->num_bkp, struct DONAU_UniqueDonorIdentifierHashP); for (size_t cnt = 0; cnt < ss->num_bkp; cnt++) { + struct DONAU_UniqueDonorIdentifierNonce *udi_nonce + = &ss->receipts[cnt].nonce; + struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi + = &ss->bkps[cnt].blinded_udi; + struct DONAU_UniqueDonorIdentifierHashP *udi_hash + = &ss->h_udis[cnt]; + struct DONAU_BudiMasterSecretP ps; + const struct DONAU_BatchIssueValues *alg_values; + DONAU_donation_unit_pub_hash (&ss->selected_pks[cnt], &ss->bkps[cnt].h_donation_unit_pub); ss->receipts[cnt].h_donation_unit_pub = ss->bkps[cnt].h_donation_unit_pub; - struct DONAU_UniqueDonorIdentifierNonce *udi_nonce = - &ss->receipts[cnt].nonce; - struct DONAU_BudiMasterSecretP ps; - const struct DONAU_BatchIssueValues *alg_values; - struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi = - &ss->bkps[cnt].blinded_udi; - struct DONAU_UniqueDonorIdentifierHashP *udi_hash = &ss->h_udis[cnt]; GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, &ps, sizeof (ps)); @@ -459,25 +466,28 @@ status_run (void *cls, ss->alg_values[cnt] = alg_values; break; case GNUNET_CRYPTO_BSA_CS: - struct CSR_Data *csr_data = GNUNET_new (struct CSR_Data); - TALER_cs_withdraw_nonce_derive ( // FIXME: write new method - (struct TALER_PlanchetMasterSecretP *) &ps, - &csr_data->nonce.cs_nonce); - csr_data->ss = ss; - csr_data->position = cnt; - csr_data->csr_handle = DONAU_csr_issue ( - TALER_TESTING_interpreter_get_context (is), - TALER_TESTING_get_donau_url (is), - &ss->selected_pks[cnt], - &csr_data->nonce.cs_nonce, - &cs_stage_two_callback, - csr_data); - if (NULL == csr_data->csr_handle) { - GNUNET_break (0); + struct CSR_Data *csr_data = GNUNET_new (struct CSR_Data); + + TALER_cs_withdraw_nonce_derive ( // FIXME: write new method + (struct TALER_PlanchetMasterSecretP *) &ps, + &csr_data->nonce.cs_nonce); + csr_data->ss = ss; + csr_data->position = cnt; + csr_data->csr_handle = DONAU_csr_issue ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_donau_url (is), + &ss->selected_pks[cnt], + &csr_data->nonce.cs_nonce, + &cs_stage_two_callback, + csr_data); + if (NULL == csr_data->csr_handle) + { + GNUNET_break (0); + } + ss->cs_pending++; + break; } - ss->cs_pending++; - break; default: GNUNET_break (0); } diff --git a/src/util/donau-secmod-cs.c b/src/util/donau-secmod-cs.c @@ -207,7 +207,8 @@ main (int argc, { struct TALER_SECMOD_Options opts = { .max_workers = 16, - .section = "donau" + .section = "donau", + .cprefix = "doco_" }; struct GNUNET_GETOPT_CommandLineOption options[] = { TALER_SECMOD_OPTIONS (&opts),