Skip to content

Commit

Permalink
fix: check bip32 path
Browse files Browse the repository at this point in the history
  • Loading branch information
krigga committed Sep 21, 2023
1 parent d7bb332 commit b2c1472
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 7 deletions.
9 changes: 7 additions & 2 deletions doc/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ Use P2 to control what kind of address to present to user:
* set bit 0x01 to make address testnet only
* set bit 0x02 to use masterchain instead of basechain for the address

The bip32 path must be at least 3 elements long and must start with the prefix `m/44'/607'/`.

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x05 | 0x00 (no display) <br> 0x01 (display) | 0x00-0x03 | 1 + 4n | `len(bip32_path) (1)` \|\|<br> `bip32_path{1} (4)` \|\|<br>`...` \|\|<br>`bip32_path{n} (4)` |
Expand All @@ -61,7 +63,7 @@ Use P2 to control what kind of address to present to user:

### Command

Sent as series of packages. First one contains bip32 path:
Sent as series of packages. First one contains bip32 path, which must be at least 3 elements long and must start with the prefix `m/44'/607'/`:

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
Expand All @@ -87,6 +89,8 @@ Use P2 to control what kind of address to present to user:
* set bit 0x01 to make address testnet only
* set bit 0x02 to use masterchain instead of basechain for the address

The bip32 path must be at least 3 elements long and must start with the prefix `m/44'/607'/`.

Payload's length is implicitly calculated from buffer length.

