Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/ldg 428 support new transaction type cip64 #3

Merged
36 commits merged into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4a24915
test: write test for get address with ethereum derivation path
keiff3r Mar 12, 2024
e657cdf
feat: Add Ethereum paths to Makefile
keiff3r Mar 12, 2024
43f850c
chore: generate golden path snapshot for the new test
keiff3r Mar 12, 2024
3ad5c5b
test: write tests to validate using ethereum derivation path
keiff3r Mar 12, 2024
2afc50f
chore: generate screens to validate tests (for ethereum derivation path)
keiff3r Mar 12, 2024
7755d03
fix: Update ETH_PACKED_DERIVATION_PATH in celo_utils.py
keiff3r Mar 12, 2024
2ea6740
chore: Update test snapshots for Ethereum path derivation
keiff3r Mar 12, 2024
8fb5be2
refactor: change eth support implementation
keiff3r Mar 14, 2024
f4cd02f
fix: add eth derivation path to match ci
keiff3r Mar 14, 2024
3fc8b41
refactor: change implementation of eth support
keiff3r Mar 14, 2024
347004e
feat: enable optimisation, remove support for eth path
keiff3r Mar 14, 2024
682c7ef
feat: add Ethereum path in Makefile
keiff3r Mar 14, 2024
9d4a256
chore: generate new test snapshots for nanosp, nano X and stax
keiff3r Mar 14, 2024
857a4e7
fix(celo.c): add multiple breaks to remove a warning
keiff3r Mar 14, 2024
8d2786e
fix: Update cx_keccak_init calls to cx_keccak_init_no_throw
keiff3r Mar 14, 2024
2f2f601
fix: Update ticker and feeTicker to const char pointers
keiff3r Mar 14, 2024
d69cb3b
fix: change cx_hash to cx_hash_no_throw
keiff3r Mar 14, 2024
cd2a5c8
fix: change os_perso_derive_node_bip32 calls to os_derive_bip32_no_throw
keiff3r Mar 14, 2024
2c3e39a
fix: remove all 'warn_unused_result' warnings
keiff3r Mar 14, 2024
c6e7b83
fix: change all deprecated functions calls with recommanded functions
keiff3r Mar 15, 2024
2e805ac
feat: create structure to add support for EIP159 & CIP64 without brea…
keiff3r Mar 19, 2024
a6ef27e
test: implement test for eip 1559 and generate golden snapshots
keiff3r Mar 19, 2024
3ea3b16
feat: prevent signing with other chain_ids but Celo's
keiff3r Mar 20, 2024
1eb83d2
refactor: rename a test and generate screenshots accordingly
keiff3r Mar 20, 2024
ed2062f
fix: add case where chainID is null (to pass ci[Clang Static Analyzer]
keiff3r Mar 20, 2024
e80516b
fix: add MIN macro to ethUstream.h and change include order in ethUst…
keiff3r Mar 21, 2024
3491b7f
fix: add return statement to processAccessList and processAndDiscard …
keiff3r Mar 21, 2024
410c076
fix(unit_test): Update txType to CELO_LEGACY in unit test
keiff3r Mar 21, 2024
1352a74
chore: Update app_celo.gif files
keiff3r Mar 21, 2024
0666526
test: rename file and add test structure for cip64
keiff3r Mar 22, 2024
27456b7
feat: implement CIP64 transaction processing
keiff3r Mar 22, 2024
728fddc
test: write test for CIP64
keiff3r Mar 22, 2024
3d01b50
test: write test_add_cUSD_as_fee_currency and update test_sign_transa…
keiff3r Mar 28, 2024
08f458e
test: Add test_sign_transaction_cip64 snapshots for all devices
keiff3r Mar 28, 2024
e08dcb0
fix(tests): update test_sign_transaction_cip64
keiff3r Mar 28, 2024
702ffdb
chore: generate new golden path (due to screen change on stax)
keiff3r Mar 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

# Celo
APP_LOAD_PARAMS += --path "44'/52752'"
# Ethereum path
APP_LOAD_PARAMS += --path "44'/60'/0'/0/0" --path "44'/60'/0'" --path "44'/60'/0'/0"

APPNAME = "Celo"
APP_LOAD_FLAGS=--appFlags 0
ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX))
Expand Down Expand Up @@ -133,7 +136,7 @@ endif

