summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2022-04-04 07:29:50 +0200
committerChristian Grothoff <grothoff@gnunet.org>2022-04-04 07:29:50 +0200
commit831e32b7ada11ad852e1171c4bee6646fb0ab865 (patch)
tree4d8edb68869b33e92c94ce607d29418d2f459cfb /src
parent393cea46d1b76b0229272edbc334f0471a069154 (diff)
downloadexchange-831e32b7ada11ad852e1171c4bee6646fb0ab865.tar.gz
exchange-831e32b7ada11ad852e1171c4bee6646fb0ab865.tar.bz2
exchange-831e32b7ada11ad852e1171c4bee6646fb0ab865.zip
-add logic for econtract_sig signatures
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-httpd_purses_create.c78
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c6
-rw-r--r--src/include/taler_exchangedb_plugin.h4
-rw-r--r--src/lib/exchange_api_purse_create_with_deposit.c147
4 files changed, 181 insertions, 54 deletions
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
@@ -112,6 +112,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.
*/
struct TALER_PrivateContractHashP h_contract_terms;
@@ -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",