From ba3be90ed4f10ac21568ce6c753ec452c809cdbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Fri, 21 Jan 2022 00:42:25 +0100 Subject: [PATCH] Simplify extension verification - simplify signature verification for extensions - remove per-extension signatures from DB schema - adjust prepared statements accordingly - adjust DB event handler for extensions --- src/auditordb/plugin_auditordb_postgres.c | 2 +- src/exchange-tools/taler-exchange-offline.c | 124 ++++++++++++----- .../taler-exchange-httpd_extensions.c | 4 +- ...ler-exchange-httpd_management_extensions.c | 129 +++++------------- src/exchangedb/exchange-0001.sql | 3 - src/exchangedb/plugin_exchangedb_postgres.c | 18 +-- src/exchangedb/test_exchangedb.c | 25 +--- src/include/taler_crypto_lib.h | 4 +- src/include/taler_exchangedb_plugin.h | 7 +- src/util/offline_signatures.c | 8 +- 10 files changed, 147 insertions(+), 177 deletions(-) diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c index 7931900a5..e0355d93b 100644 --- a/src/auditordb/plugin_auditordb_postgres.c +++ b/src/auditordb/plugin_auditordb_postgres.c @@ -796,7 +796,7 @@ static enum GNUNET_GenericReturnValue postgres_gc (void *cls) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute now = {0}; struct GNUNET_PQ_QueryParam params_time[] = { GNUNET_PQ_query_param_absolute_time (&now), GNUNET_PQ_query_param_end diff --git a/src/exchange-tools/taler-exchange-offline.c b/src/exchange-tools/taler-exchange-offline.c index 2f4456c89..a3eb1747b 100644 --- a/src/exchange-tools/taler-exchange-offline.c +++ b/src/exchange-tools/taler-exchange-offline.c @@ -1680,9 +1680,76 @@ upload_extensions (const char *exchange_url, size_t idx, const json_t *value) { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "uploading extensions %s\n", - json_dumps (value, JSON_INDENT (2))); + json_t *extensions; + struct TALER_MasterSignatureP sig; + const char *err_name; + unsigned int err_line; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_json ("extensions", + &extensions), + GNUNET_JSON_spec_fixed_auto ("extensions_sig", + &sig), + GNUNET_JSON_spec_end () + }; + + /* 1. Parse the signed extensions */ + if (GNUNET_OK != + GNUNET_JSON_parse (value, + spec, + &err_name, + &err_line)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid input to set extensions: %s#%u at %u (skipping)\n", + err_name, + err_line, + (unsigned int) idx); + json_dumpf (value, + stderr, + JSON_INDENT (2)); + global_ret = EXIT_FAILURE; + test_shutdown (); + return; + } + + /* 2. Verify the signature */ + { + struct TALER_ExtensionConfigHash h_config; + + if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "couldn't hash extensions\n"); + global_ret = EXIT_FAILURE; + test_shutdown (); + return; + } + + if (GNUNET_OK != + load_offline_key (GNUNET_NO)) + return; + + if (GNUNET_OK != TALER_exchange_offline_extension_config_hash_verify ( + &h_config, + &master_pub, + &sig)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "invalid signature for extensions\n"); + global_ret = EXIT_FAILURE; + test_shutdown (); + return; + } + + } + + /* 3. Upload */ + /* TODO */ + + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "\e[33m*TODO*\e[0m\nuploading extensions %s\n", + json_dumps (value, JSON_INDENT (2))); } @@ -3537,43 +3604,36 @@ static void do_extensions_sign (char *const *args) { json_t *obj = json_object (); - json_t *exts = json_object (); - json_t *sigs = json_object (); + json_t *extensions = json_object (); + struct TALER_ExtensionConfigHash h_config; + struct TALER_MasterSignatureP sig; GNUNET_CONFIGURATION_iterate_sections (kcfg, &collect_extensions, - exts); - json_object_set (obj, "extensions", exts); + extensions); - /* sign the extensions */ + // TODO: check size of extensions? + if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config)) { - const char *name; - json_t *config; - - json_object_foreach (exts, name, config){ - struct TALER_ExtensionConfigHash h_config; - struct TALER_MasterSignatureP sig; - - if (GNUNET_OK != TALER_extension_config_hash (config, &h_config)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "error while hashing config for extension %s\n", - name); - return; - } - - TALER_exchange_offline_extension_config_hash_sign (h_config, &master_priv, - &sig); - json_object_update (sigs, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ( - name, - &sig))); - } - + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "error while hashing config for extensions\n"); + return; } - json_object_set (obj, "extensions_sigs", sigs); + if (GNUNET_OK != + load_offline_key (GNUNET_NO)) + return; + + + TALER_exchange_offline_extension_config_hash_sign (&h_config, + &master_priv, + &sig); + json_object_set (obj, "extensions", extensions); + json_object_update (obj, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ( + "extensions_sig", + &sig))); output_operation (OP_EXTENSIONS, obj); } diff --git a/src/exchange/taler-exchange-httpd_extensions.c b/src/exchange/taler-exchange-httpd_extensions.c index 4c826e8bc..8723bebc8 100644 --- a/src/exchange/taler-exchange-httpd_extensions.c +++ b/src/exchange/taler-exchange-httpd_extensions.c @@ -171,7 +171,6 @@ extension_update_event_cb (void *cls, // Get the config from the database as string { char *config_str; - struct TALER_MasterSignatureP config_sig; // ignored enum GNUNET_DB_QueryStatus qs; struct TALER_Extension *extension; json_error_t err; @@ -183,8 +182,7 @@ extension_update_event_cb (void *cls, qs = TEH_plugin->get_extension_config (TEH_plugin->cls, extension->name, - &config_str, - &config_sig); + &config_str); if (qs < 0) { diff --git a/src/exchange/taler-exchange-httpd_management_extensions.c b/src/exchange/taler-exchange-httpd_management_extensions.c index 8d9acbb78..219ec1d3f 100644 --- a/src/exchange/taler-exchange-httpd_management_extensions.c +++ b/src/exchange/taler-exchange-httpd_management_extensions.c @@ -49,41 +49,8 @@ struct SetExtensionsContext { uint32_t num_extensions; struct Extension *extensions; - struct TALER_MasterSignatureP *extensions_sigs; }; - -/** - * @brief verifies the signature a configuration with the offline master key. - * - * @param config configuration of an extension given as JSON object - * @param master_priv offline master public key of the exchange - * @param[out] master_sig signature - * @return GNUNET_OK on success, GNUNET_SYSERR otherwise - */ -static enum GNUNET_GenericReturnValue -config_verify ( - const json_t *config, - const struct TALER_MasterPublicKeyP *master_pub, - const struct TALER_MasterSignatureP *master_sig - ) -{ - enum GNUNET_GenericReturnValue ret; - struct TALER_ExtensionConfigHash h_config; - - ret = TALER_extension_config_hash (config, &h_config); - if (GNUNET_OK != ret) - { - GNUNET_break (0); - return ret; - } - - return TALER_exchange_offline_extension_config_hash_verify (h_config, - master_pub, - master_sig); -} - - /** * Function implementing database transaction to set the configuration of * extensions. It runs the transaction logic. @@ -111,7 +78,6 @@ set_extensions (void *cls, for (uint32_t i = 0; inum_extensions; i++) { struct Extension *ext = &sec->extensions[i]; - struct TALER_MasterSignatureP *sig = &sec->extensions_sigs[i]; enum GNUNET_DB_QueryStatus qs; char *config; @@ -138,8 +104,7 @@ set_extensions (void *cls, qs = TEH_plugin->set_extension_config ( TEH_plugin->cls, TEH_extensions[ext->type]->name, - config, - sig); + config); if (qs < 0) { @@ -178,12 +143,12 @@ TEH_handler_management_post_extensions ( { MHD_RESULT ret; json_t *extensions; - json_t *extensions_sigs; + struct TALER_MasterSignatureP sig = {0}; struct GNUNET_JSON_Specification top_spec[] = { GNUNET_JSON_spec_json ("extensions", &extensions), - GNUNET_JSON_spec_json ("extensions_sigs", - &extensions_sigs), + GNUNET_JSON_spec_fixed_auto ("extensions_sig", + &sig), GNUNET_JSON_spec_end () }; struct SetExtensionsContext sec = {0}; @@ -201,38 +166,51 @@ TEH_handler_management_post_extensions ( return MHD_YES; /* failure */ } - /* Ensure we have two objects of the same size */ - if (! (json_is_object (extensions) && - json_is_object (extensions_sigs)) ) + /* Ensure we have an object */ + if (! json_is_object (extensions)) { - GNUNET_break_op (0); GNUNET_JSON_parse_free (top_spec); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, - "objects expected for extensions and extensions_sigs"); + "invalid object"); } - sec.num_extensions = json_object_size (extensions); - if (json_object_size (extensions_sigs) != sec.num_extensions) + /* Verify the signature */ { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (top_spec); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "objects extensions and extensions_sigs are not of the same size"); + struct TALER_ExtensionConfigHash h_config; + if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config)) + { + GNUNET_JSON_parse_free (top_spec); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "invalid object, non-hashable"); + } + + if (GNUNET_OK != TALER_exchange_offline_extension_config_hash_verify ( + &h_config, + &TEH_master_public_key, + &sig)) + { + GNUNET_JSON_parse_free (top_spec); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "invalid signuture"); + } } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received /management/extensions\n"); + sec.num_extensions = json_object_size (extensions); sec.extensions = GNUNET_new_array (sec.num_extensions, struct Extension); - sec.extensions_sigs = GNUNET_new_array (sec.num_extensions, - struct TALER_MasterSignatureP); /* Now parse individual extensions and signatures from those objects. */ { @@ -261,45 +239,7 @@ TEH_handler_management_post_extensions ( sec.extensions[idx].config = config; sec.extensions[idx].type = extension->type; - /* 2. Extract the corresponding signature */ - { - struct GNUNET_JSON_Specification sig_spec[] = { - GNUNET_JSON_spec_fixed_auto (name, - &sec.extensions_sigs[idx]), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != TALER_MHD_parse_json_data (connection, - extensions_sigs, - sig_spec)) - { - GNUNET_JSON_parse_free (sig_spec); - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "extension signature missing"); - goto CLEANUP; - } - - GNUNET_JSON_parse_free (sig_spec); - } - - /* 3. Verify the signature of the config */ - if (GNUNET_OK != config_verify ( - sec.extensions[idx].config, - &TEH_master_public_key, - &sec.extensions_sigs[idx])) - { - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid signature for extension"); - goto CLEANUP; - } - - /* 4. Make sure the config is sound */ + /* 2. Make sure the config is sound */ if (GNUNET_OK != extension->test_config (sec.extensions[idx].config)) { ret = TALER_MHD_reply_with_error ( @@ -356,7 +296,6 @@ CLEANUP: } } GNUNET_free (sec.extensions); - GNUNET_free (sec.extensions_sigs); GNUNET_JSON_parse_free (top_spec); return ret; } diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql index 51fd26eca..2953797dc 100644 --- a/src/exchangedb/exchange-0001.sql +++ b/src/exchangedb/exchange-0001.sql @@ -298,7 +298,6 @@ CREATE TABLE IF NOT EXISTS extensions (extension_id BIGSERIAL UNIQUE ,name VARCHAR NOT NULL UNIQUE ,config BYTEA NOT NULL - ,config_sig BYTEA NOT NULL ); COMMENT ON TABLE extensions IS 'Configurations of the activated extensions'; @@ -306,8 +305,6 @@ COMMENT ON COLUMN extensions.name IS 'Name of the extension'; COMMENT ON COLUMN extensions.config IS 'Configuration of the extension as JSON-blob'; -COMMENT ON COLUMN extensions.config - IS 'Signature of the configuration of an extension, signed with the master key of the exchange'; CREATE TABLE IF NOT EXISTS known_coins diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index d33f958be..bb952f084 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -2745,16 +2745,15 @@ prepare_statements (struct PostgresClosure *pg) /* Used in #postgres_set_extension_config */ GNUNET_PQ_make_prepare ( "set_extension_config", - "INSERT INTO extensions (name, config, config_sig) VALUES ($1, $2, $3) " + "INSERT INTO extensions (name, config) VALUES ($1, $2) " "ON CONFLICT (name) " - "DO UPDATE SET (config, config_sig) = ($2, $3)", - 3), + "DO UPDATE SET config=$2", + 2), /* Used in #postgres_get_extension_config */ GNUNET_PQ_make_prepare ( "get_extension_config", "SELECT " - " config, " - " config_sig " + " config " "FROM extensions" " WHERE name=$1;", 1), @@ -11413,20 +11412,17 @@ postgres_delete_shard_locks (void *cls) * @param cls the @e cls of this struct with the plugin-specific state * @param extension_name the name of the extension * @param config JSON object of the configuration as string - * @param config_sig signature of the configuration by the offline master key * @return transaction status code */ enum GNUNET_DB_QueryStatus postgres_set_extension_config (void *cls, const char *extension_name, - const char *config, - const struct TALER_MasterSignatureP *config_sig) + const char *config) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (extension_name), GNUNET_PQ_query_param_string (config), - GNUNET_PQ_query_param_auto_from_type (config_sig), GNUNET_PQ_query_param_end }; @@ -11448,8 +11444,7 @@ postgres_set_extension_config (void *cls, enum GNUNET_DB_QueryStatus postgres_get_extension_config (void *cls, const char *extension_name, - char **config, - struct TALER_MasterSignatureP *config_sig) + char **config) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { @@ -11458,7 +11453,6 @@ postgres_get_extension_config (void *cls, }; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_string ("config", config), - GNUNET_PQ_result_spec_auto_from_type ("config_sig", config_sig), GNUNET_PQ_result_spec_end }; diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 6cee225cc..cc91e6806 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -115,51 +115,36 @@ static enum GNUNET_GenericReturnValue test_extension_config (void) { char *config; - struct TALER_MasterSignatureP sig; - - memset (&sig, 0x42, sizeof(sig)); FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->get_extension_config (plugin->cls, "fnord", - &config, - &sig)); + &config)); - sig.eddsa_signature.r[23] = 0x23; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->set_extension_config (plugin->cls, "fnord", - "bar", - &sig)); + "bar")); - memset (&sig, 0, sizeof(sig)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->get_extension_config (plugin->cls, "fnord", - &config, - &sig)); + &config)); FAILIF (0 != strcmp ("bar", config)); - FAILIF (0x23 != sig.eddsa_signature.r[23]); - /* let's do this again! */ - memset (&sig, 0x42, sizeof(sig)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->set_extension_config (plugin->cls, "fnord", - "buzz", - &sig)); + "buzz")); - memset (&sig, 0, sizeof(sig)); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->get_extension_config (plugin->cls, "fnord", - &config, - &sig)); + &config)); FAILIF (0 != strcmp ("buzz", config)); - FAILIF (0x42 != sig.eddsa_signature.r[23]); return GNUNET_OK; drop: diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index f1fa0285d..6a805b645 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -2536,7 +2536,7 @@ TALER_merchant_wire_signature_make ( */ void TALER_exchange_offline_extension_config_hash_sign ( - const struct TALER_ExtensionConfigHash h_config, + const struct TALER_ExtensionConfigHash *h_config, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig); @@ -2552,7 +2552,7 @@ TALER_exchange_offline_extension_config_hash_sign ( */ enum GNUNET_GenericReturnValue TALER_exchange_offline_extension_config_hash_verify ( - const struct TALER_ExtensionConfigHash h_config, + const struct TALER_ExtensionConfigHash *h_config, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig ); diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 630fcb631..1b019c747 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4027,14 +4027,12 @@ struct TALER_EXCHANGEDB_Plugin * @param cls the @e cls of this struct with the plugin-specific state * @param extension_name the name of the extension * @param config JSON object of the configuration as string - * @param config_sig signature of the configuration by the offline master key * @return transaction status code */ enum GNUNET_DB_QueryStatus (*set_extension_config)(void *cls, const char *extension_name, - const char *config, - const struct TALER_MasterSignatureP *config_sig); + const char *config); /** * Function called to retrieve the configuration of an extension @@ -4049,8 +4047,7 @@ struct TALER_EXCHANGEDB_Plugin enum GNUNET_DB_QueryStatus (*get_extension_config)(void *cls, const char *extension_name, - char **config, - struct TALER_MasterSignatureP *config_sig); + char **config); }; diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c index 1240a8bc5..ab2988349 100644 --- a/src/util/offline_signatures.c +++ b/src/util/offline_signatures.c @@ -492,14 +492,14 @@ TALER_exchange_offline_wire_fee_verify ( void TALER_exchange_offline_extension_config_hash_sign ( - const struct TALER_ExtensionConfigHash h_config, + const struct TALER_ExtensionConfigHash *h_config, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterExtensionConfigurationPS ec = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.size = htonl (sizeof(ec)), - .h_config = h_config + .h_config = *h_config }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &ec, @@ -509,7 +509,7 @@ TALER_exchange_offline_extension_config_hash_sign ( enum GNUNET_GenericReturnValue TALER_exchange_offline_extension_config_hash_verify ( - const struct TALER_ExtensionConfigHash h_config, + const struct TALER_ExtensionConfigHash *h_config, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig ) @@ -517,7 +517,7 @@ TALER_exchange_offline_extension_config_hash_verify ( struct TALER_MasterExtensionConfigurationPS ec = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.size = htonl (sizeof(ec)), - .h_config = h_config + .h_config = *h_config }; return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_EXTENSION,