From 0bd5fa717e418c5e02965ac344e2bf1a4a25bef4 Mon Sep 17 00:00:00 2001 From: TamtamHero <10632523+TamtamHero@users.noreply.github.com> Date: Tue, 4 May 2021 23:33:33 +0200 Subject: [PATCH] Add Ledger signature checking for external plugins --- doc/ethapp.asc | 14 +++++++++-- src/tokens.h | 25 ++++++++++++++++++- .../cmd_provideTokenInfo.c | 23 ++++++----------- .../setExternalPlugin/cmd_setExternalPlugin.c | 21 ++++++++++++++-- 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/doc/ethapp.asc b/doc/ethapp.asc index 063588a..7a336bc 100644 --- a/doc/ethapp.asc +++ b/doc/ethapp.asc @@ -245,12 +245,18 @@ None #### Description -This commands provides the name of a plugin that should be called to interpret contract data in the following transaction signing command. +This commands provides the name of a trusted binding of a plugin with a contract address and a supported method selector. This plugin will 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. +The signature is computed on + +len(pluginName) || pluginName || contractAddress || methodSelector + +signed by the following secp256k1 public key 0482bbf2f34f367b2e5bc21847b6566f21f0976b22d3388a9a5e446ac62d25cf725b62a2555b2dd464a4da0ab2f4d506820543af1d242470b1b1a969a27578f353 + #### Coding 'Command' @@ -266,7 +272,11 @@ The function returns an error sw (0x6984) if the plugin requested is not install [width="80%"] |============================================================================================================================== | *Description* | *Length* -| Plugin name | variable +| Length of plugin name | 1 +| plugin name | variable +| contract address | 20 +| method selector | 4 +| signature | variable |============================================================================================================================== 'Output data' diff --git a/src/tokens.h b/src/tokens.h index d76f824..12577e9 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -39,7 +39,30 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA]; #endif -#ifdef HAVE_TOKENS_LIST +#ifndef HAVE_TOKENS_LIST + +#ifndef LEDGER_TEST_PUBLIC_KEY +static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { + // production key 2019-01-11 03:07PM (erc20signer) + 0x04, + 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, 0x0b, 0x68, 0xcd, + 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30, 0xfe, 0x4e, 0x8c, 0xc7, 0x6b, + 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44, 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, + 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83 +}; + +#else +static const uint8_t const LEDGER_SIGNATURE_PUBLIC_KEY[] = { + // test key 2019-01-11 03:07PM (erc20signer) + 0x04, + 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f, 0xe4, 0xc3, 0x04, + 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x84, 0xf4, 0x50, 0x91, 0x42, 0x9b, 0x52, + 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2, 0xd9, 0x28, 0x93, 0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, + 0xd4, 0x18, 0x42, 0x8c, 0xf2, 0x1a, 0x93, 0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79, +}; +#endif + +#else #define NUM_TOKENS_AKROMA 0 #define NUM_TOKENS_ELLAISM 1 diff --git a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c index dba49fd..3f04ff3 100644 --- a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c +++ b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c @@ -1,16 +1,7 @@ #include "shared_context.h" #include "apdu_constants.h" #include "ui_flow.h" - -static const uint8_t const TOKEN_SIGNATURE_PUBLIC_KEY[] = { - // production key 2019-01-11 03:07PM (erc20signer) - 0x04, - - 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, 0x0b, 0x68, 0xcd, - 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30, 0xfe, 0x4e, 0x8c, 0xc7, 0x6b, - - 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44, 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, - 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83}; +#include "tokens.h" #ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR @@ -87,8 +78,8 @@ void handleProvideErc20TokenInformation(uint8_t p1, offset += 4; dataLength -= 4; cx_ecfp_init_public_key(CX_CURVE_256K1, - TOKEN_SIGNATURE_PUBLIC_KEY, - sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), &tokenKey); if (!cx_ecdsa_verify(&tokenKey, CX_LAST, @@ -174,8 +165,8 @@ void handleProvideErc20TokenInformation(uint8_t p1, PRINTF("Descriptor whitelisted\n"); } else { cx_ecfp_init_public_key(CX_CURVE_256K1, - TOKEN_SIGNATURE_PUBLIC_KEY, - sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), &tokenKey); if (!cx_ecdsa_verify(&tokenKey, CX_LAST, @@ -192,8 +183,8 @@ void handleProvideErc20TokenInformation(uint8_t p1, #else cx_ecfp_init_public_key(CX_CURVE_256K1, - TOKEN_SIGNATURE_PUBLIC_KEY, - sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), &tokenKey); if (!cx_ecdsa_verify(&tokenKey, CX_LAST, diff --git a/src_features/setExternalPlugin/cmd_setExternalPlugin.c b/src_features/setExternalPlugin/cmd_setExternalPlugin.c index af1bb4a..03e562e 100644 --- a/src_features/setExternalPlugin/cmd_setExternalPlugin.c +++ b/src_features/setExternalPlugin/cmd_setExternalPlugin.c @@ -1,6 +1,7 @@ #include "shared_context.h" #include "apdu_constants.h" #include "ui_flow.h" +#include "tokens.h" #define CONTRACT_ADDR_SIZE 20 #define SELECTOR_SIZE 4 @@ -14,9 +15,12 @@ void handleSetExternalPlugin(uint8_t p1, UNUSED(p1); UNUSED(p2); UNUSED(flags); - uint8_t pluginNameLength = *workBuffer++; + uint8_t hash[32]; + cx_ecfp_public_key_t tokenKey; + uint8_t pluginNameLength = *workBuffer; + const size_t payload_size = 1 + pluginNameLength + CONTRACT_ADDR_SIZE + SELECTOR_SIZE; - if (dataLength < 1 || dataLength != 1 + pluginNameLength + CONTRACT_ADDR_SIZE + SELECTOR_SIZE) { + if (dataLength <= payload_size) { THROW(0x6A80); } @@ -24,6 +28,19 @@ void handleSetExternalPlugin(uint8_t p1, THROW(0x6A80); } + // check Ledger's signature over the payload + cx_hash_sha256(workBuffer, payload_size, hash, sizeof(hash)); + cx_ecfp_init_public_key(CX_CURVE_256K1, + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), + &tokenKey); + if(!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, sizeof(hash), workBuffer+payload_size, dataLength-payload_size)){ + PRINTF("Invalid external plugin signature %.*H\n", payload_size, workBuffer); + THROW(0x6A80); + } + + // move on to the rest of the payload parsing + workBuffer++; memmove(dataContext.tokenContext.pluginName, workBuffer, pluginNameLength); dataContext.tokenContext.pluginName[pluginNameLength] = '\0'; workBuffer += pluginNameLength;