aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-10-10 17:18:24 +0200
committerChristian Grothoff <christian@grothoff.org>2021-10-10 17:18:24 +0200
commit8951abfc505c38aaea2b709e5540e84cf7971cf4 (patch)
treeb8f0a3bc395735b7d0bbc42e9f23a162a5a5d789
parentdf681b0d9585cbd69f377304643a8877fd4fb00a (diff)
-finish implemnetation of /kyc-check client library
-rw-r--r--src/include/taler_exchange_service.h4
-rw-r--r--src/include/taler_signatures.h31
-rw-r--r--src/lib/exchange_api_common.c2
-rw-r--r--src/lib/exchange_api_deposit.c6
-rw-r--r--src/lib/exchange_api_handle.c12
-rw-r--r--src/lib/exchange_api_handle.h4
-rw-r--r--src/lib/exchange_api_kyc_check.c152
7 files changed, 162 insertions, 49 deletions
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index ed6f2eb1a..d5cc00eaf 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -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);
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 6b5d37685..93e48b7ce 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -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 */
@@ -819,6 +825,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.
*/
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index da1400b9d..a6873c656 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -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,
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 86f5034aa..b945f6b76 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -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 coin’s 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,
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index dfd5a3dc6..142ed18e6 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -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)
{
diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h
index 1a7e8ee7b..df0ccf7fc 100644
--- a/src/lib/exchange_api_handle.h
+++ b/src/lib/exchange_api_handle.h
@@ -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);
diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c
index 5b9d10164..82fddd455 100644
--- a/src/lib/exchange_api_kyc_check.c
+++ b/src/lib/exchange_api_kyc_check.c
@@ -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)
{