From 32fac55f7ea4d29a459310851cfc955204d3f79f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 27 Jan 2023 14:43:25 +0100 Subject: [PATCH] update GET attest logic now that it is clear that we must store KYC attributes locally: --- src/exchange/exchange.conf | 4 + src/exchange/taler-exchange-httpd.c | 25 +++++ src/exchange/taler-exchange-httpd.h | 5 + .../taler-exchange-httpd_reserves_attest.c | 102 ++++++++---------- ...taler-exchange-httpd_reserves_get_attest.c | 80 ++++++-------- src/include/taler_exchangedb_plugin.h | 2 - src/include/taler_kyclogic_lib.h | 21 ---- src/kyclogic/kyclogic_api.c | 14 --- 8 files changed, 115 insertions(+), 138 deletions(-) diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf index 758e77c97..750e71724 100644 --- a/src/exchange/exchange.conf +++ b/src/exchange/exchange.conf @@ -6,6 +6,10 @@ # This must be adjusted to your actual installation. # MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG +# Attribute encryption key for storing attributes encrypted +# in the database. Should be a high-entropy nonce. +ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE + # How long do we allow /keys to be cached at most? The actual # limit is the minimum of this value and the first expected # significant change in /keys based on the expiration times. diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 5501687fa..7f49955dc 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -132,6 +132,11 @@ struct GNUNET_TIME_Relative TEH_reserve_closing_delay; */ struct TALER_MasterPublicKeyP TEH_master_public_key; +/** + * Key used to encrypt KYC attribute data in our database. + */ +struct TALER_AttributeEncryptionKeyP TEH_attribute_key; + /** * Our DB plugin. (global) */ @@ -1862,6 +1867,26 @@ exchange_serve_process_config (void) } GNUNET_free (master_public_key_str); } + + { + char *attr_enc_key_str; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (TEH_cfg, + "exchange", + "ATTRIBUTE_ENCRYPTION_KEY", + &attr_enc_key_str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "ATTRIBUTE_ENCRYPTION_KEY"); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_hash (attr_enc_key_str, + strlen (attr_enc_key_str), + &TEH_attribute_key.hash); + GNUNET_free (attr_enc_key_str); + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Launching exchange with public key `%s'...\n", GNUNET_p2s (&TEH_master_public_key.eddsa_pub)); diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h index 7715444a3..0c2bd9e81 100644 --- a/src/exchange/taler-exchange-httpd.h +++ b/src/exchange/taler-exchange-httpd.h @@ -82,6 +82,11 @@ extern bool TEH_suicide; */ extern struct TALER_MasterPublicKeyP TEH_master_public_key; +/** + * Key used to encrypt KYC attribute data in our database. + */ +extern struct TALER_AttributeEncryptionKeyP TEH_attribute_key; + /** * Our DB plugin. */ diff --git a/src/exchange/taler-exchange-httpd_reserves_attest.c b/src/exchange/taler-exchange-httpd_reserves_attest.c index f88f2c300..0d759e1b5 100644 --- a/src/exchange/taler-exchange-httpd_reserves_attest.c +++ b/src/exchange/taler-exchange-httpd_reserves_attest.c @@ -81,9 +81,9 @@ struct ReserveAttestContext json_t *json_attest; /** - * Error code encountered in interaction with KYC provider. + * Database error codes encountered. */ - enum TALER_ErrorCode ec; + enum GNUNET_DB_QueryStatus qs; /** * Set to true if we did not find the reserve. @@ -152,68 +152,66 @@ reply_reserve_attest_success (struct MHD_Connection *connection, * set based on the details requested by the client. * * @param cls our `struct ReserveAttestContext *` - * @param provider_section KYC provider configuration section - * @param provider_user_id UID at a provider (can be NULL) - * @param legi_id legitimization process ID (can be NULL) + * @param h_payto account for which the attribute data is stored + * @param provider_section provider that must be checked + * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL; + * digits can be 0 if exact day, month or year are unknown + * @param collection_time when was the data collected + * @param expiration_time when does the data expire + * @param enc_attributes_size number of bytes in @a enc_attributes + * @param enc_attributes encrypted attribute data */ static void kyc_process_cb (void *cls, + const struct TALER_PaytoHashP *h_payto, const char *provider_section, - const char *provider_user_id, - const char *legi_id) + const char *birthdate, + struct GNUNET_TIME_Timestamp collection_time, + struct GNUNET_TIME_Timestamp expiration_time, + size_t enc_attributes_size, + const void *enc_attributes) { struct ReserveAttestContext *rsc = cls; - struct GNUNET_TIME_Timestamp etime; json_t *attrs; + json_t *val; + const char *name; bool match = false; - rsc->ec = TALER_KYCLOGIC_user_to_attributes (provider_section, - provider_user_id, - legi_id, - &etime, - &attrs); - if (TALER_EC_NONE != rsc->ec) + if (GNUNET_TIME_absolute_is_past (expiration_time.abs_time)) return; - if (GNUNET_TIME_absolute_is_past (etime.abs_time)) + attrs = TALER_CRYPTO_kyc_attributes_decrypt (&TEH_attribute_key, + enc_attributes, + enc_attributes_size); + json_object_foreach (attrs, name, val) { - json_decref (attrs); - return; - } - { - json_t *val; - const char *name; + bool requested = false; + size_t idx; + json_t *str; - json_object_foreach (attrs, name, val) + if (NULL != json_object_get (rsc->json_attest, + name)) + continue; /* duplicate */ + json_array_foreach (rsc->details, idx, str) { - bool requested = false; - size_t idx; - json_t *str; - - if (NULL != json_object_get (rsc->json_attest, - name)) - continue; /* duplicate */ - json_array_foreach (rsc->details, idx, str) + if (0 == strcmp (json_string_value (str), + name)) { - if (0 == strcmp (json_string_value (str), - name)) - { - requested = true; - break; - } + requested = true; + break; } - if (! requested) - continue; - match = true; - GNUNET_assert (0 == - json_object_set (rsc->json_attest, /* NOT set_new! */ - name, - val)); } + if (! requested) + continue; + match = true; + GNUNET_assert (0 == + json_object_set (rsc->json_attest, /* NOT set_new! */ + name, + val)); } json_decref (attrs); if (! match) return; - rsc->etime = GNUNET_TIME_timestamp_min (etime, + rsc->etime = GNUNET_TIME_timestamp_min (expiration_time, rsc->etime); } @@ -243,7 +241,7 @@ reserve_attest_transaction (void *cls, rsc->json_attest = json_array (); GNUNET_assert (NULL != rsc->json_attest); - qs = TEH_plugin->iterate_kyc_reference (TEH_plugin->cls, + qs = TEH_plugin->select_kyc_attributes (TEH_plugin->cls, &rsc->h_payto, &kyc_process_cb, rsc); @@ -255,7 +253,7 @@ reserve_attest_transaction (void *cls, = TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, - "iterate_kyc_reference"); + "select_kyc_attributes"); return qs; case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); @@ -373,16 +371,8 @@ TEH_handler_reserves_attest (struct TEH_RequestContext *rc, TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, args[0]); } - if (TALER_EC_NONE != rsc.ec) - { - json_decref (rsc.json_attest); - return TALER_MHD_reply_with_ec (rc->connection, - rsc.ec, - NULL); - } - mhd_ret = reply_reserve_attest_success (rc->connection, - &rsc); - return mhd_ret; + return reply_reserve_attest_success (rc->connection, + &rsc); } diff --git a/src/exchange/taler-exchange-httpd_reserves_get_attest.c b/src/exchange/taler-exchange-httpd_reserves_get_attest.c index aa0f26a4a..df800caad 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get_attest.c +++ b/src/exchange/taler-exchange-httpd_reserves_get_attest.c @@ -50,11 +50,6 @@ struct ReserveAttestContext */ json_t *attributes; - /** - * Error code encountered in interaction with KYC provider. - */ - enum TALER_ErrorCode ec; - /** * Set to true if we did not find the reserve. */ @@ -67,53 +62,55 @@ struct ReserveAttestContext * legitimization processes for the given user. * * @param cls our `struct ReserveAttestContext *` - * @param provider_section KYC provider configuration section - * @param provider_user_id UID at a provider (can be NULL) - * @param legi_id legitimization process ID (can be NULL) + * @param h_payto account for which the attribute data is stored + * @param provider_section provider that must be checked + * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL; + * digits can be 0 if exact day, month or year are unknown + * @param collection_time when was the data collected + * @param expiration_time when does the data expire + * @param enc_attributes_size number of bytes in @a enc_attributes + * @param enc_attributes encrypted attribute data */ static void kyc_process_cb (void *cls, + const struct TALER_PaytoHashP *h_payto, const char *provider_section, - const char *provider_user_id, - const char *legi_id) + const char *birthdate, + struct GNUNET_TIME_Timestamp collection_time, + struct GNUNET_TIME_Timestamp expiration_time, + size_t enc_attributes_size, + const void *enc_attributes) { struct ReserveAttestContext *rsc = cls; - struct GNUNET_TIME_Timestamp etime; json_t *attrs; + json_t *val; + const char *name; - rsc->ec = TALER_KYCLOGIC_user_to_attributes (provider_section, - provider_user_id, - legi_id, - &etime, - &attrs); - if (TALER_EC_NONE != rsc->ec) + if (GNUNET_TIME_absolute_is_past (expiration_time.abs_time)) return; - + attrs = TALER_CRYPTO_kyc_attributes_decrypt (&TEH_attribute_key, + enc_attributes, + enc_attributes_size); + json_object_foreach (attrs, name, val) { - json_t *val; - const char *name; + bool duplicate = false; + size_t idx; + json_t *str; - json_object_foreach (attrs, name, val) + json_array_foreach (rsc->attributes, idx, str) { - bool duplicate = false; - size_t idx; - json_t *str; - - json_array_foreach (rsc->attributes, idx, str) + if (0 == strcmp (json_string_value (str), + name)) { - if (0 == strcmp (json_string_value (str), - name)) - { - duplicate = true; - break; - } + duplicate = true; + break; } - if (duplicate) - continue; - GNUNET_assert (0 == - json_array_append (rsc->attributes, - json_string (name))); } + if (duplicate) + continue; + GNUNET_assert (0 == + json_array_append (rsc->attributes, + json_string (name))); } } @@ -144,7 +141,7 @@ reserve_attest_transaction (void *cls, rsc->attributes = json_array (); GNUNET_assert (NULL != rsc->attributes); - qs = TEH_plugin->iterate_kyc_reference (TEH_plugin->cls, + qs = TEH_plugin->select_kyc_attributes (TEH_plugin->cls, &rsc->h_payto, &kyc_process_cb, rsc); @@ -225,13 +222,6 @@ TEH_handler_reserves_get_attest (struct TEH_RequestContext *rc, TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, args[0]); } - if (TALER_EC_NONE != rsc.ec) - { - json_decref (rsc.attributes); - return TALER_MHD_reply_with_ec (rc->connection, - rsc.ec, - NULL); - } return TALER_MHD_REPLY_JSON_PACK ( rc->connection, MHD_HTTP_OK, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index d6bf798c5..b1394b45e 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -6500,8 +6500,6 @@ struct TALER_EXCHANGEDB_Plugin void *kac_cls); - // FIXME: functions below here not yet implemented! - /** * Store KYC attribute data. * diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h index e90dcb1c2..a629543a0 100644 --- a/src/include/taler_kyclogic_lib.h +++ b/src/include/taler_kyclogic_lib.h @@ -313,27 +313,6 @@ TALER_KYCLOGIC_requirements_to_logic (const char *requirements, const char **configuration_section); -/** - * Obtain attributes we collected about a user from a - * provider. - * - * @param provider_section configuration section of a - * provider that triggered KYC process for a user - * @param provider_user_id user ID of the user at the provider - * @param legitimization_id legitimizatin ID of a process - * of that user at the provider - * @param[out] attr_expiration set to when the @a attrs expire - * @param[out] attrs attributes we have about the user - * @return error code, #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -TALER_KYCLOGIC_user_to_attributes (const char *provider_section, - const char *provider_user_id, - const char *legitimization_id, - struct GNUNET_TIME_Timestamp *attr_expiration, - json_t **attrs); - - /** * Obtain the provider logic for a given @a name. * diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index d7ecf51e1..6d92fce68 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -1371,18 +1371,4 @@ TALER_KYCLOGIC_kyc_iterate_thresholds ( } -enum TALER_ErrorCode -TALER_KYCLOGIC_user_to_attributes (const char *provider_section, - const char *provider_user_id, - const char *legitimization_id, - struct GNUNET_TIME_Timestamp *attr_expiration, - json_t **attrs) -{ - GNUNET_break (0); // FIXME: not yet implemented!!! - *attrs = json_object (); - *attr_expiration = GNUNET_TIME_UNIT_ZERO_TS; - return TALER_EC_NONE; -} - - /* end of taler-exchange-httpd_kyc.c */