Skip to content

Commit

Permalink
Merge pull request #26 from cosmos/backward_compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
tdejoigny-ledger authored Aug 1, 2023
2 parents c866adc + 45eb5ce commit 0086830
Show file tree
Hide file tree
Showing 40 changed files with 160 additions and 147 deletions.
2 changes: 1 addition & 1 deletion app/Makefile.version
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ APPVERSION_M=2
# This is the `spec_version` field of `Runtime`
APPVERSION_N=34
# This is the patch version of this release
APPVERSION_P=11
APPVERSION_P=12
71 changes: 55 additions & 16 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,25 @@ __Z_INLINE void handle_getversion(__Z_UNUSED volatile uint32_t *flags, volatile
THROW(APDU_CODE_OK);
}

static void extractHDPath(uint32_t rx, uint32_t offset) {
__Z_INLINE uint8_t extractHRP(uint32_t rx, uint32_t offset) {
if (rx < offset + 1) {
THROW(APDU_CODE_DATA_INVALID);
}
MEMZERO(bech32_hrp, MAX_BECH32_HRP_LEN);

bech32_hrp_len = G_io_apdu_buffer[offset];

if (bech32_hrp_len == 0 || bech32_hrp_len > MAX_BECH32_HRP_LEN) {
THROW(APDU_CODE_DATA_INVALID);
}

memcpy(bech32_hrp, G_io_apdu_buffer + offset + 1, bech32_hrp_len);
bech32_hrp[bech32_hrp_len] = 0; // zero terminate

return bech32_hrp_len;
}

__Z_INLINE void extractHDPath(uint32_t rx, uint32_t offset) {
if ((rx - offset) < sizeof(uint32_t) * HDPATH_LEN_DEFAULT) {
THROW(APDU_CODE_WRONG_LENGTH);
}
Expand All @@ -75,12 +93,6 @@ static void extractHDPath(uint32_t rx, uint32_t offset) {
THROW(APDU_CODE_DATA_INVALID);
}

encoding = checkChainConfig(hdPath[1], bech32_hrp, bech32_hrp_len);
if (encoding == UNSUPPORTED) {
ZEMU_LOGF(50, "Chain config not supported for: %s\n", bech32_hrp)
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}

// Limit values unless the app is running in expert mode
if (!app_mode_expert()) {
for(int i=2; i < HDPATH_LEN_DEFAULT; i++) {
Expand All @@ -90,6 +102,24 @@ static void extractHDPath(uint32_t rx, uint32_t offset) {
}
}

static void extractHDPath_HRP(uint32_t rx, uint32_t offset) {
extractHDPath(rx, offset);
// Set BECH32_COSMOS as default for backward compatibility
encoding = BECH32_COSMOS;

// Check if HRP was sent
if ((rx - offset) > sizeof(uint32_t) * HDPATH_LEN_DEFAULT) {
extractHRP(rx, offset + sizeof(uint32_t) * HDPATH_LEN_DEFAULT);
encoding = checkChainConfig(hdPath[1], bech32_hrp, bech32_hrp_len);
if (encoding == UNSUPPORTED) {
ZEMU_LOGF(50, "Chain config not supported for: %s\n", bech32_hrp)
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}
} else if (hdPath[1] == HDPATH_ETH_1_DEFAULT) {
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}
}

static bool process_chunk(volatile uint32_t *tx, uint32_t rx) {
UNUSED(tx);

Expand All @@ -108,7 +138,8 @@ static bool process_chunk(volatile uint32_t *tx, uint32_t rx) {
case P1_INIT:
tx_initialize();
tx_reset();
extractHDPath(rx, OFFSET_DATA);
extractHDPath_HRP(rx, OFFSET_DATA);

return false;
case P1_ADD:
added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA);
Expand All @@ -131,6 +162,13 @@ __Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32
uint8_t len = extractHRP(rx, OFFSET_DATA);
extractHDPath(rx, OFFSET_DATA + 1 + len);

// Verify encoding
encoding = checkChainConfig(hdPath[1], bech32_hrp, bech32_hrp_len);
if (encoding == UNSUPPORTED) {
ZEMU_LOGF(50, "Chain config not supported for: %s\n", bech32_hrp)
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}

uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1];
zxerr_t zxerr = app_fill_address();
if (zxerr != zxerr_ok) {
Expand All @@ -154,19 +192,20 @@ __Z_INLINE void handleSignSecp256K1(volatile uint32_t *flags, volatile uint32_t
THROW(APDU_CODE_OK);
}

if ((hdPath[1] == HDPATH_ETH_1_DEFAULT) && !app_mode_expert()) {
*flags |= IO_ASYNCH_REPLY;
view_custom_error_show(PIC(msg_error1),PIC(msg_error2));
THROW(APDU_CODE_DATA_INVALID);
}


// Put address in output buffer, we will use it to confirm source address
zxerr_t zxerr = app_fill_address();
if (zxerr != zxerr_ok) {
*tx = 0;
THROW(APDU_CODE_DATA_INVALID);
}
parser_tx_obj.own_addr = (const char *) (G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1);

if ((encoding != BECH32_COSMOS) && !app_mode_expert()) {
*flags |= IO_ASYNCH_REPLY;
view_custom_error_show(PIC(msg_error1),PIC(msg_error2));
THROW(APDU_CODE_DATA_INVALID);
}
const char *error_msg = tx_parse();

if (error_msg != NULL) {
Expand All @@ -183,7 +222,7 @@ __Z_INLINE void handleSignSecp256K1(volatile uint32_t *flags, volatile uint32_t
}

void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
uint16_t sw = 0;
volatile uint16_t sw = 0;

BEGIN_TRY
{
Expand Down Expand Up @@ -235,7 +274,7 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
break;
}
G_io_apdu_buffer[*tx] = sw >> 8;
G_io_apdu_buffer[*tx + 1] = sw;
G_io_apdu_buffer[*tx + 1] = sw & 0xFF;
*tx += 2;
}
FINALLY
Expand Down
4 changes: 0 additions & 4 deletions app/src/common/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@

extern uint16_t action_addrResponseLen;

__Z_INLINE void app_set_hrp(char *p) {
crypto_set_hrp(p);
}

__Z_INLINE void app_sign() {
uint16_t replyLen = 0;

Expand Down
164 changes: 70 additions & 94 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <bech32.h>
#include "chain_config.h"

#define MAX_DER_SIGNATURE_LEN 73u

uint32_t hdPath[HDPATH_LEN_DEFAULT];

uint8_t bech32_hrp_len;
Expand All @@ -31,41 +33,41 @@ address_encoding_e encoding;

#include "cx.h"

zxerr_t crypto_extractUncompressedPublicKey(const uint32_t path[HDPATH_LEN_DEFAULT], uint8_t *pubKey, uint16_t pubKeyLen) {
static zxerr_t crypto_extractUncompressedPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) {
if (pubKey == NULL || pubKeyLen < PK_LEN_SECP256K1_UNCOMPRESSED) {
return zxerr_invalid_crypto_settings;
}

cx_ecfp_public_key_t cx_publicKey = {0};
cx_ecfp_private_key_t cx_privateKey = {0};
uint8_t privateKeyData[32] = {0};
uint8_t privateKeyData[64] = {0};

zxerr_t error = zxerr_unknown;
// Generate keys
CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL,
CX_CURVE_256K1,
hdPath,
HDPATH_LEN_DEFAULT,
privateKeyData,
NULL,
NULL,
0))

CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &cx_privateKey))
CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey))
CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, &cx_privateKey, 1))
memcpy(pubKey, cx_publicKey.W, PK_LEN_SECP256K1_UNCOMPRESSED);
error = zxerr_ok;

