Skip to content

Commit

Permalink
Message signing
Browse files Browse the repository at this point in the history
  • Loading branch information
relatko committed Aug 16, 2022
1 parent 1db54d0 commit be078c1
Show file tree
Hide file tree
Showing 60 changed files with 356 additions and 49 deletions.
12 changes: 12 additions & 0 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "zxformat.h"
#include "hdpath.h"
#include "parser_impl.h"
#include "message.h"

__Z_INLINE void handleGetPubkey(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
hasPubkey = false;
Expand Down Expand Up @@ -86,6 +87,17 @@ __Z_INLINE void handleSign(volatile uint32_t *flags, volatile uint32_t *tx, uint
THROW(APDU_CODE_OK);
}

if (callType == PROCESS_CHUNK_FINISHED_MESSAGE) {
zxerr_t err = message_parse();
if (err != zxerr_ok) {
THROW(APDU_CODE_DATA_INVALID);
}
CHECK_APP_CANARY()
view_review_init(message_getItem, message_getNumItems, app_sign_message);
view_review_show();
*flags |= IO_ASYNCH_REPLY;
}

const char *error_msg = tx_parse(callType);

if (error_msg != NULL) {
Expand Down
2 changes: 2 additions & 0 deletions app/src/coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ typedef struct {

#define MAIN_SLOT 0

#define DOMAIN_TAG_LENGTH 32

#ifdef __cplusplus
}
#endif
16 changes: 16 additions & 0 deletions app/src/common/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,19 @@
#include "actions.h"

uint16_t action_addr_len;

// UTF-8 encoding of "FLOW-V0.0-transaction" padded with zeros to 32 bytes
const uint8_t TX_DOMAIN_TAG_TRANSACTION[DOMAIN_TAG_LENGTH] = {\
0x46, 0x4C, 0x4F, 0x57, 0x2D, 0x56, 0x30, 0x2E,
0x30, 0x2D, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6F, 0x6E, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};

const uint8_t TX_DOMAIN_TAG_MESSAGE[DOMAIN_TAG_LENGTH] = {\
0x46, 0x4C, 0x4F, 0x57, 0x2D, 0x56, 0x30, 0x2E,
0x30, 0x2D, 0x75, 0x73, 0x65, 0x72, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};

25 changes: 22 additions & 3 deletions app/src/common/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,31 @@

#define GET_PUB_KEY_RESPONSE_LENGTH (3 * SECP256_PK_LEN)

extern const uint8_t TX_DOMAIN_TAG_TRANSACTION[DOMAIN_TAG_LENGTH];
extern const uint8_t TX_DOMAIN_TAG_MESSAGE[DOMAIN_TAG_LENGTH];

__Z_INLINE void app_sign() {
const uint8_t *message = get_signable();
const uint16_t messageLength = get_signable_length();
const uint8_t *message = tx_get_buffer();
const uint16_t messageLength = tx_get_buffer_length();

uint16_t replyLen = 0;
zxerr_t err = crypto_sign(hdPath, cryptoOptions, message, messageLength, TX_DOMAIN_TAG_TRANSACTION, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, &replyLen);

if (err != zxerr_ok || replyLen == 0) {
set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
} else {
set_code(G_io_apdu_buffer, replyLen, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, replyLen + 2);
}
}

__Z_INLINE void app_sign_message() {
const uint8_t *message = tx_get_buffer();
const uint16_t messageLength = tx_get_buffer_length();

uint16_t replyLen = 0;
zxerr_t err = crypto_sign(hdPath, cryptoOptions, message, messageLength, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, &replyLen);
zxerr_t err = crypto_sign(hdPath, cryptoOptions, message, messageLength, TX_DOMAIN_TAG_MESSAGE, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, &replyLen);

if (err != zxerr_ok || replyLen == 0) {
set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR);
Expand Down
16 changes: 11 additions & 5 deletions app/src/common/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,33 +133,39 @@ process_chunk_response_t process_chunk(__Z_UNUSED volatile uint32_t *tx, uint32_
extractHDPathAndCryptoOptions(rx, OFFSET_DATA);
initStoredTxMetadata();
return PROCESS_CHUNK_NOT_FINISHED;
case 1:
case 0x01:
added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA);
if (added != rx - OFFSET_DATA) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
return PROCESS_CHUNK_NOT_FINISHED;
case 2:
case 0x02:
added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA);
if (added != rx - OFFSET_DATA) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
return PROCESS_CHUNK_FINISHED_NO_METADATA;
case 3:
case 0x03:
if (storeTxMetadata(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA) != PARSER_OK) {
THROW(APDU_CODE_DATA_INVALID);
}
return PROCESS_CHUNK_NOT_FINISHED;
case 4:
case 0x04:
if (validateStoredTxMetadataMerkleTreeLevel(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA) != PARSER_OK) {
THROW(APDU_CODE_DATA_INVALID);
}
return PROCESS_CHUNK_NOT_FINISHED;
case 5:
case 0x05:
if (validateStoredTxMetadataMerkleTreeLevel(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA) != PARSER_OK) {
THROW(APDU_CODE_DATA_INVALID);
}
return PROCESS_CHUNK_FINISHED_WITH_METADATA;
case 0x10:
added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA);
if (added != rx - OFFSET_DATA) {
THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL);
}
return PROCESS_CHUNK_FINISHED_MESSAGE;
}