CC := $(CLANGPATH)clang

#CFLAGS += -O0
# CFLAGS += -O0
CFLAGS += -O3 -Os

AS := $(GCCPATH)arm-none-eabi-gcc
Expand Down
23 changes: 23 additions & 0 deletions apdu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## ISO/IEC 7816-4 (2005) APDU errors (SW1/SW2)

| Error Code | Error Description |
|------------|---------------------------------------------|
| 0x6700 | wrong length (general error) |
| 0x6900 | command not allowed (general error) |
| 0x6981 | command incompatible with file structure |
| 0x6982 | security status not satisfied |
| 0x6A00 | wrong parameters p1/p2 (general error) |
| 0x6A80 | incorrect parameters in command data field |
| 0x6A81 | function not supported |
| 0x6A82 | file or application not found |
| 0x6A83 | record not found |
| 0x6A84 | not enough memory space in the file |
| 0x6A85 | command length inconsistent with TLV structure |
| 0x6A86 | incorrect parameters p1/p2 |
| 0x6A87 | command length inconsistent with p1/p2 |
| 0x6A88 | referenced data or reference data not found |
| 0x6A89 | file already exists |
| 0x6A8A | file name already exists |
|-------------------Personalized status word ---------------|
| 0x6A8B | error while hashing |
| 0x6A8C | error while deriving path |
1 change: 1 addition & 0 deletions doc/ethapp.asc
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ The following standard Status Words are returned for all APDUs - some specific S
[width="80%"]
|===============================================================================================
| *SW* | *Description*
| 6501 | TransactionType not supported
| 6700 | Incorrect length
| 6982 | Security status not satisfied (Canceled by user)
| 6A80 | Invalid data
Expand Down
Binary file modified nanos_app_celo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified nanox_app_celo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 13 additions & 5 deletions src/celo.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ static uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
}

