Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@ APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += MAX_INPUT_COUNT=15
DEFINES += MAX_MESSAGE_LEN=120
else ifeq ($(TARGET_NAME),TARGET_STAX)
DEFINES += MAX_INPUT_COUNT=128
DEFINES += MAX_MESSAGE_LEN=200
else
DEFINES += MAX_INPUT_COUNT=128
DEFINES += MAX_MESSAGE_LEN=200
endif

# Application source files
Expand Down Expand Up @@ -76,7 +79,7 @@ VARIANT_PARAM = COIN
VARIANT_VALUES = KAS

# Enabling DEBUG flag will enable PRINTF and disable optimizations
#DEBUG = 1
DEBUG = 1

########################################
# Application custom permissions #
Expand Down
31 changes: 31 additions & 0 deletions doc/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,36 @@ Transactions signed with ECDSA are currently not supported.

\* While `has_more` is non-zero, you can ask for the next signature by sending another APDU back

## SIGN_MESSAGE

### Command

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x07 | 0x00 | 0x00 | var | `address_type (1)` \|\| `address_index (4)` \|\|<br>`message_len (1 bytes)` \|\| `message (var bytes)` |

| CData Part | Description |
| --- | --- |
| `address_type` | Either `00` for Receive Address or `01` for Change Address |
| `address_index` | Any value from `00000000` to `11111111` |
| `message_len` | How long the message is. Must be a value from `1` to `128`, inclusive |
| `message` | The message to sign |

### Response

| Length <br/>(bytes) | SW | RData |
| --- | --- | --- |
| var | 0x9000 | See Response Breakdown |

#### Response Breakdown

| Data | Description |
| --- | --- |
| `len(sig)` | The length of the signature. Always 64 bytes with Schnorr |
| `sig` | The Schnorr signature |
| `len(message_hash)` | The length of the message hash. Always 32 bytes |
| `message_hash` | The hash that was signed. |

## Status Words

| SW | SW name | Description |
Expand All @@ -143,4 +173,5 @@ Transactions signed with ECDSA are currently not supported.
| 0xB00A | `SW_WRONG_BIP32_COIN_TYPE` | `Coin Type` must be `111111'` |
| 0xB00B | `SW_WRONG_BIP32_TYPE` | `Type` passed is not valid. Must be either `0` for `Receive` or `1` for `Change`|
| 0xB00C | `SW_WRONG_BIP32_PATH_LEN` | Path length must be `5` |
| 0xB00D | `SW_MESSAGE_TOO_LONG` | Message len greater than max |
| 0x9000 | `OK` | Success |
2 changes: 1 addition & 1 deletion fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_compile_definitions(MAX_INPUT_COUNT=15 USB_SEGMENT_SIZE=64)
add_compile_definitions(MAX_INPUT_COUNT=15 MAX_MESSAGE_LEN=200 USB_SEGMENT_SIZE=64)

include(extra/TxParser.cmake)

Expand Down
8 changes: 8 additions & 0 deletions src/apdu/dispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "../handler/get_app_name.h"
#include "../handler/get_public_key.h"
#include "../handler/sign_tx.h"
#include "../handler/sign_msg.h"

