-finish implemnetation of /kyc-check client library

This commit is contained in:
Christian Grothoff 2021-10-10 17:18:24 +02:00
parent df681b0d95
commit 8951abfc50
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
7 changed files with 162 additions and 49 deletions

View File

@ -1810,7 +1810,7 @@ TALER_EXCHANGE_verify_coin_history (
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
int
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *history,
@ -1988,7 +1988,7 @@ typedef void
struct TALER_EXCHANGE_KycCheckHandle *
TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *eh,
uint64_t payment_target,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_payto,
struct GNUNET_TIME_Relative timeout,
TALER_EXCHANGE_KycStatusCallback cb,
void *cb_cls);

View File

@ -167,6 +167,12 @@
*/
#define TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED 1043
/**
* Signature by which an exchange affirms that an account
* successfully passed the KYC checks.
*/
#define TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS 1044
/**********************/
/* Auditor signatures */
@ -818,6 +824,31 @@ struct TALER_ExchangeKeySetPS
};
/**
* @brief Signature by which an exchange affirms that an account
* successfully passed the KYC checks.
*/
struct TALER_ExchangeAccountSetupSuccessPS
{
/**
* Purpose is #TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS. Signed by a
* `struct TALER_ExchangePublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Hash over the payto for which the signature was
* made.
*/
struct GNUNET_HashCode h_payto;
/**
* When was the signature made.
*/
struct GNUNET_TIME_AbsoluteNBO timestamp;
};
/**
* @brief Signature made by the exchange offline key over the information of
* an auditor to be added to the exchange's set of auditors.

View File

@ -42,7 +42,7 @@
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
int
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *history,

View File

@ -188,7 +188,7 @@ auditor_cb (void *cls,
* @param[out] exchange_pub set to the exchange's public key
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
*/
static int
static enum GNUNET_GenericReturnValue
verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
const json_t *json,
struct TALER_ExchangeSignatureP *exchange_sig,
@ -245,7 +245,7 @@ verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
* @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
static enum GNUNET_GenericReturnValue
verify_deposit_signature_conflict (
const struct TALER_EXCHANGE_DepositHandle *dh,
const json_t *json)
@ -441,7 +441,7 @@ handle_deposit_finished (void *cls,
* @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
*/
static int
static enum GNUNET_GenericReturnValue
verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
const struct TALER_Amount *amount,
const struct GNUNET_HashCode *h_wire,

View File

@ -257,7 +257,7 @@ free_keys_request (struct KeysRequest *kr)
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
static int
static enum GNUNET_GenericReturnValue
parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
int check_sigs,
json_t *sign_key_obj,
@ -317,7 +317,7 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
static int
static enum GNUNET_GenericReturnValue
parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
int check_sigs,
json_t *denom_key_obj,
@ -402,7 +402,7 @@ EXITIF_exit:
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
static int
static enum GNUNET_GenericReturnValue
parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
int check_sigs,
json_t *auditor_obj,
@ -670,7 +670,7 @@ denoms_cmp (struct TALER_EXCHANGE_DenomPublicKey *denom1,
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
* (malformed JSON)
*/
static int
static enum GNUNET_GenericReturnValue
decode_keys_json (const json_t *resp_obj,
bool check_sig,
struct TALER_EXCHANGE_Keys *key_data,
@ -1314,7 +1314,7 @@ TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
int
enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
{
return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
@ -1352,7 +1352,7 @@ TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
* @param at where to write the result
* @return #GNUNET_OK on success
*/
static int
static enum GNUNET_GenericReturnValue
parse_date_string (const char *dateline,
struct GNUNET_TIME_Absolute *at)
{

View File

@ -229,7 +229,7 @@ TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h);
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
int
enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
/**
@ -238,7 +238,7 @@ TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
int
enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);

View File

@ -61,6 +61,10 @@ struct TALER_EXCHANGE_KycCheckHandle
*/
void *cb_cls;
/**
* Hash of the payto:// URL that is being KYC'ed.
*/
struct GNUNET_HashCode h_payto;
};
@ -90,30 +94,104 @@ handle_kyc_check_finished (void *cls,
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
GNUNET_break (0); // FIXME
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&ks.details.kyc_ok.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&ks.details.kyc_ok.exchange_pub),
TALER_JSON_spec_absolute_time ("now",
&ks.details.kyc_ok.timestamp),
GNUNET_JSON_spec_end ()
};
const struct TALER_EXCHANGE_Keys *key_state;
struct TALER_ExchangeAccountSetupSuccessPS kyc_purpose = {
.purpose.size = htonl (sizeof (kyc_purpose)),
.purpose.purpose = htonl (
TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
.h_payto = kch->h_payto
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
ks.http_status = 0;
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
kyc_purpose.timestamp = GNUNET_TIME_absolute_hton (
ks.details.kyc_ok.timestamp);
key_state = TALER_EXCHANGE_get_keys (kch->exchange);
if (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_state,
&ks.details.kyc_ok.exchange_pub))
{
GNUNET_break_op (0);
ks.http_status = 0;
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
GNUNET_JSON_parse_free (spec);
break;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS,
&kyc_purpose,
&ks.details.kyc_ok.exchange_sig.eddsa_signature,
&ks.details.kyc_ok.exchange_pub.eddsa_pub))
{
GNUNET_break_op (0);
ks.http_status = 0;
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
GNUNET_JSON_parse_free (spec);
break;
}
kch->cb (kch->cb_cls,
&ks);
GNUNET_JSON_parse_free (spec);
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
}
case MHD_HTTP_ACCEPTED:
GNUNET_break (0); // FIXME
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("kyc_url",
&ks.details.kyc_url),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
ks.http_status = 0;
ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
}
kch->cb (kch->cb_cls,
&ks);
GNUNET_JSON_parse_free (spec);
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
}
case MHD_HTTP_NO_CONTENT:
GNUNET_break (0); // FIXME
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
break;
case MHD_HTTP_BAD_REQUEST:
ks.ec = TALER_JSON_get_error_code (j);
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_UNAUTHORIZED:
GNUNET_break (0); // FIXME
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
ks.ec = TALER_JSON_get_error_code (j);
break;
case MHD_HTTP_NOT_FOUND:
ks.ec = TALER_JSON_get_error_code (j);
TALER_EXCHANGE_kyc_check_cancel (kch);
return;
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
ks.ec = TALER_JSON_get_error_code (j);
/* Server had an internal issue; we should retry, but this API
@ -129,27 +207,16 @@ handle_kyc_check_finished (void *cls,
(int) ks.ec);
break;
}
kch->cb (kch->cb_cls,
&ks);
TALER_EXCHANGE_kyc_check_cancel (kch);
}
/**
* Submit a kyc_check request to the exchange and get the exchange's response.
*
* This API is typically not used by anyone, it is more a threat against those
* trying to receive a funds transfer by abusing the refresh protocol.
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param coin_priv private key to request kyc_check data for
* @param kyc_check_cb the callback to call with the useful result of the
* refresh operation the @a coin_priv was involved in (if any)
* @param kyc_check_cb_cls closure for @a kyc_check_cb
* @return a handle for this request
*/
struct TALER_EXCHANGE_KycCheckHandle *
TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
uint64_t payment_target,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_payto,
struct GNUNET_TIME_Relative timeout,
TALER_EXCHANGE_KycStatusCallback cb,
void *cb_cls)
@ -157,6 +224,7 @@ TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
struct TALER_EXCHANGE_KycCheckHandle *kch;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
char *arg_str;
if (GNUNET_YES !=
TEAH_handle_is_ready (exchange))
@ -164,13 +232,33 @@ TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_break (0);
return NULL;
}
{
char payto_str[sizeof (*h_payto) * 2];
char *end;
unsigned long long timeout_ms;
end = GNUNET_STRINGS_data_to_string (
h_payto,
sizeof (*h_payto),
payto_str,
sizeof (payto_str) - 1);
*end = '\0';
timeout_ms = timeout.rel_value_us
/ GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
GNUNET_asprintf (&arg_str,
"/kyc-check/%llu?h_payto=%s&timeout_ms=%llu",
(unsigned long long) payment_target,
payto_str,
timeout_ms);
}
kch = GNUNET_new (struct TALER_EXCHANGE_KycCheckHandle);
kch->exchange = exchange;
kch->h_payto = *h_payto;
kch->cb = cb;
kch->cb_cls = cb_cls;
kch->url = TEAH_path_to_url (exchange,
"FIXME");
arg_str);
GNUNET_free (arg_str);
if (NULL == kch->url)
{
GNUNET_free (kch);
@ -193,12 +281,6 @@ TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
}
/**
* Cancel a kyc_check request. This function cannot be used
* on a request handle if the callback was already invoked.
*
* @param kch the kyc_check handle
*/
void
TALER_EXCHANGE_kyc_check_cancel (struct TALER_EXCHANGE_KycCheckHandle *kch)
{