customStatus_e customProcessor(txContext_t *context) {
if ((context->currentField == TX_RLP_DATA) &&
if (((context->txType == CELO_LEGACY && context->currentField == CELO_LEGACY_RLP_DATA) ||
(context->txType == CIP64 && context->currentField == CIP64_RLP_DATA) ||
(context->txType == EIP1559 && context->currentField == EIP1559_RLP_DATA)) &&
(context->currentFieldLength != 0)) {
dataPresent = true;
// If handling a new contract rather than a function call, abort immediately
Expand Down Expand Up @@ -232,15 +234,16 @@ customStatus_e customProcessor(txContext_t *context) {
copyTxData(context,
dataContext.withdrawContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_RELOCK:
copyTxData(context,
dataContext.relockContext.data + context->currentFieldPos,
copySize);
break;
case PROVISION_CREATE_ACCOUNT:
copyTxData(context,
dataContext.createAccountContext.data + context->currentFieldPos,
copySize);

break;
default:
break;
Expand Down Expand Up @@ -331,8 +334,8 @@ void finalizeParsing(bool direct) {
uint32_t i;
uint8_t decimals = WEI_TO_ETHER;
uint8_t feeDecimals = WEI_TO_ETHER;
char *ticker = CHAINID_COINNAME " ";
char *feeTicker = CHAINID_COINNAME " ";
const char *ticker = CHAINID_COINNAME " ";
const char *feeTicker = CHAINID_COINNAME " ";
uint8_t tickerOffset = 0;

// Display correct currency if fee currency field sent
Expand All @@ -356,7 +359,12 @@ void finalizeParsing(bool direct) {
}

// Store the hash
cx_hash((cx_hash_t *)&sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
CX_THROW(cx_hash_no_throw((cx_hash_t *) &sha3,
CX_LAST,
tmpCtx.transactionContext.hash,
0,
tmpCtx.transactionContext.hash,
32));
// If there is a token to process, check if it is well known
if (provisionType == PROVISION_TOKEN) {
tokenDefinition_t *currentToken = getKnownToken(tmpContent.txContent.destination);
Expand Down
69 changes: 49 additions & 20 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ void handleGetWalletId(volatile unsigned int *tx) {
cx_ecfp_256_private_key_t priv;
cx_ecfp_256_public_key_t pub;
// seed => priv key
os_perso_derive_node_bip32(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL);
CX_THROW(os_derive_bip32_no_throw(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL));
// priv key => pubkey
cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv);
cx_ecfp_generate_pair(CX_CURVE_256K1, &pub, &priv, 1);
CX_THROW(cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv));
CX_THROW(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &pub, &priv, 1));
// pubkey -> sha512
cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t));
// ! cookie !
Expand All @@ -184,7 +184,7 @@ void handleGetWalletId(volatile unsigned int *tx) {

void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) {
UNUSED(dataLength);
uint8_t privateKeyData[32];
uint8_t privateKeyData[64];
bip32Path_t derivationPath;
cx_ecfp_private_key_t privateKey;

Expand All @@ -203,10 +203,16 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t da

tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE);
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1, derivationPath.path, derivationPath.len, privateKeyData, (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL));
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
CX_THROW(os_derive_bip32_no_throw(
CX_CURVE_256K1,
derivationPath.path,
derivationPath.len,
privateKeyData,
(tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL)));

CX_THROW(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &privateKey));
io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
CX_THROW(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1));
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat();
Expand Down Expand Up @@ -272,8 +278,8 @@ void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuf
// Skip chainId
offset += 4;
dataLength -= 4;
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey);
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) {
CX_THROW(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey));
if (!cx_ecdsa_verify_no_throw(&tokenKey, hash, 32, workBuffer + offset, dataLength)) {
PRINTF("Invalid token signature\n");
THROW(0x6A80);
}
Expand All @@ -299,11 +305,24 @@ void handleSign(uint8_t p1, uint8_t p2, const uint8_t *workBuffer, uint16_t data
appState = APP_STATE_SIGNING_TX;
dataPresent = false;
provisionType = PROVISION_NONE;
//0x8000003c is the Ethereum path
initTx(&txContext, &sha3, &tmpContent.txContent, customProcessor, NULL);
// Extract and validate the transaction type
uint8_t txType = *workBuffer;
if (txType == EIP1559 || txType == CIP64) {
// Initialize the SHA3 hashing with the transaction type
CX_THROW(cx_hash_no_throw((cx_hash_t *) &sha3, 0, workBuffer, 1, NULL, 0));
// Save the transaction type
txContext.txType = txType;
workBuffer++;
dataLength--;
}
else {
txContext.txType = CELO_LEGACY;
}


}
else
if (p1 != P1_MORE) {
else if (p1 != P1_MORE) {
THROW(0x6B00);
}
if (p2 != 0) {
Expand All @@ -313,7 +332,7 @@ void handleSign(uint8_t p1, uint8_t p2, const uint8_t *workBuffer, uint16_t data
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
if (txContext.currentField == TX_RLP_NONE) {
if (txContext.currentField == RLP_NONE) {
PRINTF("Parser not initialized\n");
THROW(0x6985);
}
Expand Down Expand Up @@ -398,16 +417,24 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
workBuffer += 4;
dataLength -= 4;
// Initialize message header + length
cx_keccak_init(&sha3, 256);
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0);
CX_THROW(cx_keccak_init_no_throw(&sha3, 256));
CX_THROW(cx_hash_no_throw((cx_hash_t *)&sha3,
0,
(uint8_t*)SIGN_MAGIC,
sizeof(SIGN_MAGIC) - 1,
NULL,
0));

for (i = 1; (((i * base) <= tmpCtx.messageSigningContext.remainingLength) &&
(((i * base) / base) == i));
i *= base);
for (; i; i /= base) {
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / i) % base);
}
tmp[pos] = '\0';
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)tmp, pos, NULL, 0);