Proofs are generated according to this [spec](https://github.com/ton-blockchain/ton-connect/blob/main/requests-responses.md#address-proof-signature-ton_proof).
Expand All @@ -107,7 +111,7 @@ Proofs are generated according to this [spec](https://github.com/ton-blockchain/

Signatures are generated according to this [spec](https://github.com/ton-blockchain/ton-connect/blob/main/requests-responses.md#sign-data-experimental).

Sent as series of packages. First one contains bip32 path:
Sent as series of packages. First one contains bip32 path, which must be at least 3 elements long and must start with the prefix `m/44'/607'/`:

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
Expand Down Expand Up @@ -144,4 +148,5 @@ Then an arbitrary number of chunks with serialized custom data (see [CUSTOM_DATA
| 0xB007 | `SW_BAD_STATE` | Security issue with bad state |
| 0xB008 | `SW_SIGNATURE_FAIL` | Signature of raw transaction failed |
| 0xB00B | `SW_REQUEST_TOO_LONG` | The request is too long |
| 0xB0BD | `SW_BAD_BIP32_PATH` | The bip32 derivation path is invalid |
| 0x9000 | `OK` | Success |
11 changes: 11 additions & 0 deletions src/common/bip32_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdbool.h>

#include "../globals.h"

#include "bip32_check.h"

bool check_global_bip32_path() {
if (G_context.bip32_path_len <= 2) return false;

return G_context.bip32_path[0] == 0x8000002c && G_context.bip32_path[1] == 0x8000025f;
}
11 changes: 11 additions & 0 deletions src/common/bip32_check.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <stdbool.h> // bool

/**
* Check the bip32 path stored in G_context.
*
* @return true if bip32 path is valid, false otherwise
*
*/
bool check_global_bip32_path();
5 changes: 5 additions & 0 deletions src/handler/get_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "../sw.h"
#include "../crypto.h"
#include "../common/buffer.h"
#include "../common/bip32_check.h"
#include "../ui/display.h"
#include "../helper/send_response.h"

Expand All @@ -42,6 +43,10 @@ int handler_get_public_key(uint8_t flags, buffer_t *cdata, bool display) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

if (!check_global_bip32_path()) {
return io_send_sw(SW_BAD_BIP32_PATH);
}

if (crypto_derive_public_key(G_context.bip32_path,
G_context.bip32_path_len,
G_context.pk_info.raw_public_key) < 0) {
Expand Down
10 changes: 8 additions & 2 deletions src/handler/sign_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@
#include "../crypto.h"
#include "../ui/display.h"
#include "../common/buffer.h"
#include "../common/bip32_check.h"
#include "../sign_data/sign_data_deserialize.h"

int handler_sign_data(buffer_t *cdata, bool first, bool more) {
if (first) { // first APDU, parse BIP32 path
explicit_bzero(&G_context, sizeof(G_context));
G_context.req_type = CONFIRM_SIGN_DATA;
G_context.state = STATE_NONE;

if (!buffer_read_u8(cdata, &G_context.bip32_path_len) ||
!buffer_read_bip32_path(cdata,
Expand All @@ -44,6 +43,13 @@ int handler_sign_data(buffer_t *cdata, bool first, bool more) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

if (!check_global_bip32_path()) {
return io_send_sw(SW_BAD_BIP32_PATH);
}

G_context.req_type = CONFIRM_SIGN_DATA;
G_context.state = STATE_NONE;

return io_send_sw(SW_OK);
}

Expand Down
10 changes: 8 additions & 2 deletions src/handler/sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@
#include "../crypto.h"
#include "../ui/display.h"
#include "../common/buffer.h"
#include "../common/bip32_check.h"
#include "../transaction/types.h"
#include "../transaction/deserialize.h"
#include "../transaction/hash.h"

int handler_sign_tx(buffer_t *cdata, bool first, bool more) {
if (first) { // first APDU, parse BIP32 path
explicit_bzero(&G_context, sizeof(G_context));
G_context.req_type = CONFIRM_TRANSACTION;
G_context.state = STATE_NONE;

if (!buffer_read_u8(cdata, &G_context.bip32_path_len) ||
!buffer_read_bip32_path(cdata,
Expand All @@ -46,6 +45,13 @@ int handler_sign_tx(buffer_t *cdata, bool first, bool more) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

if (!check_global_bip32_path()) {
return io_send_sw(SW_BAD_BIP32_PATH);
}

G_context.req_type = CONFIRM_TRANSACTION;
G_context.state = STATE_NONE;

return io_send_sw(SW_OK);
}

Expand Down
6 changes: 6 additions & 0 deletions src/proof/proof_deserialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "proof_deserialize.h"

#include "../common/buffer.h"
#include "../common/bip32_check.h"
#include "../types.h"
#include "../globals.h"
#include "../io.h"
Expand All @@ -31,6 +32,11 @@ bool deserialize_proof(buffer_t *cdata, uint8_t flags) {
return false;
}

if (!check_global_bip32_path()) {
io_send_sw(SW_BAD_BIP32_PATH);
return false;
}

if (crypto_derive_public_key(G_context.bip32_path,
G_context.bip32_path_len,
G_context.proof_info.raw_public_key) < 0) {
Expand Down
4 changes: 4 additions & 0 deletions src/sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,7 @@
* Status word for a request that is too long.
*/
#define SW_REQUEST_TOO_LONG 0xB00B
/**
* Status word for bad bip32 path.
*/
#define SW_BAD_BIP32_PATH 0xB0BD
1 change: 1 addition & 0 deletions tests/application_client/ton_command_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Errors(IntEnum):
SW_BAD_STATE = 0xB007
SW_SIGNATURE_FAIL = 0xB008
SW_REQUEST_TOO_LONG = 0xB00B
SW_BAD_BIP32_PATH = 0XB0BD

class AddressDisplayFlags(IntFlag):
NONE = 0
Expand Down
14 changes: 13 additions & 1 deletion tests/test_pubkey_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,16 @@ def test_get_public_key_confirm_refused(firmware, backend, navigator, test_name)
instructions)
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0
assert len(e.value.data) == 0

def test_get_public_key_bad_path(firmware, backend, navigator, test_name):
client = BoilerplateCommandSender(backend)
paths = ["m/44'/608'/0'/0'/0'/0'", "m/44'/607'"]

for path in paths:
with pytest.raises(ExceptionRAPDU) as e:
with client.get_public_key_with_confirmation(path, AddressDisplayFlags.NONE):
pass
# Assert that we have received a refusal
assert e.value.status == Errors.SW_BAD_BIP32_PATH
assert len(e.value.data) == 0

0 comments on commit b2c1472

Please sign in to comment.