if (pubKeyLen < PK_LEN_SECP256K1_UNCOMPRESSED) {
return zxerr_invalid_crypto_settings;
}
catch_cx_error:
MEMZERO(&cx_privateKey, sizeof(cx_privateKey));
MEMZERO(privateKeyData, sizeof(privateKeyData));

volatile zxerr_t err = zxerr_unknown;
BEGIN_TRY
{
TRY {
os_perso_derive_node_bip32(CX_CURVE_256K1,
path,
HDPATH_LEN_DEFAULT,
privateKeyData, NULL);

cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &cx_privateKey);
cx_ecfp_init_public_key(CX_CURVE_256K1, NULL, 0, &cx_publicKey);
cx_ecfp_generate_pair(CX_CURVE_256K1, &cx_publicKey, &cx_privateKey, 1);
err = zxerr_ok;
}
CATCH_OTHER(e) {
err = zxerr_ledger_api_error;
}
FINALLY {
MEMZERO(&cx_privateKey, sizeof(cx_privateKey));
MEMZERO(privateKeyData, 32);
}
if (error != zxerr_ok) {
MEMZERO(pubKey, pubKeyLen);
}
END_TRY;

memcpy(pubKey, cx_publicKey.W, PK_LEN_SECP256K1_UNCOMPRESSED);
return err;
return error;
}