CX_THROW(cx_hash_no_throw((cx_hash_t *) &sha3, 0, (uint8_t*)tmp, pos, NULL, 0));

cx_sha256_init(&tmpContent.sha2);
}
else if (p1 != P1_MORE) {
Expand All @@ -423,14 +450,14 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
THROW(0x6A80);
}
cx_hash((cx_hash_t *)&sha3, 0, workBuffer, dataLength, NULL, 0);
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
CX_THROW(cx_hash_no_throw((cx_hash_t *)&sha3, 0, workBuffer, dataLength, NULL, 0));
CX_THROW(cx_hash_no_throw((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0));
tmpCtx.messageSigningContext.remainingLength -= dataLength;
if (tmpCtx.messageSigningContext.remainingLength == 0) {
uint8_t hashMessage[32];

cx_hash((cx_hash_t *)&sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32);
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
CX_THROW(cx_hash_no_throw((cx_hash_t *)&sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32));
CX_THROW(cx_hash_no_throw((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32));

#ifdef HAVE_BAGL
#define HASH_LENGTH 4
Expand Down Expand Up @@ -648,6 +675,8 @@ unsigned char io_event(unsigned char channel) {
THROW(EXCEPTION_IO_RESET);
}
// no break is intentional
__attribute__((fallthrough)); // ignore fall-through warning

default:
UX_DEFAULT_EVENT();
break;
Expand Down
31 changes: 17 additions & 14 deletions src/ui_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,24 @@ unsigned int io_seproxyhal_touch_address_cancel(void) {
}

unsigned int io_seproxyhal_touch_tx_ok(void) {
uint8_t privateKeyData[32];
uint8_t privateKeyData[64];
uint8_t signature[100];
cx_ecfp_private_key_t privateKey;
uint32_t tx = 0;
uint32_t v = getV(&tmpContent.txContent);
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.derivationPath.path,
CX_THROW(os_derive_bip32_no_throw(CX_CURVE_256K1, tmpCtx.transactionContext.derivationPath.path,
tmpCtx.transactionContext.derivationPath.len,
privateKeyData, NULL);
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32,
&privateKey);
privateKeyData, NULL));
CX_THROW(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32,
&privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0;
size_t sig_len = sizeof(signature);
io_seproxyhal_io_heartbeat();
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
CX_THROW(cx_ecdsa_sign_no_throw(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
tmpCtx.transactionContext.hash,
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info);
sizeof(tmpCtx.transactionContext.hash), signature, &sig_len, &info));
explicit_bzero(&privateKey, sizeof(privateKey));
// Parity is present in the sequence tag in the legacy API
if (tmpContent.txContent.vLength == 0) {
Expand Down Expand Up @@ -148,22 +149,24 @@ unsigned int io_seproxyhal_touch_tx_cancel(void) {
}

unsigned int io_seproxyhal_touch_signMessage_ok(void) {
uint8_t privateKeyData[32];
uint8_t privateKeyData[64];
uint8_t signature[100];
cx_ecfp_private_key_t privateKey;
uint32_t tx = 0;
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(
CX_CURVE_256K1, tmpCtx.messageSigningContext.derivationPath.path,
tmpCtx.messageSigningContext.derivationPath.len, privateKeyData, NULL);
CX_THROW(os_derive_bip32_no_throw(
CX_CURVE_256K1, tmpCtx.messageSigningContext.derivationPath.path,
tmpCtx.messageSigningContext.derivationPath.len, privateKeyData, NULL));

io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
CX_THROW(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0;
size_t sig_len = sizeof(signature);
io_seproxyhal_io_heartbeat();
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
CX_THROW(cx_ecdsa_sign_no_throw(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
tmpCtx.messageSigningContext.hash,
sizeof(tmpCtx.messageSigningContext.hash), signature, sizeof(signature), &info);
sizeof(tmpCtx.messageSigningContext.hash), signature, &sig_len, &info));
explicit_bzero(&privateKey, sizeof(privateKey));
G_io_apdu_buffer[0] = 27;
if (info & CX_ECCINFO_PARITY_ODD) {
Expand Down
Loading
Loading