diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_management_extensions.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_management_extensions.c | 309 |
1 files changed, 111 insertions, 198 deletions
diff --git a/src/exchange/taler-exchange-httpd_management_extensions.c b/src/exchange/taler-exchange-httpd_management_extensions.c index 96b855c3c..3b24bace7 100644 --- a/src/exchange/taler-exchange-httpd_management_extensions.c +++ b/src/exchange/taler-exchange-httpd_management_extensions.c @@ -31,7 +31,6 @@ #include "taler_extensions.h" #include "taler_dbevents.h" - /** * Extension carries the necessary data for a particular extension. * @@ -39,7 +38,7 @@ struct Extension { enum TALER_Extension_Type type; - json_t *config; + json_t *manifest; }; /** @@ -49,43 +48,11 @@ struct SetExtensionsContext { uint32_t num_extensions; struct Extension *extensions; - struct TALER_MasterSignatureP *extensions_sigs; + struct TALER_MasterSignatureP extensions_sig; }; - -/** - * @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 + * Function implementing database transaction to set the manifests of * extensions. It runs the transaction logic. * - IF it returns a non-error code, the transaction logic MUST NOT queue a * MHD response. @@ -107,25 +74,24 @@ set_extensions (void *cls, { struct SetExtensionsContext *sec = cls; - /* save the configurations of all extensions */ + /* save the manifests of all extensions */ for (uint32_t i = 0; i<sec->num_extensions; i++) { struct Extension *ext = &sec->extensions[i]; - struct TALER_MasterSignatureP *sig = &sec->extensions_sigs[i]; + const struct TALER_Extension *taler_ext; enum GNUNET_DB_QueryStatus qs; - char *config; + char *manifest; - /* Sanity check. - * TODO: replace with general API to retrieve the extension-handler - */ - if (0 > ext->type || TALER_Extension_Max <= ext->type) + taler_ext = TALER_extensions_get_by_type (ext->type); + if (NULL == taler_ext) { + /* No such extension found */ GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } - config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS); - if (NULL == config) + manifest = json_dumps (ext->manifest, JSON_COMPACT | JSON_SORT_KEYS); + if (NULL == manifest) { GNUNET_break (0); *mhd_ret = TALER_MHD_reply_with_error (connection, @@ -135,11 +101,12 @@ set_extensions (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - qs = TEH_plugin->set_extension_config ( + qs = TEH_plugin->set_extension_manifest ( TEH_plugin->cls, - TEH_extensions[ext->type]->name, - config, - sig); + taler_ext->name, + manifest); + + free (manifest); if (qs < 0) { @@ -154,41 +121,96 @@ set_extensions (void *cls, /* Success, trigger event */ { - enum TALER_Extension_Type *type = &sec->extensions[i].type; + uint32_t nbo_type = htonl (sec->extensions[i].type); struct GNUNET_DB_EventHeaderP ev = { .size = htons (sizeof (ev)), .type = htons (TALER_DBEVENT_EXCHANGE_EXTENSIONS_UPDATED) }; + TEH_plugin->event_notify (TEH_plugin->cls, &ev, - type, - sizeof(*type)); + &nbo_type, + sizeof(nbo_type)); } } + /* All extensions configured, update the signature */ + TEH_extensions_sig = sec->extensions_sig; + TEH_extensions_signed = true; + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */ } +static enum GNUNET_GenericReturnValue +verify_extensions_from_json ( + const json_t *extensions, + struct SetExtensionsContext *sec) +{ + const char*name; + const struct TALER_Extension *extension; + size_t i = 0; + json_t *manifest; + + GNUNET_assert (NULL != extensions); + GNUNET_assert (json_is_object (extensions)); + + sec->num_extensions = json_object_size (extensions); + sec->extensions = GNUNET_new_array (sec->num_extensions, + struct Extension); + + json_object_foreach ((json_t *) extensions, name, manifest) + { + int critical = 0; + json_t *config; + const char *version = NULL; + + /* load and verify criticality, version, etc. */ + extension = TALER_extensions_get_by_name (name); + if (NULL == extension) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "no such extension: %s\n", name); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + TALER_extensions_parse_manifest ( + manifest, &critical, &version, &config)) + return GNUNET_SYSERR; + + if (critical != extension->critical + || 0 != strcmp (version, extension->version) // FIXME-oec: libtool compare + || NULL == config + || GNUNET_OK != extension->load_config (config, NULL)) + return GNUNET_SYSERR; + + sec->extensions[i].type = extension->type; + sec->extensions[i].manifest = json_copy (manifest); + } + + return GNUNET_OK; +} + + MHD_RESULT TEH_handler_management_post_extensions ( struct MHD_Connection *connection, const json_t *root) { + MHD_RESULT ret; + const json_t *extensions; struct SetExtensionsContext sec = {0}; - json_t *extensions; - json_t *extensions_sigs; struct GNUNET_JSON_Specification top_spec[] = { - GNUNET_JSON_spec_json ("extensions", - &extensions), - GNUNET_JSON_spec_json ("extensions_sigs", - &extensions_sigs), + GNUNET_JSON_spec_object_const ("extensions", + &extensions), + GNUNET_JSON_spec_fixed_auto ("extensions_sig", + &sec.extensions_sig), GNUNET_JSON_spec_end () }; - MHD_RESULT ret; - // Parse the top level json structure + /* Parse the top level json structure */ { enum GNUNET_GenericReturnValue res; @@ -201,159 +223,52 @@ TEH_handler_management_post_extensions ( return MHD_YES; /* failure */ } - // Ensure we have two arrays of the same size - if (! (json_is_array (extensions) && - json_is_array (extensions_sigs)) ) + /* 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, - "array expected for extensions and extensions_sigs"); - } - - sec.num_extensions = json_array_size (extensions_sigs); - if (json_array_size (extensions) != sec.num_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, - "arrays extensions and extensions_sigs are not of the same size"); - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received /management/extensions\n"); - - 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 arrays. - for (unsigned int i = 0; i<sec.num_extensions; i++) - { - // 1. parse the extension out of the json - enum GNUNET_GenericReturnValue res; - const struct TALER_Extension *extension; - const char *name; - struct GNUNET_JSON_Specification ext_spec[] = { - GNUNET_JSON_spec_string ("extension", - &name), - GNUNET_JSON_spec_json ("config", - &sec.extensions[i].config), - GNUNET_JSON_spec_end () - }; - - res = TALER_MHD_parse_json_array (connection, - extensions, - ext_spec, - i, - -1); - if (GNUNET_SYSERR == res) - { - ret = MHD_NO; /* hard failure */ - goto CLEANUP; - } - if (GNUNET_NO == res) - { - ret = MHD_YES; - goto CLEANUP; - } - - /* 2. Make sure name refers to a supported extension */ - if (GNUNET_OK != TALER_extension_get_by_name (name, - (const struct - TALER_Extension **) - TEH_extensions, - &extension)) - { - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid extension type"); - goto CLEANUP; - } - - sec.extensions[i].type = extension->type; - - /* 3. Extract the signature out of the json array */ - { - enum GNUNET_GenericReturnValue res; - struct GNUNET_JSON_Specification sig_spec[] = { - GNUNET_JSON_spec_fixed_auto (NULL, - &sec.extensions_sigs[i]), - GNUNET_JSON_spec_end () - }; - - res = TALER_MHD_parse_json_array (connection, - extensions_sigs, - sig_spec, - i, - -1); - if (GNUNET_SYSERR == res) - { - ret = MHD_NO; /* hard failure */ - goto CLEANUP; - } - if (GNUNET_NO == res) - { - ret = MHD_YES; - goto CLEANUP; - } - } - - /* 4. Verify the signature of the config */ - if (GNUNET_OK != config_verify ( - sec.extensions[i].config, + struct TALER_ExtensionManifestsHashP h_manifests; + + if (GNUNET_OK != + TALER_JSON_extensions_manifests_hash (extensions, + &h_manifests) || + GNUNET_OK != + TALER_exchange_offline_extension_manifests_hash_verify ( + &h_manifests, &TEH_master_public_key, - &sec.extensions_sigs[i])) + &sec.extensions_sig)) { - ret = TALER_MHD_reply_with_error ( + return TALER_MHD_reply_with_error ( connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid signature for extension"); - goto CLEANUP; - } - - /* 5. Make sure the config is sound */ - if (GNUNET_OK != extension->test_config (sec.extensions[i].config)) - { - GNUNET_JSON_parse_free (ext_spec); - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid configuration for extension"); - goto CLEANUP; - + "invalid signuture"); } + } - /* We have a validly signed JSON object for the extension. - * Increment its refcount and free the parser for the extension. - */ - json_incref (sec.extensions[i].config); - GNUNET_JSON_parse_free (ext_spec); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received /management/extensions\n"); - } /* for-loop */ + /* Now parse individual extensions and signatures from those objects. */ + if (GNUNET_OK != + verify_extensions_from_json (extensions, &sec)) + { + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "invalid object"); + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %u extensions\n", sec.num_extensions); - // now run the transaction to persist the configurations + /* now run the transaction to persist the configurations */ { enum GNUNET_GenericReturnValue res; res = TEH_DB_run_transaction (connection, "set extensions", - TEH_MT_OTHER, + TEH_MT_REQUEST_OTHER, &ret, &set_extensions, &sec); @@ -372,14 +287,12 @@ TEH_handler_management_post_extensions ( CLEANUP: for (unsigned int i = 0; i < sec.num_extensions; i++) { - if (NULL != sec.extensions[i].config) + if (NULL != sec.extensions[i].manifest) { - json_decref (sec.extensions[i].config); + json_decref (sec.extensions[i].manifest); } } GNUNET_free (sec.extensions); - GNUNET_free (sec.extensions_sigs); - GNUNET_JSON_parse_free (top_spec); return ret; } |