implemented signature verification for /deposit 200 OK response

This commit is contained in:
Christian Grothoff 2015-06-21 21:17:33 +02:00
parent 8f6e911308
commit a334005e3d

View File

@ -23,8 +23,10 @@
#include "platform.h" #include "platform.h"
#include <curl/curl.h> #include <curl/curl.h>
#include <jansson.h> #include <jansson.h>
#include <microhttpd.h> /* just for HTTP status codes */
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
#include "taler_mint_service.h" #include "taler_mint_service.h"
#include "mint_api_json.h"
#include "mint_api_context.h" #include "mint_api_context.h"
#include "mint_api_handle.h" #include "mint_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -85,6 +87,11 @@ struct TALER_MINT_DepositHandle
*/ */
void *buf; void *buf;
/**
* Information the mint should sign in response.
*/
struct TALER_DepositConfirmationPS depconf;
/** /**
* The size of the download buffer * The size of the download buffer
*/ */
@ -99,6 +106,77 @@ struct TALER_MINT_DepositHandle
}; };
/**
* Verify that the signature on the "200 OK" response
* from the mint is valid.
*
* @param dh deposit handle
* @param json json reply with the signature
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
*/
static int
verify_deposit_signature_ok (const struct TALER_MINT_DepositHandle *dh,
json_t *json)
{
struct TALER_MintSignatureP mint_sig;
const struct TALER_MINT_Keys *key_state;
const struct TALER_MintPublicKeyP *mint_pub;
struct MAJ_Specification spec[] = {
MAJ_spec_fixed_auto ("sig", &mint_sig),
MAJ_spec_end
};
if (GNUNET_OK !=
MAJ_parse_json (json,
spec))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
key_state = TALER_MINT_get_keys (dh->mint);
mint_pub = TALER_MINT_get_signing_key (key_state);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT,
&dh->depconf.purpose,
&mint_sig.eddsa_signature,
&mint_pub->eddsa_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* Verify that the signatures on the "403 FORBIDDEN" response from the
* mint demonstrating customer double-spending are valid.
*
* @param dh deposit handle
* @param json json reply with the signature(s) and transaction history
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
*/
static int
verify_deposit_signature_forbidden (const struct TALER_MINT_DepositHandle *dh,
json_t *json)
{
struct MAJ_Specification spec[] = {
MAJ_spec_end
};
if (GNUNET_OK !=
MAJ_parse_json (json,
spec))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
GNUNET_break (0); // not implemented
return GNUNET_OK;
}
/** /**
* Function called when we're done processing the * Function called when we're done processing the
* HTTP /deposit request. * HTTP /deposit request.
@ -110,7 +188,7 @@ handle_deposit_finished (void *cls,
CURL *eh) CURL *eh)
{ {
struct TALER_MINT_DepositHandle *dh = cls; struct TALER_MINT_DepositHandle *dh = cls;
unsigned int response_code; long response_code;
json_error_t error; json_error_t error;
json_t *json; json_t *json;
@ -129,13 +207,54 @@ handle_deposit_finished (void *cls,
} }
if (NULL != json) if (NULL != json)
{ {
GNUNET_break (0); // FIXME: obtain response code from eh! if (CURLE_OK !=
response_code = 42; curl_easy_getinfo (eh,
CURLINFO_RESPONSE_CODE,
&response_code))
{
/* unexpected error... */
GNUNET_break (0);
response_code = 0;
}
} }
switch (response_code) switch (response_code)
{ {
/* FIXME: verify json response signatures case MHD_HTTP_OK:
(and that format matches response_code) */ if (GNUNET_OK !=
verify_deposit_signature_ok (dh,
json))
{
GNUNET_break_op (0);
response_code = 0;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the mint is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_FORBIDDEN:
/* Double spending; check signatures on transaction history */
if (GNUNET_OK !=
verify_deposit_signature_forbidden (dh,
json))
{
GNUNET_break_op (0);
response_code = 0;
}
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, mint says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
break;
default: default:
/* unexpected response code */ /* unexpected response code */
GNUNET_break (0); GNUNET_break (0);
@ -153,11 +272,22 @@ handle_deposit_finished (void *cls,
/** /**
* Verify signature information about the deposit. * Verify signature information about the deposit.
* *
* @param deposit information about the deposit * @param dki public key information
* @param amount the amount to be deposited
* @param h_wire hash of the merchants account details
* @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
* @param coin_pub coins public key
* @param denom_pub denomination key with which the coin is signed
* @param denom_sig mints unblinded signature of the coin
* @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
* @param transaction_id transaction id for the transaction between merchant and customer
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
* @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed)
* @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coins private key.
* @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
*/ */
static int static int
verify_signatures (struct TALER_MINT_Handle *mint, verify_signatures (const struct TALER_MINT_DenomPublicKey *dki,
const struct TALER_Amount *amount, const struct TALER_Amount *amount,
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract, const struct GNUNET_HashCode *h_contract,
@ -170,19 +300,9 @@ verify_signatures (struct TALER_MINT_Handle *mint,
struct GNUNET_TIME_Absolute refund_deadline, struct GNUNET_TIME_Absolute refund_deadline,
const struct TALER_CoinSpendSignatureP *coin_sig) const struct TALER_CoinSpendSignatureP *coin_sig)
{ {
const struct TALER_MINT_Keys *key_state;
struct TALER_DepositRequestPS dr; struct TALER_DepositRequestPS dr;
const struct TALER_MINT_DenomPublicKey *dki;
struct TALER_CoinPublicInfo coin_info; struct TALER_CoinPublicInfo coin_info;
key_state = TALER_MINT_get_keys (mint);
dki = TALER_MINT_get_denomination_key (key_state,
denom_pub);
if (NULL == dki)
{
TALER_LOG_WARNING ("Denomination key unknown to mint\n");
return GNUNET_SYSERR;
}
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
dr.h_contract = *h_contract; dr.h_contract = *h_contract;
@ -289,7 +409,7 @@ deposit_download_cb (char *bufptr,
* @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
* @param coin_pub coins public key * @param coin_pub coins public key
* @param denom_pub denomination key with which the coin is signed * @param denom_pub denomination key with which the coin is signed
* @param ub_sig mints unblinded signature of the coin * @param denom_sig mints unblinded signature of the coin
* @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
* @param transaction_id transaction id for the transaction between merchant and customer * @param transaction_id transaction id for the transaction between merchant and customer
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
@ -316,11 +436,14 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
TALER_MINT_DepositResultCallback cb, TALER_MINT_DepositResultCallback cb,
void *cb_cls) void *cb_cls)
{ {
const struct TALER_MINT_Keys *key_state;
const struct TALER_MINT_DenomPublicKey *dki;
struct TALER_MINT_DepositHandle *dh; struct TALER_MINT_DepositHandle *dh;
struct TALER_MINT_Context *ctx; struct TALER_MINT_Context *ctx;
json_t *deposit_obj; json_t *deposit_obj;
CURL *eh; CURL *eh;
struct GNUNET_HashCode h_wire; struct GNUNET_HashCode h_wire;
struct TALER_Amount amount_without_fee;
if (GNUNET_YES != if (GNUNET_YES !=
MAH_handle_is_ready (mint)) MAH_handle_is_ready (mint))
@ -336,9 +459,17 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
GNUNET_break (0); GNUNET_break (0);
return NULL; return NULL;
} }
key_state = TALER_MINT_get_keys (mint);
dki = TALER_MINT_get_denomination_key (key_state,
denom_pub);
if (NULL == dki)
{
TALER_LOG_WARNING ("Denomination key unknown to mint\n");
return NULL;
}
if (GNUNET_OK != if (GNUNET_OK !=
verify_signatures (mint, verify_signatures (dki,
amount, amount,
&h_wire, &h_wire,
h_contract, h_contract,
@ -385,6 +516,22 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
dh->cb = cb; dh->cb = cb;
dh->cb_cls = cb_cls; dh->cb_cls = cb_cls;
dh->url = MAH_path_to_url (mint, "/deposit"); dh->url = MAH_path_to_url (mint, "/deposit");
dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT);
dh->depconf.h_contract = *h_contract;
dh->depconf.h_wire = h_wire;
dh->depconf.transaction_id = GNUNET_htonll (transaction_id);
dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
TALER_amount_subtract (&amount_without_fee,
amount,
&dki->fee_deposit);
TALER_amount_hton (&dh->depconf.amount_without_fee,
&amount_without_fee);
dh->depconf.coin_pub = *coin_pub;
dh->depconf.merchant = *merchant_pub;
eh = curl_easy_init (); eh = curl_easy_init ();
GNUNET_assert (NULL != (dh->json_enc = GNUNET_assert (NULL != (dh->json_enc =
json_dumps (deposit_obj, json_dumps (deposit_obj,