diff --git a/src/ledger_pki.c b/src/ledger_pki.c new file mode 100644 index 0000000..65d2bb3 --- /dev/null +++ b/src/ledger_pki.c @@ -0,0 +1,76 @@ +#include "apdu_constants.h" +#include "public_keys.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif + +#define KEY_USAGE_STR(x) \ + (x == CERTIFICATE_PUBLIC_KEY_USAGE_GENUINE_CHECK ? "GENUINE_CHECK" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_EXCHANGE_PAYLOAD ? "EXCHANGE_PAYLOAD" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA ? "NFT_METADATA" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_TRUSTED_NAME ? "TRUSTED_NAME" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_BACKUP_PROVIDER ? "BACKUP_PROVIDER" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_RECOVER_ORCHESTRATOR ? "RECOVER_ORCHESTRATOR" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA ? "PLUGIN_METADATA" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META ? "COIN_META" \ + : x == CERTIFICATE_PUBLIC_KEY_USAGE_SEED_ID_AUTH ? "SEED_ID_AUTH" \ + : "Unknown") + +int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t *PubKey, + const uint8_t keyLen, +#ifdef HAVE_LEDGER_PKI + const uint8_t keyUsageExp, +#endif + uint8_t *signature, + const uint8_t sigLen) { + UNUSED(tag); + cx_ecfp_public_key_t verif_key = {0}; + cx_err_t error = CX_INTERNAL_ERROR; +#ifdef HAVE_LEDGER_PKI + uint8_t key_usage = 0; + size_t trusted_name_len = 0; + uint8_t trusted_name[CERTIFICATE_TRUSTED_NAME_MAXLEN] = {0}; + cx_ecfp_384_public_key_t public_key = {0}; +#endif + + PRINTF( + "[%s] " + "=======================================================================================\n", + tag); +#ifdef HAVE_LEDGER_PKI + error = os_pki_get_info(&key_usage, trusted_name, &trusted_name_len, &public_key); + if ((error == 0) && (key_usage == keyUsageExp)) { + PRINTF("[%s] Certificate '%s' loaded for usage 0x%x (%s)\n", + tag, + trusted_name, + key_usage, + KEY_USAGE_STR(key_usage)); + + // Checking the signature with PKI + if (!os_pki_verify(buffer, bufLen, signature, sigLen)) { + PRINTF("%s: Invalid signature\n", tag); +#ifndef HAVE_BYPASS_SIGNATURES + error = APDU_RESPONSE_INVALID_DATA; + goto end; +#endif + } + } else +#endif + { + PRINTF("[%s] ********** No certificate loaded. Using legacy path **********\n", tag); + CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, PubKey, keyLen, &verif_key)); + if (!cx_ecdsa_verify_no_throw(&verif_key, buffer, bufLen, signature, sigLen)) { + PRINTF("%s: Invalid signature\n", tag); +#ifndef HAVE_BYPASS_SIGNATURES + error = APDU_RESPONSE_INVALID_DATA; + goto end; +#endif + } + } + error = CX_OK; +end: + return error; +} diff --git a/src/public_keys.h b/src/public_keys.h index d5964db..18348d6 100644 --- a/src/public_keys.h +++ b/src/public_keys.h @@ -16,6 +16,7 @@ ********************************************************************************/ #pragma once +#include static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { #if defined(HAVE_CAL_TEST_KEY) @@ -101,3 +102,14 @@ static const uint8_t LEDGER_NFT_SELECTOR_PUBLIC_KEY[] = { 0x92, 0xc7, 0xc6, 0x48, 0x0d, 0x39, 0xce, 0xbb, 0xa3 #endif }; + +extern int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t *PubKey, + const uint8_t keyLen, +#ifdef HAVE_LEDGER_PKI + const uint8_t keyUsageExp, +#endif + uint8_t *signature, + const uint8_t sigLen); diff --git a/src_features/provideDomainName/cmd_provide_domain_name.c b/src_features/provideDomainName/cmd_provide_domain_name.c index cfcdc0d..be3c185 100644 --- a/src_features/provideDomainName/cmd_provide_domain_name.c +++ b/src_features/provideDomainName/cmd_provide_domain_name.c @@ -12,6 +12,9 @@ #include "hash_bytes.h" #include "network.h" #include "public_keys.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif #define P1_FIRST_CHUNK 0x01 #define P1_FOLLOWING_CHUNK 0x00 @@ -364,39 +367,36 @@ static bool handle_address(const s_tlv_data *data, */ static bool verify_signature(const s_sig_ctx *sig_ctx) { uint8_t hash[INT256_LENGTH]; - cx_ecfp_public_key_t verif_key; cx_err_t error = CX_INTERNAL_ERROR; +#ifdef HAVE_DOMAIN_NAME_TEST_KEY + e_key_id valid_key_id = KEY_ID_TEST; +#else + e_key_id valid_key_id = KEY_ID_PROD; +#endif + bool ret_code = false; + + if (sig_ctx->key_id != valid_key_id) { + PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); + return false; + } CX_CHECK( cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); - switch (sig_ctx->key_id) { -#ifdef HAVE_DOMAIN_NAME_TEST_KEY - case KEY_ID_TEST: -#else - case KEY_ID_PROD: + + CX_CHECK(check_signature_with_pubkey("Domain Name", + hash, + sizeof(hash), + DOMAIN_NAME_PUB_KEY, + sizeof(DOMAIN_NAME_PUB_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, #endif - CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, - DOMAIN_NAME_PUB_KEY, - sizeof(DOMAIN_NAME_PUB_KEY), - &verif_key)); - break; - default: - PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); - return false; - } - if (!cx_ecdsa_verify_no_throw(&verif_key, - hash, - sizeof(hash), - sig_ctx->input_sig, - sig_ctx->input_sig_size)) { - PRINTF("Domain name signature verification failed!\n"); -#ifndef HAVE_BYPASS_SIGNATURES - return false; -#endif - } - return true; + (uint8_t *) (sig_ctx->input_sig), + sig_ctx->input_sig_size)); + + ret_code = true; end: - return false; + return ret_code; } /** diff --git a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c index e4f9e20..9d9dc0f 100644 --- a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c +++ b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c @@ -5,6 +5,9 @@ #include "os_io_seproxyhal.h" #include "network.h" #include "manage_asset_info.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, @@ -20,22 +23,21 @@ void handleProvideErc20TokenInformation(uint8_t p1, uint8_t tickerLength; uint64_t chain_id; uint8_t hash[INT256_LENGTH]; - cx_ecfp_public_key_t tokenKey; - tokenDefinition_t *token = &get_current_asset_info()->token; + cx_err_t error = CX_INTERNAL_ERROR; PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex); if (dataLength < 1) { - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } tickerLength = workBuffer[offset++]; dataLength--; if ((tickerLength + 1) > sizeof(token->ticker)) { - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } if (dataLength < tickerLength + 20 + 4 + 4) { - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32); memmove(token->ticker, workBuffer + offset, tickerLength); @@ -53,21 +55,26 @@ void handleProvideErc20TokenInformation(uint8_t p1, chain_id = U4BE(workBuffer, offset); if (!app_compatible_with_chain_id(&chain_id)) { UNSUPPORTED_CHAIN_ID_MSG(chain_id); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += 4; dataLength -= 4; - CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), - &tokenKey)); - if (!cx_ecdsa_verify_no_throw(&tokenKey, hash, 32, workBuffer + offset, dataLength)) { -#ifndef HAVE_BYPASS_SIGNATURES - PRINTF("Invalid token signature\n"); - THROW(0x6A80); + error = check_signature_with_pubkey("ERC20 Token Info", + hash, + sizeof(hash), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, #endif + (uint8_t *) (workBuffer + offset), + dataLength); +#ifndef HAVE_BYPASS_SIGNATURES + if (error != CX_OK) { + THROW(APDU_RESPONSE_INVALID_DATA); } +#endif G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex; validate_current_asset_info(); diff --git a/src_features/provideNFTInformation/cmd_provideNFTInfo.c b/src_features/provideNFTInformation/cmd_provideNFTInfo.c index 2b46d9d..3d40965 100644 --- a/src_features/provideNFTInformation/cmd_provideNFTInfo.c +++ b/src_features/provideNFTInformation/cmd_provideNFTInfo.c @@ -9,6 +9,9 @@ #include "network.h" #include "public_keys.h" #include "manage_asset_info.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif #define TYPE_SIZE 1 #define VERSION_SIZE 1 @@ -50,19 +53,29 @@ void handleProvideNFTInformation(uint8_t p1, UNUSED(tx); UNUSED(flags); uint8_t hash[INT256_LENGTH]; - cx_ecfp_public_key_t nftKey; + nftInfo_t *nft = NULL; + size_t offset = 0; + size_t payloadSize = 0; + uint8_t collectionNameLength = 0; + uint64_t chain_id = 0; + uint8_t signatureLen = 0; + cx_err_t error = CX_INTERNAL_ERROR; +#ifdef HAVE_NFT_STAGING_KEY + uint8_t valid_keyId = STAGING_NFT_METADATA_KEY; +#else + uint8_t valid_keyId = PROD_NFT_METADATA_KEY; +#endif + PRINTF("In handle provide NFTInformation\n"); if ((pluginType != ERC721) && (pluginType != ERC1155)) { PRINTF("NFT metadata provided without proper plugin loaded!\n"); THROW(0x6985); } - nftInfo_t *nft = &get_current_asset_info()->nft; + nft = &get_current_asset_info()->nft; PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex); - size_t offset = 0; - if (dataLength <= HEADER_SIZE) { PRINTF("Data too small for headers: expected at least %d, got %d\n", HEADER_SIZE, @@ -70,34 +83,24 @@ void handleProvideNFTInformation(uint8_t p1, THROW(APDU_RESPONSE_INVALID_DATA); } - uint8_t type = workBuffer[offset]; - switch (type) { - case TYPE_1: - break; - default: - PRINTF("Unsupported type %d\n", type); - THROW(APDU_RESPONSE_INVALID_DATA); - break; + if (workBuffer[offset] != TYPE_1) { + PRINTF("Unsupported type %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += TYPE_SIZE; - uint8_t version = workBuffer[offset]; - switch (version) { - case VERSION_1: - break; - default: - PRINTF("Unsupported version %d\n", version); - THROW(APDU_RESPONSE_INVALID_DATA); - break; + if (workBuffer[offset] != VERSION_1) { + PRINTF("Unsupported version %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += VERSION_SIZE; - uint8_t collectionNameLength = workBuffer[offset]; + collectionNameLength = workBuffer[offset]; offset += NAME_LENGTH_SIZE; // Size of the payload (everything except the signature) - size_t payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE + - KEY_ID_SIZE + ALGORITHM_ID_SIZE; + payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE + + KEY_ID_SIZE + ALGORITHM_ID_SIZE; if (dataLength < payloadSize) { PRINTF("Data too small for payload: expected at least %d, got %d\n", payloadSize, @@ -124,7 +127,7 @@ void handleProvideNFTInformation(uint8_t p1, PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset); offset += ADDRESS_LENGTH; - uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); + chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); // this prints raw data, so to have a more meaningful print, display // the buffer before the endianness swap PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset)); @@ -134,35 +137,18 @@ void handleProvideNFTInformation(uint8_t p1, } offset += CHAIN_ID_SIZE; - uint8_t keyId = workBuffer[offset]; - const uint8_t *rawKey; - uint8_t rawKeyLen; - - PRINTF("KeyID: %d\n", keyId); - switch (keyId) { -#ifdef HAVE_NFT_STAGING_KEY - case STAGING_NFT_METADATA_KEY: -#endif - case PROD_NFT_METADATA_KEY: - rawKey = LEDGER_NFT_METADATA_PUBLIC_KEY; - rawKeyLen = sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY); - break; - default: - PRINTF("KeyID %d not supported\n", keyId); - THROW(APDU_RESPONSE_INVALID_DATA); - break; + if (workBuffer[offset] != valid_keyId) { + PRINTF("Unsupported KeyID %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } - PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey); offset += KEY_ID_SIZE; - uint8_t algorithmId = workBuffer[offset]; - PRINTF("Algorithm: %d\n", algorithmId); - - if (algorithmId != ALGORITHM_ID_1) { - PRINTF("Incorrect algorithmId %d\n", algorithmId); + if (workBuffer[offset] != ALGORITHM_ID_1) { + PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]); THROW(APDU_RESPONSE_INVALID_DATA); } offset += ALGORITHM_ID_SIZE; + PRINTF("hashing: %.*H\n", payloadSize, workBuffer); cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash)); @@ -171,7 +157,7 @@ void handleProvideNFTInformation(uint8_t p1, THROW(APDU_RESPONSE_INVALID_DATA); } - uint8_t signatureLen = workBuffer[offset]; + signatureLen = workBuffer[offset]; PRINTF("Signature len: %d\n", signatureLen); if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) { PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n", @@ -187,17 +173,21 @@ void handleProvideNFTInformation(uint8_t p1, THROW(APDU_RESPONSE_INVALID_DATA); } - CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &nftKey)); - if (!cx_ecdsa_verify_no_throw(&nftKey, - hash, - sizeof(hash), - (uint8_t *) workBuffer + offset, - signatureLen)) { -#ifndef HAVE_BYPASS_SIGNATURES - PRINTF("Invalid NFT signature\n"); - THROW(APDU_RESPONSE_INVALID_DATA); + error = check_signature_with_pubkey("NFT Info", + hash, + sizeof(hash), + LEDGER_NFT_METADATA_PUBLIC_KEY, + sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA, #endif + (uint8_t *) (workBuffer + offset), + signatureLen); +#ifndef HAVE_BYPASS_SIGNATURES + if (error != CX_OK) { + THROW(APDU_RESPONSE_INVALID_DATA); } +#endif G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex; validate_current_asset_info(); diff --git a/src_features/setExternalPlugin/cmd_setExternalPlugin.c b/src_features/setExternalPlugin/cmd_setExternalPlugin.c index a2ddd71..9613336 100644 --- a/src_features/setExternalPlugin/cmd_setExternalPlugin.c +++ b/src_features/setExternalPlugin/cmd_setExternalPlugin.c @@ -6,6 +6,9 @@ #include "plugin_utils.h" #include "common_ui.h" #include "os_io_seproxyhal.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif void handleSetExternalPlugin(uint8_t p1, uint8_t p2, @@ -18,41 +21,43 @@ void handleSetExternalPlugin(uint8_t p1, UNUSED(flags); PRINTF("Handling set Plugin\n"); uint8_t hash[INT256_LENGTH]; - cx_ecfp_public_key_t tokenKey; uint8_t pluginNameLength = *workBuffer; + uint32_t params[2]; + cx_err_t error = CX_INTERNAL_ERROR; + PRINTF("plugin Name Length: %d\n", pluginNameLength); const size_t payload_size = 1 + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE; if (dataLength <= payload_size) { PRINTF("data too small: expected at least %d got %d\n", payload_size, dataLength); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } if (pluginNameLength + 1 > sizeof(dataContext.tokenContext.pluginName)) { PRINTF("name length too big: expected max %d, got %d\n", sizeof(dataContext.tokenContext.pluginName), pluginNameLength + 1); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } // check Ledger's signature over the payload cx_hash_sha256(workBuffer, payload_size, hash, sizeof(hash)); - CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), - &tokenKey)); - if (!cx_ecdsa_verify_no_throw(&tokenKey, - hash, - sizeof(hash), - workBuffer + payload_size, - dataLength - payload_size)) { -#ifndef HAVE_BYPASS_SIGNATURES - PRINTF("Invalid plugin signature %.*H\n", - dataLength - payload_size, - workBuffer + payload_size); - THROW(0x6A80); + + error = check_signature_with_pubkey("External Plugin", + hash, + sizeof(hash), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, #endif + (uint8_t *) (workBuffer + payload_size), + dataLength - payload_size); +#ifndef HAVE_BYPASS_SIGNATURES + if (error != CX_OK) { + THROW(APDU_RESPONSE_INVALID_DATA); } +#endif // move on to the rest of the payload parsing workBuffer++; @@ -63,7 +68,6 @@ void handleSetExternalPlugin(uint8_t p1, 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 { diff --git a/src_features/setPlugin/cmd_setPlugin.c b/src_features/setPlugin/cmd_setPlugin.c index d083d9b..7373092 100644 --- a/src_features/setPlugin/cmd_setPlugin.c +++ b/src_features/setPlugin/cmd_setPlugin.c @@ -9,6 +9,9 @@ #include "os_io_seproxyhal.h" #include "network.h" #include "public_keys.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif // Supported internal plugins #define ERC721_STR "ERC721" @@ -82,53 +85,51 @@ void handleSetPlugin(uint8_t p1, UNUSED(flags); PRINTF("Handling set Plugin\n"); uint8_t hash[INT256_LENGTH] = {0}; - cx_ecfp_public_key_t pluginKey = {0}; tokenContext_t *tokenContext = &dataContext.tokenContext; - size_t offset = 0; + uint8_t pluginNameLength = 0; + size_t payloadSize = 0; + uint64_t chain_id = 0; + uint8_t signatureLen = 0; + cx_err_t error = CX_INTERNAL_ERROR; +#ifdef HAVE_NFT_STAGING_KEY + enum KeyId valid_keyId = TEST_PLUGIN_KEY; +#else + enum KeyId valid_keyId = PROD_PLUGIN_KEY; +#endif + enum KeyId keyId; + uint32_t params[2]; if (dataLength <= HEADER_SIZE) { PRINTF("Data too small for headers: expected at least %d, got %d\n", HEADER_SIZE, dataLength); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } - enum Type type = workBuffer[offset]; - PRINTF("Type: %d\n", type); - switch (type) { - case ETH_PLUGIN: - break; - default: - PRINTF("Unsupported type %d\n", type); - THROW(0x6a80); - break; + if (workBuffer[offset] != ETH_PLUGIN) { + PRINTF("Unsupported type %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += TYPE_SIZE; - uint8_t version = workBuffer[offset]; - PRINTF("version: %d\n", version); - switch (version) { - case VERSION_1: - break; - default: - PRINTF("Unsupported version %d\n", version); - THROW(0x6a80); - break; + if (workBuffer[offset] != VERSION_1) { + PRINTF("Unsupported version %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += VERSION_SIZE; - uint8_t pluginNameLength = workBuffer[offset]; + pluginNameLength = workBuffer[offset]; offset += PLUGIN_NAME_LENGTH_SIZE; // Size of the payload (everything except the signature) - size_t payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE + - CHAIN_ID_SIZE + KEY_ID_SIZE + ALGORITHM_ID_SIZE; + payloadSize = HEADER_SIZE + pluginNameLength + ADDRESS_LENGTH + SELECTOR_SIZE + CHAIN_ID_SIZE + + KEY_ID_SIZE + ALGORITHM_ID_SIZE; if (dataLength < payloadSize) { PRINTF("Data too small for payload: expected at least %d, got %d\n", payloadSize, dataLength); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } // `+ 1` because we want to add a null terminating character. @@ -136,7 +137,7 @@ void handleSetPlugin(uint8_t p1, PRINTF("plugin name too big: expected max %d, got %d\n", sizeof(dataContext.tokenContext.pluginName), pluginNameLength + 1); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } // Safe because we've checked the size before. @@ -155,7 +156,7 @@ void handleSetPlugin(uint8_t p1, PRINTF("Selector: %.*H\n", SELECTOR_SIZE, tokenContext->methodSelector); offset += SELECTOR_SIZE; - uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); + chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE); // this prints raw data, so to have a more meaningful print, display // the buffer before the endianness swap PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset)); @@ -165,105 +166,86 @@ void handleSetPlugin(uint8_t p1, } offset += CHAIN_ID_SIZE; - enum KeyId keyId = workBuffer[offset]; - uint8_t const *rawKey; - uint8_t rawKeyLen; - - PRINTF("KeyID: %d\n", keyId); - switch (keyId) { -#ifdef HAVE_NFT_STAGING_KEY - case TEST_PLUGIN_KEY: -#endif - case PROD_PLUGIN_KEY: - rawKey = LEDGER_NFT_SELECTOR_PUBLIC_KEY; - rawKeyLen = sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY); - break; - default: - PRINTF("KeyID %d not supported\n", keyId); - THROW(0x6A80); - break; + keyId = workBuffer[offset]; + if (keyId != valid_keyId) { + PRINTF("Unsupported KeyID %d\n", keyId); + THROW(APDU_RESPONSE_INVALID_DATA); } - - PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey); offset += KEY_ID_SIZE; - uint8_t algorithmId = workBuffer[offset]; - PRINTF("Algorithm: %d\n", algorithmId); - - if (algorithmId != ECC_SECG_P256K1__ECDSA_SHA_256) { - PRINTF("Incorrect algorithmId %d\n", algorithmId); - THROW(0x6a80); + if (workBuffer[offset] != ECC_SECG_P256K1__ECDSA_SHA_256) { + PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += ALGORITHM_ID_SIZE; + PRINTF("hashing: %.*H\n", payloadSize, workBuffer); cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash)); if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE) { PRINTF("Data too short to hold signature length\n"); - THROW(0x6a80); + THROW(APDU_RESPONSE_INVALID_DATA); } - uint8_t signatureLen = workBuffer[offset]; + signatureLen = workBuffer[offset]; PRINTF("Signature len: %d\n", signatureLen); if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) { PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n", MIN_DER_SIG_SIZE, MAX_DER_SIG_SIZE, signatureLen); - THROW(0x6a80); + THROW(APDU_RESPONSE_INVALID_DATA); } offset += SIGNATURE_LENGTH_SIZE; if (dataLength < payloadSize + SIGNATURE_LENGTH_SIZE + signatureLen) { PRINTF("Signature could not fit in data\n"); - THROW(0x6a80); + THROW(APDU_RESPONSE_INVALID_DATA); } - CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &pluginKey)); - if (!cx_ecdsa_verify_no_throw(&pluginKey, - hash, - sizeof(hash), - (unsigned char *) (workBuffer + offset), - signatureLen)) { -#ifndef HAVE_BYPASS_SIGNATURES - PRINTF("Invalid NFT signature\n"); - THROW(0x6A80); + error = check_signature_with_pubkey("Set Plugin", + hash, + sizeof(hash), + LEDGER_NFT_SELECTOR_PUBLIC_KEY, + sizeof(LEDGER_NFT_SELECTOR_PUBLIC_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_PLUGIN_METADATA, #endif + (uint8_t *) (workBuffer + offset), + signatureLen); +#ifndef HAVE_BYPASS_SIGNATURES + if (error != CX_OK) { + THROW(APDU_RESPONSE_INVALID_DATA); } +#endif pluginType = getPluginType(tokenContext->pluginName, pluginNameLength); if (keyId == PROD_PLUGIN_KEY) { if (pluginType != ERC721 && pluginType != ERC1155) { PRINTF("AWS key must only be used to set NFT internal plugins\n"); - THROW(0x6A80); + THROW(APDU_RESPONSE_INVALID_DATA); } } - switch (pluginType) { - case EXTERNAL: { - PRINTF("Check external plugin %s\n", tokenContext->pluginName); + if (pluginType == EXTERNAL) { + PRINTF("Check external plugin %s\n", tokenContext->pluginName); - // Check if the plugin is present on the device - uint32_t params[2]; - params[0] = (uint32_t) 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", tokenContext->pluginName); - memset(tokenContext->pluginName, 0, sizeof(tokenContext->pluginName)); - THROW(0x6984); - } - FINALLY { - } + // Check if the plugin is present on the device + params[0] = (uint32_t) 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", tokenContext->pluginName); + memset(tokenContext->pluginName, 0, sizeof(tokenContext->pluginName)); + THROW(0x6984); + } + FINALLY { } - END_TRY; - break; } - default: - break; + END_TRY; } G_io_apdu_buffer[(*tx)++] = 0x90; diff --git a/src_features/signMessageEIP712/filtering.c b/src_features/signMessageEIP712/filtering.c index efefd64..276fc36 100644 --- a/src_features/signMessageEIP712/filtering.c +++ b/src_features/signMessageEIP712/filtering.c @@ -12,6 +12,9 @@ #include "path.h" #include "ui_logic.h" #include "filtering.h" +#ifdef HAVE_LEDGER_PKI +#include "os_pki.h" +#endif #define FILT_MAGIC_MESSAGE_INFO 183 #define FILT_MAGIC_AMOUNT_JOIN_TOKEN 11 @@ -95,26 +98,26 @@ static bool sig_verif_start(cx_sha256_t *hash_ctx, uint8_t magic) { */ static bool sig_verif_end(cx_sha256_t *hash_ctx, const uint8_t *sig, uint8_t sig_length) { uint8_t hash[INT256_LENGTH]; - cx_ecfp_public_key_t verifying_key; cx_err_t error = CX_INTERNAL_ERROR; + bool ret_code = false; // Finalize hash CX_CHECK(cx_hash_no_throw((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); - CX_CHECK(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), - &verifying_key)); - if (!cx_ecdsa_verify_no_throw(&verifying_key, hash, sizeof(hash), sig, sig_length)) { -#ifndef HAVE_BYPASS_SIGNATURES - PRINTF("Invalid EIP-712 filtering signature\n"); - apdu_response_code = APDU_RESPONSE_INVALID_DATA; - return false; + CX_CHECK(check_signature_with_pubkey("EIP712 Filtering", + hash, + sizeof(hash), + LEDGER_SIGNATURE_PUBLIC_KEY, + sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), +#ifdef HAVE_LEDGER_PKI + CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, #endif - } - return true; + (uint8_t *) (sig), + sig_length)); + + ret_code = true; end: - return false; + return ret_code; } /**