__Z_INLINE zxerr_t compressPubkey(const uint8_t *pubkey, uint16_t pubkeyLen, uint8_t *output, uint16_t outputLen) {
Expand Down Expand Up @@ -116,9 +118,13 @@ static zxerr_t crypto_hashBuffer(const uint8_t *input, const uint16_t inputLen,
return zxerr_ok;
}

zxerr_t crypto_sign(uint8_t *signature,
uint16_t signatureMaxlen,
zxerr_t crypto_sign(uint8_t *output,
uint16_t outputLen,
uint16_t *sigSize) {
if (output == NULL || sigSize == NULL || outputLen < MAX_DER_SIGNATURE_LEN) {
return zxerr_invalid_crypto_settings;
}

uint8_t messageDigest[CX_SHA256_SIZE] = {0};

// Hash it
Expand All @@ -129,77 +135,47 @@ zxerr_t crypto_sign(uint8_t *signature,
CHECK_APP_CANARY()

cx_ecfp_private_key_t cx_privateKey;
uint8_t privateKeyData[32];
unsigned int info = 0;
volatile int signatureLength = 0;

volatile zxerr_t err = zxerr_unknown;
BEGIN_TRY
{
TRY
{
// Generate keys
os_perso_derive_node_bip32(CX_CURVE_SECP256K1,
hdPath,
HDPATH_LEN_DEFAULT,
privateKeyData, NULL);

cx_ecfp_init_private_key(CX_CURVE_SECP256K1, privateKeyData, 32, &cx_privateKey);

// Sign
signatureLength = cx_ecdsa_sign(&cx_privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
messageDigest,
CX_SHA256_SIZE,
signature,
signatureMaxlen,
&info);
err = zxerr_ok;
}
CATCH_OTHER(e) {
err = zxerr_ledger_api_error;
}
FINALLY {
MEMZERO(&cx_privateKey, sizeof(cx_privateKey));
MEMZERO(privateKeyData, 32);
}
}
END_TRY;

uint8_t privateKeyData[64] = {0};
size_t signatureLength = MAX_DER_SIGNATURE_LEN;
uint32_t tmpInfo = 0;
*sigSize = 0;

zxerr_t error = zxerr_unknown;

CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL,
CX_CURVE_256K1,
hdPath,
HDPATH_LEN_DEFAULT,
privateKeyData,
NULL,
NULL,
0))
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &cx_privateKey))
CATCH_CXERROR(cx_ecdsa_sign_no_throw(&cx_privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
messageDigest,
CX_SHA256_SIZE,
output,
&signatureLength, &tmpInfo))
*sigSize = signatureLength;
return err;
}
error = zxerr_ok;

uint8_t extractHRP(uint32_t rx, uint32_t offset) {
if (rx < offset + 1) {
THROW(APDU_CODE_DATA_INVALID);
}
MEMZERO(bech32_hrp, MAX_BECH32_HRP_LEN);

bech32_hrp_len = G_io_apdu_buffer[offset];
catch_cx_error:
MEMZERO(&cx_privateKey, sizeof(cx_privateKey));
MEMZERO(privateKeyData, sizeof(privateKeyData));

if (bech32_hrp_len == 0 || bech32_hrp_len > MAX_BECH32_HRP_LEN) {
THROW(APDU_CODE_DATA_INVALID);
if (error != zxerr_ok) {
MEMZERO(output, outputLen);
}

memcpy(bech32_hrp, G_io_apdu_buffer + offset + 1, bech32_hrp_len);
bech32_hrp[bech32_hrp_len] = 0; // zero terminate

return bech32_hrp_len;
return error;
}

void ripemd160_32(uint8_t *out, uint8_t *in) {
cx_ripemd160_t rip160;
cx_ripemd160_init(&rip160);
cx_hash(&rip160.header, CX_LAST, in, CX_SHA256_SIZE, out, CX_RIPEMD160_SIZE);
}

void crypto_set_hrp(char *p) {
bech32_hrp_len = strlen(p);
if (bech32_hrp_len < MAX_BECH32_HRP_LEN) {
snprintf(bech32_hrp, sizeof(bech32_hrp), "%s", p);
}
cx_hash_no_throw(&rip160.header, CX_LAST, in, CX_SHA256_SIZE, out, CX_RIPEMD160_SIZE);
}

zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrResponseLen) {
Expand All @@ -209,7 +185,7 @@ zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrR

// extract pubkey
uint8_t uncompressedPubkey [PK_LEN_SECP256K1_UNCOMPRESSED] = {0};
CHECK_ZXERR(crypto_extractUncompressedPublicKey(hdPath, uncompressedPubkey, sizeof(uncompressedPubkey)))
CHECK_ZXERR(crypto_extractUncompressedPublicKey(uncompressedPubkey, sizeof(uncompressedPubkey)))
CHECK_ZXERR(compressPubkey(uncompressedPubkey, sizeof(uncompressedPubkey), buffer, buffer_len))
char *addr = (char *) (buffer + PK_LEN_SECP256K1);

Expand All @@ -230,7 +206,7 @@ zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrR
if (cx_keccak_init_no_throw(&ctx, 256) != CX_OK) {
return zxerr_unknown;
}
cx_hash((cx_hash_t *)&ctx, CX_LAST, uncompressedPubkey+1, sizeof(uncompressedPubkey)-1, hashed1_pk, sizeof(hashed1_pk));
cx_hash_no_throw((cx_hash_t *)&ctx, CX_LAST, uncompressedPubkey+1, sizeof(uncompressedPubkey)-1, hashed1_pk, sizeof(hashed1_pk));
CHECK_ZXERR(bech32EncodeFromBytes(addr, buffer_len - PK_LEN_SECP256K1, bech32_hrp, hashed1_pk + 12, sizeof(hashed1_pk) - 12, 1, BECH32_ENCODING_BECH32))
break;
}
Expand Down
2 changes: 0 additions & 2 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ extern char bech32_hrp[MAX_BECH32_HRP_LEN + 1];
extern uint8_t bech32_hrp_len;
extern address_encoding_e encoding;

uint8_t extractHRP(uint32_t rx, uint32_t offset);

void crypto_set_hrp(char *p);

zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen);
Expand Down
2 changes: 1 addition & 1 deletion deps/ledger-zxlib
Loading

0 comments on commit 0086830

Please sign in to comment.