THROW(APDU_CODE_INVALIDP1P2);
Expand Down
1 change: 1 addition & 0 deletions app/src/common/app_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ typedef enum {
PROCESS_CHUNK_NOT_FINISHED = 0,
PROCESS_CHUNK_FINISHED_WITH_METADATA,
PROCESS_CHUNK_FINISHED_NO_METADATA,
PROCESS_CHUNK_FINISHED_MESSAGE,
} process_chunk_response_t;

process_chunk_response_t process_chunk(volatile uint32_t *tx, uint32_t rx);
Expand Down
20 changes: 0 additions & 20 deletions app/src/common/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@ storage_t NV_CONST N_appdata_impl __attribute__ ((aligned(64)));

parser_context_t ctx_parsed_tx;

// UTF-8 encoding of "FLOW-V0.0-transaction" padded with zeros to 32 bytes
#define DOMAIN_TAG_LENGTH 32
const uint8_t TX_DOMAIN_TAG[DOMAIN_TAG_LENGTH] = {\
0x46, 0x4C, 0x4F, 0x57, 0x2D, 0x56, 0x30, 0x2E,
0x30, 0x2D, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6F, 0x6E, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};

#define TX_BUFFER_OFFSET DOMAIN_TAG_LENGTH

Expand All @@ -68,29 +60,17 @@ void tx_initialize() {

void tx_reset() {
buffering_reset();
buffering_append((uint8_t *)TX_DOMAIN_TAG, DOMAIN_TAG_LENGTH);
}

uint32_t tx_append(unsigned char *buffer, uint32_t length) {
return buffering_append(buffer, length);
}

uint32_t tx_get_buffer_length() {
if (buffering_get_buffer()->pos >= TX_BUFFER_OFFSET) {
return buffering_get_buffer()->pos - TX_BUFFER_OFFSET;
}
return 0;
}

uint32_t get_signable_length() {
return buffering_get_buffer()->pos;
}

uint8_t *tx_get_buffer() {
return buffering_get_buffer()->data + TX_BUFFER_OFFSET;
}

uint8_t *get_signable() {
return buffering_get_buffer()->data;
}

Expand Down
25 changes: 15 additions & 10 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)
#include "cx.h"