#ifdef HAVE_DEBUG_APDU
#include "../handler/debug.h"
Expand Down Expand Up @@ -92,6 +93,13 @@ int apdu_dispatcher(const command_t *cmd) {
buf.offset = 0;

return handler_sign_tx(&buf, cmd->p1, (bool) (cmd->p2 & P2_MORE));
case SIGN_MESSAGE:

buf.ptr = cmd->data;
buf.size = cmd->lc;
buf.offset = 0;

return handler_sign_msg(&buf);
#ifdef HAVE_DEBUG_APDU
case DEBUG_APDU:
return handler_debug(cmd->p1);
Expand Down
95 changes: 0 additions & 95 deletions src/common/bip32.c

This file was deleted.

7 changes: 2 additions & 5 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@
*/
#define MAX_APPNAME_LEN 64

/**
* Maximum transaction length (bytes).
*/
#define MAX_TRANSACTION_LEN 128

/**
* Maximum signature length (bytes).
* Schnorr signatures only have 64 bytes
Expand All @@ -70,4 +65,6 @@
*/
#define SIGNING_KEY "TransactionSigningHash"

#define MESSAGE_SIGNING_KEY "PersonalMessageSigningHash"

#define MAX_OUTPUT_COUNT 2
37 changes: 36 additions & 1 deletion src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "globals.h"

#include "sighash.h"
#include "personal_message.h"

bool crypto_validate_public_key(const uint32_t *bip32_path,
uint8_t bip32_path_len,
Expand All @@ -54,7 +55,7 @@ bool crypto_validate_public_key(const uint32_t *bip32_path,
return memcmp(raw_pubkey + 1, compressed_public_key, 32) == 0;
}

int crypto_sign_message(void) {
int crypto_sign_transaction(void) {
cx_ecfp_private_key_t private_key = {0};
cx_ecfp_public_key_t public_key = {0};
uint8_t chain_code[32] = {0};
Expand Down Expand Up @@ -117,3 +118,37 @@ int crypto_sign_message(void) {

return error;
}

int crypto_sign_personal_message(void) {
hash_personal_message(G_context.msg_info.message,
G_context.msg_info.message_len,
G_context.msg_info.message_hash);

cx_ecfp_private_key_t private_key = {0};
uint8_t chain_code[32] = {0};

int error = bip32_derive_init_privkey_256(CX_CURVE_256K1,
G_context.bip32_path,
G_context.bip32_path_len,
&private_key,
chain_code);

BEGIN_TRY {
TRY {
size_t sig_len = sizeof(G_context.tx_info.signature);
error = cx_ecschnorr_sign_no_throw(&private_key,
CX_ECSCHNORR_BIP0340 | CX_RND_TRNG,
CX_SHA256,
G_context.msg_info.message_hash,
sizeof(G_context.msg_info.message_hash),
G_context.msg_info.signature,
&sig_len);
}
FINALLY {
explicit_bzero(&private_key, sizeof(private_key));
}
}
END_TRY;

return error;
}
13 changes: 12 additions & 1 deletion src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* @return 0 on success, error number otherwise.
*
*/
int crypto_sign_message(void);
int crypto_sign_transaction(void);

/**
* Checks if the compressed public key matches the
Expand All @@ -56,3 +56,14 @@ int crypto_sign_message(void);
bool crypto_validate_public_key(const uint32_t *bip32_path,
uint8_t bip32_path_len,
uint8_t compressed_public_key[static 32]);

/**
* Sign personal message hash in global context.
*
* @see G_context.bip32_path,
* G_context.msg_info.signature.
*
* @return 0 on success, error number otherwise.
*
*/
int crypto_sign_personal_message(void);
90 changes: 90 additions & 0 deletions src/handler/sign_msg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*****************************************************************************
* MIT License
*
* Copyright (c) 2023 coderofstuff
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#include <stdint.h> // uint*_t
#include <string.h> // memset, explicit_bzero

#include "types.h"
#include "buffer.h"
#include "./globals.h"
#include "./sign_msg.h"
#include "../sw.h"
#include "../ui/display.h"
#include "../helper/send_response.h"

/**
* Handler for SIGN_MESSAGE command. If successfully parse BIP32 path
* and message, sign the message and send APDU response.
*
* @see G_context.bip32_path, G_context.msg_info
*
* @param[in,out] cdata
* Command data with BIP32 path and raw message.
*
* @return zero or positive integer if success, negative integer otherwise.
*
*/
int handler_sign_msg(buffer_t *cdata) {
explicit_bzero(&G_context, sizeof(G_context));
G_context.req_type = CONFIRM_MESSAGE;
G_context.state = STATE_NONE;

if (!buffer_read_u8(cdata, &G_context.msg_info.address_type)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

if (!buffer_read_u32(cdata, &G_context.msg_info.address_index, BE)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

uint8_t message_len = 0;
if (!buffer_read_u8(cdata, &message_len)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

if (message_len > MAX_MESSAGE_LEN) {
return io_send_sw(SW_MESSAGE_TOO_LONG);
}

G_context.msg_info.message_len = (size_t) message_len;

if (!buffer_can_read(cdata, G_context.msg_info.message_len)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

memcpy(G_context.msg_info.message, cdata->ptr + cdata->offset, G_context.msg_info.message_len);

if (!buffer_seek_cur(cdata, G_context.msg_info.message_len)) {
return io_send_sw(SW_WRONG_DATA_LENGTH);
}

G_context.bip32_path[0] = 0x8000002C;
G_context.bip32_path[1] = 0x8001b207;
G_context.bip32_path[2] = 0x80000000;
G_context.bip32_path[3] = (uint32_t)(G_context.msg_info.address_type);
G_context.bip32_path[4] = G_context.msg_info.address_index;

G_context.bip32_path_len = 5;

return ui_display_message();
}
Loading