From f8e9241a3d4adb3e31e8691782136aaed88b41da Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 6 Nov 2022 22:29:51 +0100 Subject: [PATCH] fix #7427 --- src/exchange/taler-exchange-httpd_kyc-check.c | 16 ++++++++++ src/include/taler_crypto_lib.h | 10 ++++-- src/include/taler_exchange_service.h | 5 +++ src/include/taler_kyclogic_lib.h | 3 ++ src/kyclogic/kyclogic_api.c | 32 ++++++++++++++++--- src/lib/exchange_api_kyc_check.c | 5 +++ src/util/exchange_signatures.c | 22 ++++++++----- 7 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index 55199593e..47338ae96 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -92,6 +92,11 @@ struct KycPoller */ struct GNUNET_TIME_Absolute timeout; + /** + * If the KYC complete, what kind of data was collected? + */ + json_t *kyc_details; + /** * Set to starting URL of KYC process if KYC is required. */ @@ -195,6 +200,7 @@ kyp_cleanup (struct TEH_RequestContext *rc) kyp->ih_logic->initiate_cancel (kyp->ih); kyp->ih = NULL; } + json_decref (kyp->kyc_details); GNUNET_free (kyp->kyc_url); GNUNET_free (kyp->hint); GNUNET_free (kyp); @@ -327,9 +333,16 @@ kyc_check (void *cls, if (TALER_KYCLOGIC_check_satisfied ( requirements, &h_payto, + &kyp->kyc_details, TEH_plugin->select_satisfied_kyc_processes, TEH_plugin->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "KYC requirements `%s' already satisfied\n", + requirements); + GNUNET_free (requirements); return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } kyp->kyc_required = true; ret = TALER_KYCLOGIC_requirements_to_logic (requirements, @@ -610,6 +623,7 @@ TEH_handler_kyc_check ( (ec = TALER_exchange_online_account_setup_success_sign ( &TEH_keys_exchange_sign_, &kyp->h_payto, + kyp->kyc_details, now, &pub, &sig))) @@ -625,6 +639,8 @@ TEH_handler_kyc_check ( &sig), GNUNET_JSON_pack_data_auto ("exchange_pub", &pub), + GNUNET_JSON_pack_object_incref ("kyc_details", + kyp->kyc_details), GNUNET_JSON_pack_timestamp ("now", now)); } diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 6b8000933..7a056376f 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -3891,10 +3891,12 @@ TALER_exchange_online_key_set_verify ( /** - * Create account setup success signature. + * Create account KYC setup success signature. * * @param scb function to call to create the signature * @param h_payto target of the KYC account + * @param kyc JSON data describing which KYC checks + * were satisfied * @param timestamp time when the KYC was confirmed * @param[out] pub where to write the public key * @param[out] sig where to write the signature @@ -3904,15 +3906,18 @@ enum TALER_ErrorCode TALER_exchange_online_account_setup_success_sign ( TALER_ExchangeSignCallback scb, const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, struct GNUNET_TIME_Timestamp timestamp, struct TALER_ExchangePublicKeyP *pub, struct TALER_ExchangeSignatureP *sig); /** - * Verify account setup success signature. + * Verify account KYC setup success signature. * * @param h_payto target of the KYC account + * @param kyc JSON data describing which KYC checks + * were satisfied * @param timestamp time when the KYC was confirmed * @param pub where to write the public key * @param sig where to write the signature @@ -3921,6 +3926,7 @@ TALER_exchange_online_account_setup_success_sign ( enum GNUNET_GenericReturnValue TALER_exchange_online_account_setup_success_verify ( const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, struct GNUNET_TIME_Timestamp timestamp, const struct TALER_ExchangePublicKeyP *pub, const struct TALER_ExchangeSignatureP *sig); diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index e3a349a92..d11f7d616 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3454,6 +3454,11 @@ struct TALER_EXCHANGE_KycStatus struct { + /** + * Details about which KYC check(s) were passed. + */ + const json_t *kyc_details; + /** * Time of the affirmation. */ diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h index cfe6a5c7d..c18c677df 100644 --- a/src/include/taler_kyclogic_lib.h +++ b/src/include/taler_kyclogic_lib.h @@ -232,6 +232,8 @@ TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event, * * @param requirements space-spearated list of requirements * @param h_payto hash over the account + * @param[out] kyc_expire if satisfied, set to when the KYC + * check data expires * @param ki iterator over satisfied providers * @param ki_cls closure for @a ki * @return true if the KYC check was satisfied @@ -239,6 +241,7 @@ TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event, bool TALER_KYCLOGIC_check_satisfied (const char *requirements, const struct TALER_PaytoHashP *h_payto, + json_t **kyc_details, TALER_KYCLOGIC_KycSatisfiedIterator ki, void *ki_cls); diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index e7084ba41..3954ae4ce 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -306,9 +306,8 @@ load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg, /** - * Add check type to global array of checks. - * First checks if the type already exists, otherwise - * adds a new one. + * Add check type to global array of checks. First checks if the type already + * exists, otherwise adds a new one. * * @param check name of the check * @return pointer into the global list @@ -934,6 +933,10 @@ struct RemoveContext */ unsigned int *needed_cnt; + /** + * Object with information about collected KYC data. + */ + json_t *kyc_details; }; @@ -967,6 +970,14 @@ remove_satisfied (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Provider satisfies check `%s'\n", kc->name); + if (NULL != rc->kyc_details) + { + GNUNET_assert (0 == + json_object_set_new ( + rc->kyc_details, + kc->name, + json_object ())); + } for (unsigned int k = 0; k<*rc->needed_cnt; k++) if (kc == rc->needed[k]) { @@ -1136,6 +1147,7 @@ TALER_KYCLOGIC_kyc_get_details ( bool TALER_KYCLOGIC_check_satisfied (const char *requirements, const struct TALER_PaytoHashP *h_payto, + json_t **kyc_details, TALER_KYCLOGIC_KycSatisfiedIterator ki, void *ki_cls) { @@ -1157,10 +1169,13 @@ TALER_KYCLOGIC_check_satisfied (const char *requirements, { struct RemoveContext rc = { .needed = needed, - .needed_cnt = &needed_cnt + .needed_cnt = &needed_cnt, }; enum GNUNET_DB_QueryStatus qs; + rc.kyc_details = json_object (); + GNUNET_assert (NULL != rc.kyc_details); + /* Check what provider checks are already satisfied for h_payto (with database), remove those from the 'needed' array. */ qs = ki (ki_cls, @@ -1168,6 +1183,15 @@ TALER_KYCLOGIC_check_satisfied (const char *requirements, &remove_satisfied, &rc); GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely? + if (0 != needed_cnt) + { + json_decref (rc.kyc_details); + *kyc_details = NULL; + } + else + { + *kyc_details = rc.kyc_details; + } } return (0 == needed_cnt); } diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c index 6dfbb48d7..68a40a962 100644 --- a/src/lib/exchange_api_kyc_check.c +++ b/src/lib/exchange_api_kyc_check.c @@ -96,6 +96,7 @@ handle_kyc_check_finished (void *cls, break; case MHD_HTTP_OK: { + json_t *kyc_details; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("exchange_sig", &ks.details.success.exchange_sig), @@ -103,6 +104,8 @@ handle_kyc_check_finished (void *cls, &ks.details.success.exchange_pub), GNUNET_JSON_spec_timestamp ("now", &ks.details.success.timestamp), + GNUNET_JSON_spec_json ("kyc_details", + &kyc_details), GNUNET_JSON_spec_end () }; const struct TALER_EXCHANGE_Keys *key_state; @@ -117,6 +120,7 @@ handle_kyc_check_finished (void *cls, ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; } + ks.details.success.kyc_details = kyc_details; key_state = TALER_EXCHANGE_get_keys (kch->exchange); if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, @@ -132,6 +136,7 @@ handle_kyc_check_finished (void *cls, if (GNUNET_OK != TALER_exchange_online_account_setup_success_verify ( &kch->h_payto, + ks.details.success.kyc_details, ks.details.success.timestamp, &ks.details.success.exchange_pub, &ks.details.success.exchange_sig)) diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c index 1762d5a50..c2a841839 100644 --- a/src/util/exchange_signatures.c +++ b/src/util/exchange_signatures.c @@ -449,18 +449,20 @@ struct TALER_ExchangeAccountSetupSuccessPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * Hash over the payto for which the signature was - * made. + * Hash over the payto for which the signature was made. */ struct TALER_PaytoHashP h_payto; - /* FIXME: include details on *which* KYC process was satisfied! #7427 */ + /** + * Hash over details on *which* KYC obligations were discharged! + */ + struct GNUNET_HashCode h_kyc; /** * When was the signature made. - * FIXME: replace by *expiration* time! #7427 */ struct GNUNET_TIME_TimestampNBO timestamp; + }; GNUNET_NETWORK_STRUCT_END @@ -470,6 +472,7 @@ enum TALER_ErrorCode TALER_exchange_online_account_setup_success_sign ( TALER_ExchangeSignCallback scb, const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, struct GNUNET_TIME_Timestamp timestamp, struct TALER_ExchangePublicKeyP *pub, struct TALER_ExchangeSignatureP *sig) @@ -479,10 +482,11 @@ TALER_exchange_online_account_setup_success_sign ( .purpose.purpose = htonl ( TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), .h_payto = *h_payto, - .timestamp = GNUNET_TIME_timestamp_hton ( - timestamp) + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) }; + TALER_json_hash (kyc, + &kyc_purpose.h_kyc); return scb (&kyc_purpose.purpose, pub, sig); @@ -492,6 +496,7 @@ TALER_exchange_online_account_setup_success_sign ( enum GNUNET_GenericReturnValue TALER_exchange_online_account_setup_success_verify ( const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, struct GNUNET_TIME_Timestamp timestamp, const struct TALER_ExchangePublicKeyP *pub, const struct TALER_ExchangeSignatureP *sig) @@ -501,10 +506,11 @@ TALER_exchange_online_account_setup_success_verify ( .purpose.purpose = htonl ( TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), .h_payto = *h_payto, - .timestamp = GNUNET_TIME_timestamp_hton ( - timestamp) + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) }; + TALER_json_hash (kyc, + &kyc_purpose.h_kyc); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS, &kyc_purpose,