__Z_INLINE digest_type_e get_hash_type(const uint16_t options) {
const uint8_t hash_type = (uint8_t) (options & 0xFF);
switch(hash_type) {
Expand Down Expand Up @@ -118,28 +117,32 @@ void sha256(const uint8_t *message, uint16_t messageLen, uint8_t message_digest[
cx_hash_sha256(message, messageLen, message_digest, CX_SHA256_SIZE);
}

zxerr_t digest_message(const uint8_t *message, uint16_t messageLen, digest_type_e hash_kind, uint8_t *digest, uint16_t digestMax, uint16_t* digest_size) {
zxerr_t digest_message(const uint8_t *message, uint16_t messageLen, const uint8_t domainTag[DOMAIN_TAG_LENGTH],
digest_type_e hash_kind, uint8_t *digest, uint16_t digestMax, uint16_t* digest_size) {
switch(hash_kind) {
case HASH_SHA2_256: {
zemu_log_stack("sha2_256");
if (digestMax < CX_SHA256_SIZE) {
zemu_log_stack("digest_message: zxerr_buffer_too_small");
return zxerr_buffer_too_small;
}
sha256(message, messageLen, digest);
cx_sha256_t sha2;
cx_sha256_init(&sha2);
cx_hash((cx_hash_t*) &sha2, 0, domainTag, DOMAIN_TAG_LENGTH, NULL, 0);
cx_hash((cx_hash_t*) &sha2, CX_LAST, message, messageLen, digest, CX_SHA256_SIZE);
*digest_size = CX_SHA256_SIZE;
return zxerr_ok;
}
case HASH_SHA3_256: {
if (digestMax < 32) {
zemu_log_stack("sha3_256");
if (digestMax < CX_SHA256_SIZE) {
return zxerr_buffer_too_small;
}
zemu_log_stack("sha3_256");
cx_sha3_t sha3;
cx_sha3_init(&sha3, 256);
cx_hash((cx_hash_t*)&sha3, CX_LAST, message, messageLen, digest, 32);
zemu_log_stack("sha3_256 ready");
*digest_size = 32;
cx_hash((cx_hash_t*) &sha3, 0, domainTag, DOMAIN_TAG_LENGTH, NULL, 0);
cx_hash((cx_hash_t*) &sha3, CX_LAST, message, messageLen, digest, CX_SHA256_SIZE);
*digest_size = CX_SHA256_SIZE;
return zxerr_ok;
}
default: {
Expand All @@ -149,7 +152,9 @@ zxerr_t digest_message(const uint8_t *message, uint16_t messageLen, digest_type_
}
}

zxerr_t crypto_sign(const hd_path_t path, const uint16_t options, const uint8_t *message, uint16_t messageLen, uint8_t *buffer, uint16_t bufferSize, uint16_t *sigSize) {
zxerr_t crypto_sign(const hd_path_t path, const uint16_t options,
const uint8_t *message, uint16_t messageLen, const uint8_t domainTag[DOMAIN_TAG_LENGTH],
uint8_t *buffer, uint16_t bufferSize, uint16_t *sigSize) {
zemu_log_stack("crypto_sign");

cx_curve_t curve = get_cx_curve(options);
Expand All @@ -163,7 +168,7 @@ zxerr_t crypto_sign(const hd_path_t path, const uint16_t options, const uint8_t
uint8_t messageDigest[32];
uint16_t messageDigestSize = 0;

CHECK_ZXERR(digest_message(message, messageLen, cx_hash_kind, messageDigest, sizeof(messageDigest), &messageDigestSize));
CHECK_ZXERR(digest_message(message, messageLen, domainTag, cx_hash_kind, messageDigest, sizeof(messageDigest), &messageDigestSize));

if (messageDigestSize != 32) {
zemu_log_stack("crypto_sign: zxerr_out_of_bounds");
Expand Down
1 change: 1 addition & 0 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ zxerr_t crypto_sign(
const uint16_t options,
const uint8_t *message,
uint16_t messageLen,
const uint8_t domainTag[DOMAIN_TAG_LENGTH],
uint8_t *signature,
uint16_t signatureMaxlen,
uint16_t *sigSize
Expand Down
90 changes: 90 additions & 0 deletions app/src/message.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*******************************************************************************
* (c) 2022 Vacuumlabs
*
* 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 "message.h"
#include "zxformat.h"
#include "app_mode.h"
#include "hdpath.h"
#include "crypto.h"
#include "buffering.h"

#define MAX_MESSAGE_SHOW_LENGTH 34*5
#define MAX_MESSAGE_LENGTH 0x7FFF

struct {
uint8_t hash[CX_SHA256_SIZE];
uint16_t length;
uint8_t *message;
bool canBeDisplayed;

} messageData;

zxerr_t message_parse() {
messageData.message = buffering_get_buffer()->data;
messageData.length = buffering_get_buffer()->pos;

if (messageData.length > MAX_MESSAGE_LENGTH) {
return zxerr_out_of_bounds;
}

sha256(messageData.message, messageData.length, messageData.hash);
messageData.canBeDisplayed = false;

if (messageData.length <= MAX_MESSAGE_SHOW_LENGTH) {
messageData.canBeDisplayed = true;
for(size_t j=0; j<messageData.length; j++) {
if (messageData.message[j]<32 || messageData.message[j]>127) {
messageData.canBeDisplayed = false;
break;
}
}
}

return zxerr_ok;
}

zxerr_t message_getNumItems(uint8_t *num_items){
*num_items = app_mode_expert() ? 2: 1;
return zxerr_ok;
}

// retrieves a readable output for each field / page
zxerr_t message_getItem(int8_t displayIdx,
char *outKey, uint16_t outKeyLen,
char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount) {
switch(displayIdx) {
case 0:
if (messageData.canBeDisplayed) {
snprintf(outKey, outKeyLen, "Message");
pageStringExt(outVal, outValLen, (char *)messageData.message, messageData.length, pageIdx, pageCount);
}
else {
snprintf(outKey, outKeyLen, "Message hash");
pageHexString(outVal, outValLen, messageData.hash, sizeof(messageData.hash), pageIdx, pageCount);
}
return zxerr_ok;
case 1:
if (app_mode_expert()) {
snprintf(outKey, outKeyLen, "Your Path");
char buffer[100];
path_options_to_string(buffer, sizeof(buffer), hdPath.data, HDPATH_LEN_DEFAULT, cryptoOptions);
pageString(outVal, outValLen, buffer, pageIdx, pageCount);
return zxerr_ok;
}
return zxerr_no_data;
}
return zxerr_no_data;
}
29 changes: 29 additions & 0 deletions app/src/message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* (c) 2022 Vacuumlabs
*
* 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.
********************************************************************************/
#pragma once

#include "zxerror.h"

zxerr_t message_parse();

zxerr_t message_getNumItems(uint8_t *num_items);

zxerr_t message_getItem(int8_t displayIdx,
char *outKey, uint16_t outKeyLen,
char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);


1 change: 1 addition & 0 deletions deps/ledger-zxlib/dockerized_build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ speculos_port_5002_test_internal:
$(call run_nodejs_test,5002,40002,test-slot-transaction-interaction.js)
$(call run_nodejs_test,5002,40002,test-transaction-expert-mode.js)
$(call run_nodejs_test,5002,40002,test-transaction-arbitrary.js)
$(call run_nodejs_test,5002,40002,test-messages.js)
$(call run_nodejs_test,5002,40002,test-transactions.js)
@echo "# ALL TESTS COMPLETED!" | tee -a $(TESTS_SPECULOS_DIR)/speculos-port-5002.log

Expand Down
Loading

0 comments on commit be078c1

Please sign in to comment.