-add logic for econtract_sig signatures

This commit is contained in:
Christian Grothoff 2022-04-04 07:29:50 +02:00
parent 393cea46d1
commit 831e32b7ad
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 181 additions and 54 deletions

View File

@ -111,6 +111,11 @@ struct PurseCreateContext
*/ */
struct TALER_PurseContractSignatureP purse_sig; 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. * Hash of the contract terms of the purse.
*/ */
@ -260,7 +265,7 @@ create_transaction (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
*mhd_ret *mhd_ret
= return TALER_MHD_REPLY_JSON_PACK ( = TALER_MHD_REPLY_JSON_PACK (
connection, connection,
MHD_HTTP_CONFLICT, MHD_HTTP_CONFLICT,
TALER_JSON_pack_ec ( TALER_JSON_pack_ec (
@ -319,6 +324,7 @@ create_transaction (void *cls,
&pcc->contract_pub, &pcc->contract_pub,
pcc->econtract_size, pcc->econtract_size,
pcc->econtract, pcc->econtract,
&pcc->econtract_sig,
&in_conflict); &in_conflict);
if (qs < 0) if (qs < 0)
{ {
@ -333,16 +339,45 @@ create_transaction (void *cls,
} }
if (in_conflict) if (in_conflict)
{ {
/* FIXME-DESIGN: we have no proof that the struct TALER_ContractDiffiePublicP pub_ckey;
client is at fault here! struct TALER_PurseContractSignatureP econtract_sig;
=> need 2nd client signature over the encrypted size_t econtract_size;
contract (and ECDHE public key)!!! */ 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 *mhd_ret
= TEH_RESPONSE_reply_with_error ( = TALER_MHD_REPLY_JSON_PACK (
connection, connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_CONFLICT,
TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT_STORED, TALER_JSON_pack_ec (
NULL); 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 GNUNET_DB_STATUS_HARD_ERROR;
} }
return qs; return qs;
@ -591,8 +626,12 @@ TEH_handler_purses_create (
GNUNET_JSON_spec_var_size ("econtract", GNUNET_JSON_spec_var_size ("econtract",
&pcc.econtract, &pcc.econtract,
&pcc.ecotract_size)), &pcc.ecotract_size)),
GNUNET_JSON_spec_fixed_auto ("contract_pub", GNUNET_JSON_spec_mark_optional (
&pcc.contract_pub), 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", GNUNET_JSON_spec_fixed_auto ("merge_pub",
&pcc.merge_pub), &pcc.merge_pub),
GNUNET_JSON_spec_fixed_auto ("purse_sig", GNUNET_JSON_spec_fixed_auto ("purse_sig",
@ -719,6 +758,23 @@ TEH_handler_purses_create (
TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID, TALER_EC_EXCHANGE_PURSE_CREATE_SIGNATURE_INVALID,
NULL); 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 == if (GNUNET_SYSERR ==
TEH_plugin->preflight (TEH_plugin->cls)) TEH_plugin->preflight (TEH_plugin->cls))

View File

@ -3289,6 +3289,7 @@ prepare_statements (struct PostgresClosure *pg)
"SELECT " "SELECT "
" pub_ckey" " pub_ckey"
",e_contract" ",e_contract"
// ",econtract_sig"
" FROM contracts" " FROM contracts"
" WHERE purse_pub=$1;", " WHERE purse_pub=$1;",
1), 1),
@ -12811,6 +12812,7 @@ postgres_insert_partner (void *cls,
* @param pub_ckey ephemeral key for DH used to encrypt the contract * @param pub_ckey ephemeral key for DH used to encrypt the contract
* @param econtract_size number of bytes in @a econtract * @param econtract_size number of bytes in @a econtract
* @param econtract the encrypted contract * @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 * @param[out] in_conflict set to true if @a econtract
* conflicts with an existing contract; * conflicts with an existing contract;
* in this case, the return value will be * in this case, the return value will be
@ -12823,6 +12825,8 @@ postgres_insert_contract (void *cls,
const struct TALER_ContractDiffiePublicP *pub_ckey, const struct TALER_ContractDiffiePublicP *pub_ckey,
size_t econtract_size, size_t econtract_size,
const void *econtract, const void *econtract,
const struct
TALER_PurseContractSignatureP *econtract_sig,
bool *in_conflict) bool *in_conflict)
{ {
GNUNET_break (0); 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 cls the @e cls of this struct with the plugin-specific state
* @param purse_pub key to lookup the contract by * @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] 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_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 * @param[out] econtract set to the encrypted contract on success, to be freed by the caller
* @return transaction status code * @return transaction status code
@ -12844,6 +12849,7 @@ static enum GNUNET_DB_QueryStatus
postgres_select_contract (void *cls, postgres_select_contract (void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub, const struct TALER_PurseContractPublicKeyP *purse_pub,
struct TALER_ContractDiffiePublicP *pub_ckey, struct TALER_ContractDiffiePublicP *pub_ckey,
struct TALER_PurseContractSignatureP *econtract_sig,
size_t *econtract_size, size_t *econtract_size,
void **econtract) void **econtract)
{ {

View File

@ -4426,6 +4426,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param pub_ckey ephemeral key for DH used to encrypt the contract * @param pub_ckey ephemeral key for DH used to encrypt the contract
* @param econtract_size number of bytes in @a econtract * @param econtract_size number of bytes in @a econtract
* @param econtract the encrypted contract * @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 * @param[out] in_conflict set to true if @a econtract
* conflicts with an existing contract; * conflicts with an existing contract;
* in this case, the return value will be * in this case, the return value will be
@ -4438,6 +4439,7 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_ContractDiffiePublicP *pub_ckey, const struct TALER_ContractDiffiePublicP *pub_ckey,
size_t econtract_size, size_t econtract_size,
const void *econtract, const void *econtract,
const struct TALER_PurseContractSignatureP *econtract_sig,
bool *in_conflict); 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 cls the @e cls of this struct with the plugin-specific state
* @param purse_pub key to lookup the contract by * @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] 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_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 * @param[out] econtract set to the encrypted contract on success, to be freed by the caller
* @return transaction status code * @return transaction status code
@ -4455,6 +4458,7 @@ struct TALER_EXCHANGEDB_Plugin
(*select_contract)(void *cls, (*select_contract)(void *cls,
const struct TALER_PurseContractPublicKeyP *purse_pub, const struct TALER_PurseContractPublicKeyP *purse_pub,
struct TALER_ContractDiffiePublicP *pub_ckey, struct TALER_ContractDiffiePublicP *pub_ckey,
struct TALER_PurseContractSignatureP *econtract_sig,
size_t *econtract_size, size_t *econtract_size,
void **econtract); void **econtract);

View File

@ -70,6 +70,30 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle
*/ */
void *cb_cls; 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: case MHD_HTTP_OK:
{ {
const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_TIME_Timestamp etime;
struct TALER_Amount total_deposited;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
#if 0
GNUNET_JSON_spec_fixed_auto ("exchange_sig", GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&pch->exchange_sig), &pch->exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&pch->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 () GNUNET_JSON_spec_end ()
}; };
@ -123,7 +152,6 @@ handle_purse_create_deposit_finished (void *cls,
break; break;
} }
key_state = TALER_EXCHANGE_get_keys (pch->exchange); key_state = TALER_EXCHANGE_get_keys (pch->exchange);
#if 0
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state, TALER_EXCHANGE_test_signing_key (key_state,
&exchange_pub)) &exchange_pub))
@ -134,9 +162,24 @@ handle_purse_create_deposit_finished (void *cls,
TALER_EC_EXCHANGE_PURSE_CREATE_WITH_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; TALER_EC_EXCHANGE_PURSE_CREATE_WITH_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
break; break;
} }
#endif if (GNUNET_OK !=
// FIXME: validate reply... TALER_exchange_online_purse_created_verify (
(void) key_state; 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; break;
case MHD_HTTP_BAD_REQUEST: 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 */ happen, we should pass the JSON reply to the application */
break; break;
case MHD_HTTP_CONFLICT: case MHD_HTTP_CONFLICT:
// FIXME: check reply? // FIXME: check reply!
break; break;
case MHD_HTTP_GONE: case MHD_HTTP_GONE:
/* could happen if denomination was revoked */ /* could happen if denomination was revoked */
@ -211,50 +254,55 @@ TALER_EXCHANGE_purse_create_with_deposit (
json_t *create_obj; json_t *create_obj;
json_t *deposit_arr; json_t *deposit_arr;
CURL *eh; CURL *eh;
struct TALER_PurseMergePublicKeyP merge_pub;
struct TALER_PurseContractSignatureP purse_sig; struct TALER_PurseContractSignatureP purse_sig;
struct TALER_PurseContractPublicKeyP purse_pub; struct TALER_PurseContractSignatureP econtract_sig;
struct TALER_ContractDiffiePublicP contract_pub; struct TALER_ContractDiffiePublicP contract_pub;
struct TALER_PrivateContractHashP h_contract_terms;
char arg_str[sizeof (purse_pub) * 2 + 32]; char arg_str[sizeof (purse_pub) * 2 + 32];
char *url; char *url;
uint32_t min_age; 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 != pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle);
GNUNET_JSON_parse (contract_terms, pch->exchange = exchange;
spec, pch->cb = cb;
NULL, NULL)) pch->cb_cls = cb_cls;
pcc->purse_expiration = purse_expiration;
{ {
GNUNET_break (0); struct GNUNET_JSON_Specification spec[] = {
return NULL; 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 == GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange)); TEAH_handle_is_ready (exchange));
if (GNUNET_OK != if (GNUNET_OK !=
TALER_JSON_contract_hash (contract_terms, TALER_JSON_contract_hash (contract_terms,
&h_contract_terms)) &pcc->h_contract_terms))
{ {
GNUNET_break (0); GNUNET_break (0);
return NULL; return NULL;
} }
GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, 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 pub_str[sizeof (purse_pub) * 2];
char *end; char *end;
end = GNUNET_STRINGS_data_to_string ( end = GNUNET_STRINGS_data_to_string (
&purse_pub, &pcc->purse_pub,
sizeof (purse_pub), sizeof (pcc->purse_pub),
pub_str, pub_str,
sizeof (pub_str)); sizeof (pub_str));
*end = '\0'; *end = '\0';
@ -263,14 +311,10 @@ TALER_EXCHANGE_purse_create_with_deposit (
"/purses/%s/create", "/purses/%s/create",
pub_str); 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, GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv,
&contract_pub.ecdhe_pub); &contract_pub.ecdhe_pub);
GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv, 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, pch->url = TEAH_path_to_url (exchange,
arg_str); arg_str);
if (NULL == pch->url) if (NULL == pch->url)
@ -310,7 +354,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
#endif #endif
TALER_wallet_purse_deposit_sign ( TALER_wallet_purse_deposit_sign (
url, url,
&purse_pub, &pcc->purse_pub,
&deposit->amount, &deposit->amount,
&deposit->coin_priv, &deposit->coin_priv,
&coin_sig); &coin_sig);
@ -337,10 +381,10 @@ TALER_EXCHANGE_purse_create_with_deposit (
} }
GNUNET_free (url); GNUNET_free (url);
TALER_wallet_purse_create_sign (purse_expiration, TALER_wallet_purse_create_sign (purse_expiration,
&h_contract_terms, &pcc->h_contract_terms,
&merge_pub, &pcc->merge_pub,
min_age, min_age,
&purse_value_after_fees, &pcc->purse_value_after_fees,
purse_priv, purse_priv,
&purse_sig); &purse_sig);
{ {
@ -348,29 +392,46 @@ TALER_EXCHANGE_purse_create_with_deposit (
size_t econtract_size = 0; size_t econtract_size = 0;
if (upload_contract) if (upload_contract)
{
TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
contract_priv, contract_priv,
merge_priv, merge_priv,
contract_terms, contract_terms,
&econtract, &econtract,
&econtract_size); &econtract_size);
TALER_wallet_econtract_upload_sign (econtract,
econtract_size,
&contract_pub,
purse_priv,
&econtract_sig);
}
create_obj = GNUNET_JSON_PACK ( create_obj = GNUNET_JSON_PACK (
TALER_JSON_pack_amount ("amount", TALER_JSON_pack_amount ("amount",
&purse_value_after_fees), &pcc->purse_value_after_fees),
GNUNET_JSON_pack_uint64 ("min_age", GNUNET_JSON_pack_uint64 ("min_age",
min_age), min_age),
GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_data_varsize ("econtract", GNUNET_JSON_pack_data_varsize ("econtract",
econtract, econtract,
econtract_size)), econtract_size)),
GNUNET_JSON_pack_data_auto ("contract_pub", GNUNET_JSON_pack_allow_null (
&contract_pub), (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", GNUNET_JSON_pack_data_auto ("purse_sig",
&purse_sig), &purse_sig),
GNUNET_JSON_pack_data_auto ("merge_pub", GNUNET_JSON_pack_data_auto ("merge_pub",
&merge_pub), &pcc->merge_pub),
GNUNET_JSON_pack_data_auto ("h_contract_terms", GNUNET_JSON_pack_data_auto ("h_contract_terms",
&h_contract_terms), &pcc->h_contract_terms),
GNUNET_JSON_pack_timestamp ("purse_expiration", GNUNET_JSON_pack_timestamp ("purse_expiration",
purse_expiration), purse_expiration),
GNUNET_JSON_pack_array_steal ("deposits", GNUNET_JSON_pack_array_steal ("deposits",