diff --git a/doc/ethapp.asc b/doc/ethapp.asc index d35664c..063588a 100644 --- a/doc/ethapp.asc +++ b/doc/ethapp.asc @@ -20,6 +20,9 @@ Application version 1.5.0 - 25th of September 2020 - Add SIGN ETH EIP 712 - Add GET ETH2 PUBLIC KEY +## 1.6.3 + - Add SET EXTERNAL PLUGIN + ## About This application describes the APDU messages interface to communicate with the Ethereum application. @@ -237,6 +240,39 @@ signed by the following secp256k1 public key 0482bbf2f34f367b2e5bc21847b6566f21f None + +### SET EXTERNAL PLUGIN + +#### Description + +This commands provides the name of a plugin that should be called to interpret contract data in the following transaction signing command. + +It shall be run immediately before performing a transaction involving a contract supported by this plugin to display the proper information to the user if necessary. + +The function returns an error sw (0x6984) if the plugin requested is not installed on the device, 0x9000 otherwise. + +#### Coding + +'Command' + +[width="80%"] +|============================================================================================================================== +| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* +| E0 | 12 | 00 | 00 | variable | 00 +|============================================================================================================================== + +'Input data' + +[width="80%"] +|============================================================================================================================== +| *Description* | *Length* +| Plugin name | variable +|============================================================================================================================== + +'Output data' + +None + ### GET APP CONFIGURATION #### Description diff --git a/src/apdu_constants.h b/src/apdu_constants.h index 7ead09c..fd3dff9 100644 --- a/src/apdu_constants.h +++ b/src/apdu_constants.h @@ -14,6 +14,7 @@ #define INS_SIGN_EIP_712_MESSAGE 0x0C #define INS_GET_ETH2_PUBLIC_KEY 0x0E #define INS_SET_ETH2_WITHDRAWAL_INDEX 0x10 +#define INS_SET_EXTERNAL_PLUGIN 0x12 #define P1_CONFIRM 0x01 #define P1_NON_CONFIRM 0x00 #define P2_NO_CHAINCODE 0x00 @@ -88,6 +89,13 @@ void handleSignEIP712Message(uint8_t p1, unsigned int *flags, unsigned int *tx); +void handleSetExternalPlugin(uint8_t p1, + uint8_t p2, + uint8_t *workBuffer, + uint16_t dataLength, + unsigned int *flags, + unsigned int *tx); + #ifdef HAVE_ETH2 void handleGetEth2PublicKey(uint8_t p1, diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c index 02d5e33..b9300c6 100644 --- a/src/eth_plugin_handler.c +++ b/src/eth_plugin_handler.c @@ -61,23 +61,31 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress, uint8_t i; const uint8_t **selectors; dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_UNAVAILABLE; - // Handle hardcoded plugin list + PRINTF("Selector %.*H\n", 4, init->selector); - for (i = 0;; i++) { - uint8_t j; - selectors = (const uint8_t **) PIC(INTERNAL_ETH_PLUGINS[i].selectors); - if (selectors == NULL) { - break; - } - for (j = 0; ((j < INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL)); - j++) { - if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) == 0) { - if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) || - ((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) { - strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias); - dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK; - contractAddress = NULL; - break; + if (tmpCtx.transactionContext.externalPluginIsSet) { + PRINTF("External plugin will be used\n"); + dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK; + contractAddress = NULL; + } + else { + // Search internal plugin list + for (i = 0;; i++) { + uint8_t j; + selectors = (const uint8_t **) PIC(INTERNAL_ETH_PLUGINS[i].selectors); + if (selectors == NULL) { + break; + } + for (j = 0; ((j < INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL)); + j++) { + if (memcmp(init->selector, (const void *) PIC(selectors[j]), SELECTOR_SIZE) == 0) { + if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) || + ((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) { + strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias); + dataContext.tokenContext.pluginStatus = ETH_PLUGIN_RESULT_OK; + contractAddress = NULL; + break; + } } } } diff --git a/src/eth_plugin_interface.h b/src/eth_plugin_interface.h index b6a00ac..792d36f 100644 --- a/src/eth_plugin_interface.h +++ b/src/eth_plugin_interface.h @@ -16,7 +16,8 @@ typedef enum { ETH_PLUGIN_FINALIZE = 0x0103, ETH_PLUGIN_PROVIDE_TOKEN = 0x0104, ETH_PLUGIN_QUERY_CONTRACT_ID = 0x0105, - ETH_PLUGIN_QUERY_CONTRACT_UI = 0x0106 + ETH_PLUGIN_QUERY_CONTRACT_UI = 0x0106, + ETH_PLUGIN_CHECK_PRESENCE = 0x01FF } eth_plugin_msg_t; diff --git a/src/eth_plugin_ui.c b/src/eth_plugin_ui.c index fa126d6..c305d9f 100644 --- a/src/eth_plugin_ui.c +++ b/src/eth_plugin_ui.c @@ -23,11 +23,12 @@ void plugin_ui_get_id() { strings.tmp.tmp2, sizeof(strings.tmp.tmp2)); // Query the original contract for ID if it's not an internal alias - if (!eth_plugin_call( - (dataContext.tokenContext.pluginName[0] == '-' ? NULL - : tmpContent.txContent.destination), - ETH_PLUGIN_QUERY_CONTRACT_ID, - (void *) &pluginQueryContractID)) { + if (!eth_plugin_call((dataContext.tokenContext.pluginName[0] == '-' || + tmpCtx.transactionContext.externalPluginIsSet + ? NULL + : tmpContent.txContent.destination), + ETH_PLUGIN_QUERY_CONTRACT_ID, + (void *) &pluginQueryContractID)) { PRINTF("Plugin query contract ID call failed\n"); io_seproxyhal_touch_tx_cancel(NULL); } diff --git a/src/main.c b/src/main.c index dd4e34d..e64b4c6 100644 --- a/src/main.c +++ b/src/main.c @@ -496,6 +496,15 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { tx); break; + case INS_SET_EXTERNAL_PLUGIN: + handleSetExternalPlugin(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + break; + case INS_SIGN: handleSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], diff --git a/src/shared_context.h b/src/shared_context.h index 8d624fc..2259398 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -83,6 +83,7 @@ typedef struct transactionContext_t { tokenDefinition_t tokens[MAX_TOKEN]; uint8_t tokenSet[MAX_TOKEN]; uint8_t currentTokenIndex; + bool externalPluginIsSet; } transactionContext_t; typedef struct messageSigningContext_t { diff --git a/src_features/setExternalPlugin/cmd_setExternalPlugin.c b/src_features/setExternalPlugin/cmd_setExternalPlugin.c new file mode 100644 index 0000000..b5748f7 --- /dev/null +++ b/src_features/setExternalPlugin/cmd_setExternalPlugin.c @@ -0,0 +1,51 @@ +#include "shared_context.h" +#include "apdu_constants.h" +#include "ui_flow.h" + +void handleSetExternalPlugin(uint8_t p1, + uint8_t p2, + uint8_t *workBuffer, + uint16_t dataLength, + unsigned int *flags, + unsigned int *tx) { + UNUSED(p1); + UNUSED(p2); + UNUSED(flags); + uint8_t pluginNameLength = dataLength; + + if (dataLength < 1) { + THROW(0x6A80); + } + + if (pluginNameLength + 1 > sizeof(dataContext.tokenContext.pluginName)) { + THROW(0x6A80); + } + + memmove(dataContext.tokenContext.pluginName, workBuffer, pluginNameLength); + dataContext.tokenContext.pluginName[pluginNameLength] = '\0'; + + PRINTF("Check external plugin %s\n", dataContext.tokenContext.pluginName); + + // Check if the plugin is present on the device + uint32_t params[2]; + params[0] = (uint32_t) dataContext.tokenContext.pluginName; + params[1] = ETH_PLUGIN_CHECK_PRESENCE; + BEGIN_TRY { + TRY { + os_lib_call(params); + } + CATCH_OTHER(e) { + PRINTF("%s external plugin is not present\n", dataContext.tokenContext.pluginName); + THROW(0x6984); + } + FINALLY { + } + } + END_TRY; + + tmpCtx.transactionContext.externalPluginIsSet = true; + PRINTF("Plugin found\n"); + + G_io_apdu_buffer[(*tx)++] = 0x90; + G_io_apdu_buffer[(*tx)++] = 0x00; +} \ No newline at end of file