Multicoin support - support specific dashboard icon, fix coin ID in message signature, implement GET COIN VERSION / SET ALTERNATE COIN VERSION
Multicoin support
This commit is contained in:
parent
170945c40e
commit
7266eed882
|
@ -2,6 +2,7 @@ bin
|
|||
debug
|
||||
dep
|
||||
obj
|
||||
src/u2f_crypto_data.h
|
||||
src/glyphs.c
|
||||
|
||||
|
||||
|
||||
|
|
2
TODO.md
2
TODO.md
|
@ -1,7 +1,7 @@
|
|||
# BTC Application TODOs
|
||||
|
||||
- [X] Sign message support
|
||||
- [ ] Altcoins fixes (signing message format, prompts)
|
||||
- [X] Altcoins fixes (signing message format, prompts)
|
||||
- [ ] Support an arbitrary number of TX outputs
|
||||
- [ ] Support device / PIN locking in next firmware update
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 75 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 67 B |
|
@ -58,6 +58,7 @@
|
|||
#define BTCHIP_INS_SET_USER_KEYCARD 0x10
|
||||
#define BTCHIP_INS_SETUP_SECURE_SCREEN 0x12
|
||||
#define BTCHIP_INS_SET_ALTERNATE_COIN_VER 0x14
|
||||
#define BTCHIP_INS_GET_COIN_VER 0x16
|
||||
|
||||
#define BTCHIP_INS_STORE_TRUST_ROOT_BIP70 0x30
|
||||
#define BTCHIP_INS_CREATE_CERTIFICATE_BIP70 0x32
|
||||
|
@ -152,5 +153,6 @@ unsigned short btchip_apdu_get_random(void);
|
|||
unsigned short btchip_apdu_get_firmware_version(void);
|
||||
|
||||
unsigned short btchip_apdu_set_alternate_coin_version(void);
|
||||
unsigned short btchip_apdu_get_coin_version(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "btchip_filesystem_tx.h"
|
||||
|
||||
#define MAX_OUTPUT_TO_CHECK 500
|
||||
#define MAX_COIN_ID 10
|
||||
#define MAX_SHORT_COIN_ID 4
|
||||
|
||||
#define MAGIC_TRUSTED_INPUT 0x32
|
||||
#define MAGIC_DEV_KEY 0x01
|
||||
|
@ -143,6 +145,14 @@ struct btchip_context_s {
|
|||
unsigned char payToAddressVersion;
|
||||
/** Current Pay To Script Hash version */
|
||||
unsigned char payToScriptHashVersion;
|
||||
/** Current Coin ID */
|
||||
unsigned char coinId[MAX_COIN_ID];
|
||||
/** Current short Coin ID */
|
||||
unsigned char shortCoinId[MAX_SHORT_COIN_ID];
|
||||
/** Current Coin ID length */
|
||||
unsigned char coinIdLength;
|
||||
/** Current short Coin ID length */
|
||||
unsigned char shortCoinIdLength;
|
||||
|
||||
/** Non protected transaction context */
|
||||
|
||||
|
@ -192,6 +202,7 @@ struct btchip_context_s {
|
|||
// was previously in NVRAM
|
||||
btchip_transaction_summary_t transactionSummary;
|
||||
|
||||
|
||||
unsigned short hashedMessageLength;
|
||||
|
||||
union {
|
||||
|
|
|
@ -37,6 +37,14 @@ struct btchip_config_s {
|
|||
unsigned char options;
|
||||
unsigned char payToAddressVersion;
|
||||
unsigned char payToScriptHashVersion;
|
||||
/** Current Coin ID */
|
||||
unsigned char coinId[MAX_COIN_ID];
|
||||
/** Current short Coin ID */
|
||||
unsigned char shortCoinId[MAX_SHORT_COIN_ID];
|
||||
/** Current Coin ID length */
|
||||
unsigned char coinIdLength;
|
||||
/** Current short Coin ID length */
|
||||
unsigned char shortCoinIdLength;
|
||||
};
|
||||
typedef struct btchip_config_s btchip_config_t;
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Ledger Blue - Bitcoin Wallet
|
||||
* (c) 2016 Ledger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
********************************************************************************/
|
||||
|
||||
#include "btchip_internal.h"
|
||||
#include "btchip_apdu_constants.h"
|
||||
|
||||
#define P1_VERSION_ONLY 0x00
|
||||
#define P1_VERSION_COINID 0x01
|
||||
|
||||
unsigned short btchip_apdu_get_coin_version() {
|
||||
uint8_t offset = 0;
|
||||
|
||||
SB_CHECK(N_btchip.bkp.config.operationMode);
|
||||
if ((SB_GET(N_btchip.bkp.config.operationMode) ==
|
||||
BTCHIP_MODE_SETUP_NEEDED) ||
|
||||
(SB_GET(N_btchip.bkp.config.operationMode) == BTCHIP_MODE_ISSUER)) {
|
||||
return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
G_io_apdu_buffer[offset++] = btchip_context_D.payToAddressVersion;
|
||||
G_io_apdu_buffer[offset++] = btchip_context_D.payToScriptHashVersion;
|
||||
G_io_apdu_buffer[offset++] = btchip_context_D.coinIdLength;
|
||||
os_memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId,
|
||||
btchip_context_D.coinIdLength);
|
||||
offset += btchip_context_D.coinIdLength;
|
||||
G_io_apdu_buffer[offset++] = btchip_context_D.shortCoinIdLength;
|
||||
os_memmove(G_io_apdu_buffer + offset, btchip_context_D.shortCoinId,
|
||||
btchip_context_D.shortCoinIdLength);
|
||||
offset += btchip_context_D.shortCoinIdLength;
|
||||
btchip_context_D.outLength = offset;
|
||||
|
||||
return BTCHIP_SW_OK;
|
||||
}
|
|
@ -18,9 +18,25 @@
|
|||
#include "btchip_internal.h"
|
||||
#include "btchip_apdu_constants.h"
|
||||
|
||||
#define P1_VERSION_ONLY 0x00
|
||||
#define P1_VERSION_COINID 0x01
|
||||
|
||||
unsigned short btchip_apdu_set_alternate_coin_version() {
|
||||
if (G_io_apdu_buffer[ISO_OFFSET_LC] != 0x02) {
|
||||
return BTCHIP_SW_INCORRECT_LENGTH;
|
||||
uint8_t offset = ISO_OFFSET_CDATA;
|
||||
unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1];
|
||||
if ((p1 != P1_VERSION_ONLY) && (p1 != P1_VERSION_COINID)) {
|
||||
return BTCHIP_SW_INCORRECT_P1_P2;
|
||||
}
|
||||
|
||||
if (p1 == P1_VERSION_ONLY) {
|
||||
if (G_io_apdu_buffer[ISO_OFFSET_LC] != 0x02) {
|
||||
return BTCHIP_SW_INCORRECT_LENGTH;
|
||||
}
|
||||
} else {
|
||||
if (G_io_apdu_buffer[ISO_OFFSET_LC] >
|
||||
4 + MAX_COIN_ID + MAX_SHORT_COIN_ID) {
|
||||
return BTCHIP_SW_INCORRECT_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
SB_CHECK(N_btchip.bkp.config.operationMode);
|
||||
|
@ -34,9 +50,23 @@ unsigned short btchip_apdu_set_alternate_coin_version() {
|
|||
return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
btchip_context_D.payToAddressVersion = G_io_apdu_buffer[ISO_OFFSET_CDATA];
|
||||
btchip_context_D.payToScriptHashVersion =
|
||||
G_io_apdu_buffer[ISO_OFFSET_CDATA + 1];
|
||||
btchip_context_D.payToAddressVersion = G_io_apdu_buffer[offset++];
|
||||
btchip_context_D.payToScriptHashVersion = G_io_apdu_buffer[offset++];
|
||||
if (p1 == P1_VERSION_COINID) {
|
||||
uint8_t coinIdLength = G_io_apdu_buffer[offset];
|
||||
uint8_t shortCoinIdLength = G_io_apdu_buffer[offset + 1 + coinIdLength];
|
||||
if ((coinIdLength > MAX_COIN_ID) ||
|
||||
(shortCoinIdLength > MAX_SHORT_COIN_ID)) {
|
||||
return BTCHIP_SW_INCORRECT_DATA;
|
||||
}
|
||||
os_memmove(btchip_context_D.coinId, G_io_apdu_buffer + offset + 1,
|
||||
coinIdLength);
|
||||
btchip_context_D.coinIdLength = coinIdLength;
|
||||
offset += 1 + coinIdLength;
|
||||
os_memmove(btchip_context_D.shortCoinId, G_io_apdu_buffer + offset + 1,
|
||||
shortCoinIdLength);
|
||||
btchip_context_D.shortCoinIdLength = shortCoinIdLength;
|
||||
}
|
||||
|
||||
return BTCHIP_SW_OK;
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@ void btchip_autosetup() {
|
|||
// supporting multi output
|
||||
SB_SET(config.supportedModes, BTCHIP_MODE_WALLET);
|
||||
SB_SET(config.operationMode, BTCHIP_MODE_WALLET);
|
||||
#ifdef HAVE_DEFAULT_TESTNET
|
||||
config.payToAddressVersion = 111;
|
||||
config.payToScriptHashVersion = 196;
|
||||
#else
|
||||
config.payToAddressVersion = 0;
|
||||
config.payToScriptHashVersion = 5;
|
||||
#endif
|
||||
config.payToAddressVersion = BTCHIP_P2PKH_VERSION;
|
||||
config.payToScriptHashVersion = BTCHIP_P2SH_VERSION;
|
||||
config.coinIdLength = strlen(BTCHIP_COINID);
|
||||
os_memmove(config.coinId, BTCHIP_COINID, config.coinIdLength);
|
||||
config.shortCoinIdLength = strlen(BTCHIP_COINID_SHORT);
|
||||
os_memmove(config.shortCoinId, BTCHIP_COINID_SHORT,
|
||||
config.shortCoinIdLength);
|
||||
nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config));
|
||||
cx_rng(tmp, sizeof(tmp));
|
||||
cx_des_init_key(tmp, sizeof(tmp), &desKey);
|
||||
|
|
|
@ -121,6 +121,13 @@ unsigned short btchip_apdu_sign_message_internal() {
|
|||
cx_sha256_init(&btchip_context_D.transactionHashFull);
|
||||
cx_sha256_init(
|
||||
&btchip_context_D.transactionHashAuthorization);
|
||||
chunkLength =
|
||||
btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH;
|
||||
cx_hash(&btchip_context_D.transactionHashFull.header, 0,
|
||||
&chunkLength, 1, NULL);
|
||||
cx_hash(&btchip_context_D.transactionHashFull.header, 0,
|
||||
btchip_context_D.coinId,
|
||||
btchip_context_D.coinIdLength, NULL);
|
||||
cx_hash(&btchip_context_D.transactionHashFull.header, 0,
|
||||
(unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL);
|
||||
if (btchip_context_D.transactionSummary.messageLength <
|
||||
|
|
|
@ -44,6 +44,14 @@ void btchip_context_init() {
|
|||
N_btchip.bkp.config.payToAddressVersion;
|
||||
btchip_context_D.payToScriptHashVersion =
|
||||
N_btchip.bkp.config.payToScriptHashVersion;
|
||||
btchip_context_D.coinIdLength = N_btchip.bkp.config.coinIdLength;
|
||||
os_memmove(btchip_context_D.coinId, N_btchip.bkp.config.coinId,
|
||||
N_btchip.bkp.config.coinIdLength);
|
||||
btchip_context_D.shortCoinIdLength =
|
||||
N_btchip.bkp.config.shortCoinIdLength;
|
||||
os_memmove(btchip_context_D.shortCoinId,
|
||||
N_btchip.bkp.config.shortCoinId,
|
||||
N_btchip.bkp.config.shortCoinIdLength);
|
||||
SB_CHECK(N_btchip.bkp.config.operationMode);
|
||||
}
|
||||
if (!N_btchip.storageInitialized) {
|
||||
|
|
|
@ -40,9 +40,8 @@ unsigned char const BASE58ALPHABET[] = {
|
|||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||
|
||||
unsigned char const SIGNMAGIC[] = {0x18, 'B', 'i', 't', 'c', 'o', 'i', 'n', ' ',
|
||||
'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', 'e',
|
||||
's', 's', 'a', 'g', 'e', ':', '\n'};
|
||||
unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M',
|
||||
'e', 's', 's', 'a', 'g', 'e', ':', '\n'};
|
||||
|
||||
unsigned char const TWOPOWER[] = {0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80};
|
||||
|
@ -61,6 +60,7 @@ unsigned char const DISPATCHER_CLA[] = {
|
|||
BTCHIP_CLA, // btchip_apdu_get_random,
|
||||
BTCHIP_CLA, // btchip_apdu_get_firmware_version,
|
||||
BTCHIP_CLA, // btchip_apdu_set_alternate_coin_version
|
||||
BTCHIP_CLA, // btchip_apdu_get_coin_version
|
||||
};
|
||||
|
||||
unsigned char const DISPATCHER_INS[] = {
|
||||
|
@ -77,6 +77,7 @@ unsigned char const DISPATCHER_INS[] = {
|
|||
BTCHIP_INS_GET_RANDOM, // btchip_apdu_get_random,
|
||||
BTCHIP_INS_GET_FIRMWARE_VERSION, // btchip_apdu_get_firmware_version,
|
||||
BTCHIP_INS_SET_ALTERNATE_COIN_VER, // btchip_apdu_set_alternate_coin_version
|
||||
BTCHIP_INS_GET_COIN_VER, // btchip_apdu_get_coin_version
|
||||
};
|
||||
|
||||
unsigned char const DISPATCHER_DATA_IN[] = {
|
||||
|
@ -93,6 +94,7 @@ unsigned char const DISPATCHER_DATA_IN[] = {
|
|||
0, // btchip_apdu_get_random,
|
||||
0, // btchip_apdu_get_firmware_version,
|
||||
1, // btchip_apdu_set_alternate_coin_version
|
||||
0, // btchip_apdu_get_coin_version
|
||||
};
|
||||
|
||||
apduProcessingFunction const DISPATCHER_FUNCTIONS[] = {
|
||||
|
@ -109,4 +111,5 @@ apduProcessingFunction const DISPATCHER_FUNCTIONS[] = {
|
|||
btchip_apdu_get_random,
|
||||
btchip_apdu_get_firmware_version,
|
||||
btchip_apdu_set_alternate_coin_version,
|
||||
btchip_apdu_get_coin_version,
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "btchip_internal.h"
|
||||
|
||||
#define SIGNMAGIC_LENGTH 25
|
||||
#define SIGNMAGIC_LENGTH 17
|
||||
|
||||
extern unsigned char const WIDE HEXDIGITS[16];
|
||||
extern unsigned char const WIDE BASE58TABLE[128];
|
||||
|
@ -49,7 +49,7 @@ extern unsigned char const WIDE TWOPOWER[8];
|
|||
|
||||
#define APDU_BASE_LENGTH 13
|
||||
|
||||
#define DISPATCHER_APDUS 13
|
||||
#define DISPATCHER_APDUS 14
|
||||
|
||||
typedef unsigned short (*WIDE apduProcessingFunction)(void);
|
||||
|
||||
|
|
67
src/main.c
67
src/main.c
|
@ -144,7 +144,8 @@ const bagl_element_t ui_idle_nanos[] = {
|
|||
NULL,
|
||||
NULL},
|
||||
|
||||
{{BAGL_ICON, 0x01, 17, 9, 14, 14, 0, 0, 0, 0xFFFFFF, 0x000000, 0,
|
||||
#ifdef COIN_BITCOIN
|
||||
{{BAGL_ICON, 0x01, 12, 9, 14, 14, 0, 0, 0, 0xFFFFFF, 0x000000, 0,
|
||||
BAGL_GLYPH_ICON_BITCOIN_BADGE},
|
||||
NULL,
|
||||
0,
|
||||
|
@ -153,8 +154,9 @@ const bagl_element_t ui_idle_nanos[] = {
|
|||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{{BAGL_LABELINE, 0x01, 38, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
|
||||
BAGL_FONT_OPEN_SANS_REGULAR_11px, 0},
|
||||
#endif // COIN_BITCOIN
|
||||
{{BAGL_LABELINE, 0x01, 33, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
|
||||
BAGL_FONT_OPEN_SANS_EXTRABOLD_11px, 0},
|
||||
"Use wallet to",
|
||||
0,
|
||||
0,
|
||||
|
@ -162,8 +164,8 @@ const bagl_element_t ui_idle_nanos[] = {
|
|||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{{BAGL_LABELINE, 0x01, 39, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
|
||||
BAGL_FONT_OPEN_SANS_REGULAR_11px, 0},
|
||||
{{BAGL_LABELINE, 0x01, 34, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
|
||||
BAGL_FONT_OPEN_SANS_EXTRABOLD_11px, 0},
|
||||
"view accounts",
|
||||
0,
|
||||
0,
|
||||
|
@ -986,10 +988,38 @@ unsigned char io_event(unsigned char channel) {
|
|||
|
||||
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
|
||||
if (UX_DISPLAYED()) {
|
||||
// TODO perform actions after all screen elements have been
|
||||
// displayed
|
||||
UX_DISPLAYED_:
|
||||
#ifdef COIN_LITECOIN
|
||||
// extra elements per screen, only for idle screen
|
||||
if (ux.elements == ui_idle_nanos && ui_idle_nanos_state == 0) {
|
||||
// could be used to perform extra print after an array has been
|
||||
// displayed
|
||||
switch (ux.elements_count - ux.elements_current) {
|
||||
case 0: {
|
||||
extern unsigned int const C_icon_litecoin_colors[];
|
||||
extern unsigned char const C_icon_litecoin_bitmap[];
|
||||
io_seproxyhal_display_bitmap(12, 9, 14, 14,
|
||||
C_icon_litecoin_colors, 1,
|
||||
C_icon_litecoin_bitmap);
|
||||
break;
|
||||
}
|
||||
|
||||
// case 1: // next extra element
|
||||
// case 2: // next next extra element ...
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ux.elements_current++;
|
||||
}
|
||||
#endif // COIN_LITECOIN
|
||||
;
|
||||
} else {
|
||||
UX_DISPLAY_PROCESSED_EVENT();
|
||||
// nothing displayed, then it's likely the end of the screen
|
||||
if (!io_seproxyhal_spi_is_status_sent()) {
|
||||
goto UX_DISPLAYED_;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1101,18 +1131,27 @@ uint8_t prepare_full_output(unsigned int outputPos) {
|
|||
4);
|
||||
|
||||
// Prepare amount
|
||||
// TODO : match current coin version
|
||||
|
||||
strcpy(fullAmount, "BTC ");
|
||||
btchip_context_D.tmp = (unsigned char *)fullAmount + 4;
|
||||
os_memmove(fullAmount, btchip_context_D.shortCoinId,
|
||||
btchip_context_D.shortCoinIdLength);
|
||||
fullAmount[btchip_context_D.shortCoinIdLength] = ' ';
|
||||
btchip_context_D.tmp =
|
||||
(unsigned char *)(fullAmount +
|
||||
btchip_context_D.shortCoinIdLength + 1);
|
||||
textSize = btchip_convert_hex_amount_to_displayable(amount);
|
||||
fullAmount[textSize + 4] = '\0';
|
||||
fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] =
|
||||
'\0';
|
||||
|
||||
// prepare fee display
|
||||
strcpy(feesAmount, "BTC ");
|
||||
btchip_context_D.tmp = (unsigned char *)feesAmount + 4;
|
||||
os_memmove(feesAmount, btchip_context_D.shortCoinId,
|
||||
btchip_context_D.shortCoinIdLength);
|
||||
feesAmount[btchip_context_D.shortCoinIdLength] = ' ';
|
||||
btchip_context_D.tmp =
|
||||
(unsigned char *)(feesAmount +
|
||||
btchip_context_D.shortCoinIdLength + 1);
|
||||
textSize = btchip_convert_hex_amount_to_displayable(fees);
|
||||
feesAmount[textSize + 4] = '\0';
|
||||
feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] =
|
||||
'\0';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue