From 831e32b7ada11ad852e1171c4bee6646fb0ab865 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 4 Apr 2022 07:29:50 +0200 Subject: -add logic for econtract_sig signatures --- src/exchange/taler-exchange-httpd_purses_create.c | 78 ++++++++++-- src/exchangedb/plugin_exchangedb_postgres.c | 6 + src/include/taler_exchangedb_plugin.h | 4 + src/lib/exchange_api_purse_create_with_deposit.c | 147 +++++++++++++++------- 4 files changed, 181 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c index 75cb448a2..326dad5c3 100644 --- a/src/exchange/taler-exchange-httpd_purses_create.c +++ b/src/exchange/taler-exchange-httpd_purses_create.c @@ -111,6 +111,11 @@ struct PurseCreateContext */ struct TALER_PurseContractSignatureP purse_sig; + /** + * Signature of the client affiming this encrypted contract. + */ + struct TALER_PurseContractSignatureP econtract_sig; + /** * Hash of the contract terms of the purse. */ @@ -260,7 +265,7 @@ create_transaction (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } *mhd_ret - = return TALER_MHD_REPLY_JSON_PACK ( + = TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_CONFLICT, TALER_JSON_pack_ec ( @@ -319,6 +324,7 @@ create_transaction (void *cls, &pcc->contract_pub, pcc->econtract_size, pcc->econtract, + &pcc->econtract_sig, &in_conflict); if (qs < 0) { @@ -333,16 +339,45 @@ create_transaction (void *cls, } if (in_conflict) { - /* FIXME-DESIGN: we have no proof that the - client is at fault here! - => need 2nd client signature over the encrypted - contract (and ECDHE public key)!!! */ + struct TALER_ContractDiffiePublicP pub_ckey; + struct TALER_PurseContractSignatureP econtract_sig; + size_t econtract_size; + void *econtract; + struct GNUNET_HashCode h_econtract; + + qs = select_contract (cls, + &pcc->purse_pub, + &pub_ckey, + &econtract_sig, + &econtract_size, + &econtract); + if (qs <= 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + TALER_LOG_WARNING ( + "Failed to store fetch contract information from database\n"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "select contract"); + return qs; + } + GNUNET_CRYPTO_hash (econtract, + econtract_size, + &h_econtract); *mhd_ret - = TEH_RESPONSE_reply_with_error ( + = TALER_MHD_REPLY_JSON_PACK ( connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT_STORED, - NULL); + MHD_HTTP_CONFLICT, + TALER_JSON_pack_ec ( + TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA), + GNUNET_JSON_pack_data_auto ("h_econtract", + &h_econtract), + GNUNET_JSON_pack_data_auto ("econtract_sig", + &econtract_sig), + GNUNET_JSON_pack_data_auto ("pub_ckey", + &pub_ckey)); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -591,8 +626,12 @@ TEH_handler_purses_create ( GNUNET_JSON_spec_var_size ("econtract", &pcc.econtract, &pcc.ecotract_size)), - GNUNET_JSON_spec_fixed_auto ("contract_pub", - &pcc.contract_pub), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("econtract_sig", + &pcc.econtract_sig)), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("contract_pub", + &pcc.contract_pub)), GNUNET_JSON_spec_fixed_auto ("merge_pub", &pcc.merge_pub), GNUNET_JSON_spec_fixed_auto ("purse_sig", @@ -719,6 +758,23 @@ TEH_handler_purses_create ( TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, NULL); } + if ( (NULL != pcc.econtract) && + (GNUNET_OK != + TALER_wallet_econtract_upload_verify (pcc.econtract, + pcc.econtract_size, + &pcc.contract_pub, + purse_pub, + &pcc.econtract_sig)) ) + { + TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n"); + GNUNET_JSON_parse_free (spec); + GNUNET_free (pcc.coins); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_UNAUTHORIZED, + TALER_EC_EXCHANGE_PURSE_ECONTRACT_SIGNATURE_INVALID, + NULL); + } + if (GNUNET_SYSERR == TEH_plugin->preflight (TEH_plugin->cls)) diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 9ba373707..bc6da918c 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3289,6 +3289,7 @@ prepare_statements (struct PostgresClosure *pg) "SELECT " " pub_ckey" ",e_contract" + // ",econtract_sig" " FROM contracts" " WHERE purse_pub=$1;", 1), @@ -12811,6 +12812,7 @@ postgres_insert_partner (void *cls, * @param pub_ckey ephemeral key for DH used to encrypt the contract * @param econtract_size number of bytes in @a econtract * @param econtract the encrypted contract + * @param[out] econtract_sig set to the signature over the encrypted contract * @param[out] in_conflict set to true if @a econtract * conflicts with an existing contract; * in this case, the return value will be @@ -12823,6 +12825,8 @@ postgres_insert_contract (void *cls, const struct TALER_ContractDiffiePublicP *pub_ckey, size_t econtract_size, const void *econtract, + const struct + TALER_PurseContractSignatureP *econtract_sig, bool *in_conflict) { GNUNET_break (0); @@ -12836,6 +12840,7 @@ postgres_insert_contract (void *cls, * @param cls the @e cls of this struct with the plugin-specific state * @param purse_pub key to lookup the contract by * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract + * @param[out] econtract_sig set to the signature over the encrypted contract * @param[out] econtract_size set to the number of bytes in @a econtract * @param[out] econtract set to the encrypted contract on success, to be freed by the caller * @return transaction status code @@ -12844,6 +12849,7 @@ static enum GNUNET_DB_QueryStatus postgres_select_contract (void *cls, const struct TALER_PurseContractPublicKeyP *purse_pub, struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractSignatureP *econtract_sig, size_t *econtract_size, void **econtract) { diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 5512d3336..1e56c5e0d 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4426,6 +4426,7 @@ struct TALER_EXCHANGEDB_Plugin * @param pub_ckey ephemeral key for DH used to encrypt the contract * @param econtract_size number of bytes in @a econtract * @param econtract the encrypted contract + * @param[out] econtract_sig set to the signature over the encrypted contract * @param[out] in_conflict set to true if @a econtract * conflicts with an existing contract; * in this case, the return value will be @@ -4438,6 +4439,7 @@ struct TALER_EXCHANGEDB_Plugin const struct TALER_ContractDiffiePublicP *pub_ckey, size_t econtract_size, const void *econtract, + const struct TALER_PurseContractSignatureP *econtract_sig, bool *in_conflict); @@ -4447,6 +4449,7 @@ struct TALER_EXCHANGEDB_Plugin * @param cls the @e cls of this struct with the plugin-specific state * @param purse_pub key to lookup the contract by * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract + * @param[out] econtract_sig set to the signature over the encrypted contract * @param[out] econtract_size set to the number of bytes in @a econtract * @param[out] econtract set to the encrypted contract on success, to be freed by the caller * @return transaction status code @@ -4455,6 +4458,7 @@ struct TALER_EXCHANGEDB_Plugin (*select_contract)(void *cls, const struct TALER_PurseContractPublicKeyP *purse_pub, struct TALER_ContractDiffiePublicP *pub_ckey, + struct TALER_PurseContractSignatureP *econtract_sig, size_t *econtract_size, void **econtract); diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index 5ce91e0e3..065e2722a 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -70,6 +70,30 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle */ void *cb_cls; + /** + * Expected value in the purse after fees. + */ + struct TALER_Amount purse_value_after_fees; + + /** + * Public key of the merge capability. + */ + struct TALER_PurseMergePublicKeyP merge_pub; + + /** + * Public key of the purse. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Hash over the purse's contrac terms. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * When does the purse expire. + */ + struct GNUNET_TIME_Timestamp purse_expiration; }; @@ -102,13 +126,18 @@ handle_purse_create_deposit_finished (void *cls, case MHD_HTTP_OK: { const struct TALER_EXCHANGE_Keys *key_state; + struct GNUNET_TIME_Timestamp etime; + struct TALER_Amount total_deposited; struct GNUNET_JSON_Specification spec[] = { -#if 0 GNUNET_JSON_spec_fixed_auto ("exchange_sig", &pch->exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_pub", &pch->exchange_pub), -#endif + GNUNET_JSON_spec_timestamp ("exchange_timestamp", + &etime), + TALER_JSON_spec_amount ("total_deposited", + pch->purse_value_after_fees.currency, + &total_deposited), GNUNET_JSON_spec_end () }; @@ -123,7 +152,6 @@ handle_purse_create_deposit_finished (void *cls, break; } key_state = TALER_EXCHANGE_get_keys (pch->exchange); -#if 0 if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, &exchange_pub)) @@ -134,9 +162,24 @@ handle_purse_create_deposit_finished (void *cls, TALER_EC_EXCHANGE_PURSE_CREATE_WITH_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; break; } -#endif - // FIXME: validate reply... - (void) key_state; + if (GNUNET_OK != + TALER_exchange_online_purse_created_verify ( + etime, + pcc->purse_expiration, + &pcc->purse_value_after_fees, + &total_deposited, + &pcc->purse_pub, + &pcc->merge_pub, + &pcc->h_contract_terms, + &exchange_pub, + &exchange_sig)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = + TALER_EC_EXCHANGE_PURSE_CREATE_WITH_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + break; + } } break; case MHD_HTTP_BAD_REQUEST: @@ -159,7 +202,7 @@ handle_purse_create_deposit_finished (void *cls, happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_CONFLICT: - // FIXME: check reply? + // FIXME: check reply! break; case MHD_HTTP_GONE: /* could happen if denomination was revoked */ @@ -211,50 +254,55 @@ TALER_EXCHANGE_purse_create_with_deposit ( json_t *create_obj; json_t *deposit_arr; CURL *eh; - struct TALER_PurseMergePublicKeyP merge_pub; struct TALER_PurseContractSignatureP purse_sig; - struct TALER_PurseContractPublicKeyP purse_pub; + struct TALER_PurseContractSignatureP econtract_sig; struct TALER_ContractDiffiePublicP contract_pub; - struct TALER_PrivateContractHashP h_contract_terms; char arg_str[sizeof (purse_pub) * 2 + 32]; char *url; uint32_t min_age; - struct TALER_Amount purse_value_after_fees; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("amount", - &purse_value_after_fees), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("minimum_age", - &min_age)), - GNUNET_JSON_spec_end () - }; - if (GNUNET_OK != - GNUNET_JSON_parse (contract_terms, - spec, - NULL, NULL)) + pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle); + pch->exchange = exchange; + pch->cb = cb; + pch->cb_cls = cb_cls; + pcc->purse_expiration = purse_expiration; { - GNUNET_break (0); - return NULL; + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("amount", + &pch->purse_value_after_fees), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("minimum_age", + &min_age)), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (contract_terms, + spec, + NULL, NULL)) + { + GNUNET_break (0); + return NULL; + } } GNUNET_assert (GNUNET_YES == TEAH_handle_is_ready (exchange)); if (GNUNET_OK != TALER_JSON_contract_hash (contract_terms, - &h_contract_terms)) + &pcc->h_contract_terms)) { GNUNET_break (0); return NULL; } GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, - &purse_pub.eddsa_pub); + &pcc->purse_pub.eddsa_pub); { char pub_str[sizeof (purse_pub) * 2]; char *end; end = GNUNET_STRINGS_data_to_string ( - &purse_pub, - sizeof (purse_pub), + &pcc->purse_pub, + sizeof (pcc->purse_pub), pub_str, sizeof (pub_str)); *end = '\0'; @@ -263,14 +311,10 @@ TALER_EXCHANGE_purse_create_with_deposit ( "/purses/%s/create", pub_str); } - pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle); - pch->exchange = exchange; - pch->cb = cb; - pch->cb_cls = cb_cls; GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv, &contract_pub.ecdhe_pub); GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv, - &merge_pub.eddsa_pub); + &pcc->merge_pub.eddsa_pub); pch->url = TEAH_path_to_url (exchange, arg_str); if (NULL == pch->url) @@ -310,7 +354,7 @@ TALER_EXCHANGE_purse_create_with_deposit ( #endif TALER_wallet_purse_deposit_sign ( url, - &purse_pub, + &pcc->purse_pub, &deposit->amount, &deposit->coin_priv, &coin_sig); @@ -337,10 +381,10 @@ TALER_EXCHANGE_purse_create_with_deposit ( } GNUNET_free (url); TALER_wallet_purse_create_sign (purse_expiration, - &h_contract_terms, - &merge_pub, + &pcc->h_contract_terms, + &pcc->merge_pub, min_age, - &purse_value_after_fees, + &pcc->purse_value_after_fees, purse_priv, &purse_sig); { @@ -348,29 +392,46 @@ TALER_EXCHANGE_purse_create_with_deposit ( size_t econtract_size = 0; if (upload_contract) + { TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, contract_priv, merge_priv, contract_terms, &econtract, &econtract_size); + TALER_wallet_econtract_upload_sign (econtract, + econtract_size, + &contract_pub, + purse_priv, + &econtract_sig); + } create_obj = GNUNET_JSON_PACK ( TALER_JSON_pack_amount ("amount", - &purse_value_after_fees), + &pcc->purse_value_after_fees), GNUNET_JSON_pack_uint64 ("min_age", min_age), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_data_varsize ("econtract", econtract, econtract_size)), - GNUNET_JSON_pack_data_auto ("contract_pub", - &contract_pub), + GNUNET_JSON_pack_allow_null ( + (upload_contract) + ? GNUNET_JSON_pack_data_auto ("contract_pub", + &contract_pub) + : GNUNET_JSON_pack_string ("dummy", + NULL)), + GNUNET_JSON_pack_allow_null ( + (upload_contract) + ? GNUNET_JSON_pack_data_auto ("econtract_sig", + &econtract_sig) + : GNUNET_JSON_pack_string ("dummy2", + NULL)), GNUNET_JSON_pack_data_auto ("purse_sig", &purse_sig), GNUNET_JSON_pack_data_auto ("merge_pub", - &merge_pub), + &pcc->merge_pub), GNUNET_JSON_pack_data_auto ("h_contract_terms", - &h_contract_terms), + &pcc->h_contract_terms), GNUNET_JSON_pack_timestamp ("purse_expiration", purse_expiration), GNUNET_JSON_pack_array_steal ("deposits", -- cgit v1.2.3