2014-04-29 12:26:51 +00:00
/*
2017-11-05 16:46:34 +00:00
* This file is part of the TREZOR project , https : //trezor.io/
2014-04-29 12:26:51 +00:00
*
* Copyright ( C ) 2014 Pavol Rusnak < stick @ satoshilabs . com >
*
* This library is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library . If not , see < http : //www.gnu.org/licenses/>.
*/
2017-10-03 11:11:53 +00:00
# include <libopencm3/stm32/flash.h>
2014-04-29 12:26:51 +00:00
# include "trezor.h"
# include "fsm.h"
# include "messages.h"
# include "bip32.h"
# include "storage.h"
# include "coins.h"
# include "debug.h"
# include "transaction.h"
# include "rng.h"
# include "storage.h"
# include "oled.h"
# include "protect.h"
# include "pinmatrix.h"
# include "layout2.h"
2017-01-02 20:22:59 +00:00
# include "address.h"
# include "base58.h"
2014-04-29 12:26:51 +00:00
# include "ecdsa.h"
# include "reset.h"
# include "recovery.h"
# include "memory.h"
# include "usb.h"
# include "util.h"
# include "signing.h"
2014-06-07 12:21:59 +00:00
# include "aes.h"
# include "hmac.h"
2014-11-15 01:01:21 +00:00
# include "crypto.h"
# include "base58.h"
2014-12-08 18:58:13 +00:00
# include "bip39.h"
2014-12-10 17:04:51 +00:00
# include "ripemd160.h"
2016-04-22 15:49:00 +00:00
# include "curves.h"
2015-06-03 19:21:16 +00:00
# include "secp256k1.h"
2016-05-24 21:22:30 +00:00
# include "ethereum.h"
2017-05-29 16:07:55 +00:00
# include "nem.h"
2017-05-30 16:41:02 +00:00
# include "nem2.h"
2017-10-03 11:11:53 +00:00
# include "rfc6979.h"
2017-06-18 20:22:33 +00:00
# include "gettext.h"
2014-04-29 12:26:51 +00:00
// message methods
2016-08-29 21:22:49 +00:00
static uint8_t msg_resp [ MSG_OUT_SIZE ] __attribute__ ( ( aligned ) ) ;
2014-04-29 12:26:51 +00:00
2016-11-22 19:57:45 +00:00
# define RESP_INIT(TYPE) \
TYPE * resp = ( TYPE * ) ( void * ) msg_resp ; \
2015-08-24 10:47:27 +00:00
_Static_assert ( sizeof ( msg_resp ) > = sizeof ( TYPE ) , # TYPE " is too large " ) ; \
memset ( resp , 0 , sizeof ( TYPE ) ) ;
2014-04-29 12:26:51 +00:00
2016-11-22 19:57:45 +00:00
# define CHECK_INITIALIZED \
if ( ! storage_isInitialized ( ) ) { \
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_NotInitialized , NULL ) ; \
2016-11-22 19:57:45 +00:00
return ; \
}
# define CHECK_NOT_INITIALIZED \
if ( storage_isInitialized ( ) ) { \
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , _ ( " Device is already initialized. Use Wipe first. " ) ) ; \
2016-11-22 19:57:45 +00:00
return ; \
}
2016-11-22 20:06:39 +00:00
# define CHECK_PIN \
if ( ! protectPin ( true ) ) { \
layoutHome ( ) ; \
return ; \
}
# define CHECK_PIN_UNCACHED \
if ( ! protectPin ( false ) ) { \
layoutHome ( ) ; \
return ; \
}
2016-11-22 20:39:33 +00:00
# define CHECK_PARAM(cond, errormsg) \
if ( ! ( cond ) ) { \
2017-06-18 19:10:12 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , ( errormsg ) ) ; \
2016-11-22 20:39:33 +00:00
layoutHome ( ) ; \
return ; \
}
2014-04-29 12:26:51 +00:00
void fsm_sendSuccess ( const char * text )
{
RESP_INIT ( Success ) ;
if ( text ) {
resp - > has_message = true ;
strlcpy ( resp - > message , text , sizeof ( resp - > message ) ) ;
}
msg_write ( MessageType_MessageType_Success , resp ) ;
}
void fsm_sendFailure ( FailureType code , const char * text )
{
2014-05-20 13:36:35 +00:00
if ( protectAbortedByInitialize ) {
fsm_msgInitialize ( ( Initialize * ) 0 ) ;
protectAbortedByInitialize = false ;
return ;
}
2014-04-29 12:26:51 +00:00
RESP_INIT ( Failure ) ;
resp - > has_code = true ;
resp - > code = code ;
2017-06-18 20:22:33 +00:00
if ( ! text ) {
switch ( code ) {
case FailureType_Failure_UnexpectedMessage :
text = _ ( " Unexpected message " ) ;
break ;
case FailureType_Failure_ButtonExpected :
text = _ ( " Button expected " ) ;
break ;
case FailureType_Failure_DataError :
text = _ ( " Data error " ) ;
break ;
case FailureType_Failure_ActionCancelled :
text = _ ( " Action cancelled by user " ) ;
break ;
case FailureType_Failure_PinExpected :
text = _ ( " PIN expected " ) ;
break ;
case FailureType_Failure_PinCancelled :
text = _ ( " PIN cancelled " ) ;
break ;
case FailureType_Failure_PinInvalid :
text = _ ( " PIN invalid " ) ;
break ;
case FailureType_Failure_InvalidSignature :
text = _ ( " Invalid signature " ) ;
break ;
case FailureType_Failure_ProcessError :
text = _ ( " Process error " ) ;
break ;
case FailureType_Failure_NotEnoughFunds :
text = _ ( " Not enough funds " ) ;
break ;
case FailureType_Failure_NotInitialized :
text = _ ( " Device not initialized " ) ;
break ;
case FailureType_Failure_FirmwareError :
text = _ ( " Firmware error " ) ;
break ;
}
}
2014-04-29 12:26:51 +00:00
if ( text ) {
resp - > has_message = true ;
strlcpy ( resp - > message , text , sizeof ( resp - > message ) ) ;
}
msg_write ( MessageType_MessageType_Failure , resp ) ;
}
2017-11-14 16:53:17 +00:00
static const CoinInfo * fsm_getCoin ( bool has_name , const char * name )
2015-01-26 11:51:56 +00:00
{
2017-10-30 21:13:09 +00:00
const CoinInfo * coin ;
2017-04-21 10:55:14 +00:00
if ( has_name ) {
coin = coinByName ( name ) ;
} else {
coin = coinByName ( " Bitcoin " ) ;
}
2015-01-26 11:51:56 +00:00
if ( ! coin ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Invalid coin name " ) ) ;
2015-01-26 11:51:56 +00:00
layoutHome ( ) ;
return 0 ;
}
return coin ;
}
2017-11-14 16:53:17 +00:00
static HDNode * fsm_getDerivedNode ( const char * curve , const uint32_t * address_n , size_t address_n_count )
2014-04-29 12:26:51 +00:00
{
2017-08-08 10:59:39 +00:00
static CONFIDENTIAL HDNode node ;
2016-05-19 23:49:20 +00:00
if ( ! storage_getRootNode ( & node , curve , true ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_NotInitialized , _ ( " Device not initialized or passphrase request cancelled or unsupported curve " ) ) ;
2015-01-26 11:51:56 +00:00
layoutHome ( ) ;
2014-04-29 12:26:51 +00:00
return 0 ;
}
2015-01-26 12:53:06 +00:00
if ( ! address_n | | address_n_count = = 0 ) {
return & node ;
}
2016-12-12 11:16:48 +00:00
if ( hdnode_private_ckd_cached ( & node , address_n , address_n_count , NULL ) = = 0 ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Failed to derive private key " ) ) ;
2015-01-26 19:24:07 +00:00
layoutHome ( ) ;
return 0 ;
2014-04-29 12:26:51 +00:00
}
2015-01-26 12:53:06 +00:00
return & node ;
2014-04-29 12:26:51 +00:00
}
void fsm_msgInitialize ( Initialize * msg )
{
( void ) msg ;
recovery_abort ( ) ;
signing_abort ( ) ;
2015-03-31 14:31:29 +00:00
session_clear ( false ) ; // do not clear PIN
2015-08-25 17:50:04 +00:00
layoutHome ( ) ;
2015-03-30 13:47:03 +00:00
fsm_msgGetFeatures ( 0 ) ;
}
void fsm_msgGetFeatures ( GetFeatures * msg )
{
( void ) msg ;
2014-04-29 12:26:51 +00:00
RESP_INIT ( Features ) ;
resp - > has_vendor = true ; strlcpy ( resp - > vendor , " bitcointrezor.com " , sizeof ( resp - > vendor ) ) ;
resp - > has_major_version = true ; resp - > major_version = VERSION_MAJOR ;
resp - > has_minor_version = true ; resp - > minor_version = VERSION_MINOR ;
resp - > has_patch_version = true ; resp - > patch_version = VERSION_PATCH ;
resp - > has_device_id = true ; strlcpy ( resp - > device_id , storage_uuid_str , sizeof ( resp - > device_id ) ) ;
resp - > has_pin_protection = true ; resp - > pin_protection = storage . has_pin ;
2014-05-25 22:58:17 +00:00
resp - > has_passphrase_protection = true ; resp - > passphrase_protection = storage . has_passphrase_protection & & storage . passphrase_protection ;
2014-04-29 12:26:51 +00:00
# ifdef SCM_REVISION
2014-06-06 00:45:15 +00:00
int len = sizeof ( SCM_REVISION ) - 1 ;
resp - > has_revision = true ; memcpy ( resp - > revision . bytes , SCM_REVISION , len ) ; resp - > revision . size = len ;
2014-04-29 12:26:51 +00:00
# endif
resp - > has_bootloader_hash = true ; resp - > bootloader_hash . size = memory_bootloader_hash ( resp - > bootloader_hash . bytes ) ;
if ( storage . has_language ) {
resp - > has_language = true ;
strlcpy ( resp - > language , storage . language , sizeof ( resp - > language ) ) ;
}
if ( storage . has_label ) {
resp - > has_label = true ;
strlcpy ( resp - > label , storage . label , sizeof ( resp - > label ) ) ;
}
2017-10-31 17:32:08 +00:00
_Static_assert ( pb_arraysize ( Features , coins ) > = COINS_COUNT , " Features.coins max_count not large enough " ) ;
2014-04-29 12:26:51 +00:00
resp - > coins_count = COINS_COUNT ;
2017-10-30 21:13:09 +00:00
for ( int i = 0 ; i < COINS_COUNT ; i + + ) {
2017-10-31 17:32:08 +00:00
if ( coins [ i ] . coin_name ) {
resp - > coins [ i ] . has_coin_name = true ;
strlcpy ( resp - > coins [ i ] . coin_name , coins [ i ] . coin_name , sizeof ( resp - > coins [ i ] . coin_name ) ) ;
}
if ( coins [ i ] . coin_shortcut ) {
resp - > coins [ i ] . has_coin_shortcut = true ;
2017-11-04 17:15:50 +00:00
strlcpy ( resp - > coins [ i ] . coin_shortcut , coins [ i ] . coin_shortcut + 1 , sizeof ( resp - > coins [ i ] . coin_shortcut ) ) ;
2017-10-31 17:32:08 +00:00
}
resp - > coins [ i ] . has_address_type = coins [ i ] . has_address_type ;
resp - > coins [ i ] . address_type = coins [ i ] . address_type ;
2017-10-30 21:13:09 +00:00
resp - > coins [ i ] . has_maxfee_kb = true ;
resp - > coins [ i ] . maxfee_kb = coins [ i ] . maxfee_kb ;
2017-10-31 17:32:08 +00:00
resp - > coins [ i ] . has_address_type_p2sh = coins [ i ] . has_address_type_p2sh ;
resp - > coins [ i ] . address_type_p2sh = coins [ i ] . address_type_p2sh ;
resp - > coins [ i ] . has_xpub_magic = coins [ i ] . xpub_magic ! = 0 ;
resp - > coins [ i ] . xpub_magic = coins [ i ] . xpub_magic ;
resp - > coins [ i ] . has_xprv_magic = coins [ i ] . xprv_magic ! = 0 ;
resp - > coins [ i ] . xprv_magic = coins [ i ] . xprv_magic ;
resp - > coins [ i ] . has_segwit = true ;
resp - > coins [ i ] . segwit = coins [ i ] . has_segwit ;
resp - > coins [ i ] . has_forkid = coins [ i ] . has_forkid ;
resp - > coins [ i ] . forkid = coins [ i ] . forkid ;
2017-10-31 20:55:15 +00:00
resp - > coins [ i ] . has_force_bip143 = true ;
resp - > coins [ i ] . force_bip143 = coins [ i ] . force_bip143 ;
2017-10-30 21:13:09 +00:00
}
2014-05-25 22:58:17 +00:00
resp - > has_initialized = true ; resp - > initialized = storage_isInitialized ( ) ;
resp - > has_imported = true ; resp - > imported = storage . has_imported & & storage . imported ;
2015-03-30 13:47:03 +00:00
resp - > has_pin_cached = true ; resp - > pin_cached = session_isPinCached ( ) ;
resp - > has_passphrase_cached = true ; resp - > passphrase_cached = session_isPassphraseCached ( ) ;
2017-06-26 17:51:43 +00:00
resp - > has_needs_backup = true ; resp - > needs_backup = storage_needsBackup ( ) ;
2017-07-17 16:36:09 +00:00
resp - > has_flags = true ; resp - > flags = storage_getFlags ( ) ;
2014-04-29 12:26:51 +00:00
msg_write ( MessageType_MessageType_Features , resp ) ;
}
void fsm_msgPing ( Ping * msg )
{
RESP_INIT ( Success ) ;
if ( msg - > has_button_protection & & msg - > button_protection ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " answer to ping? " ) , NULL , NULL , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
return ;
}
}
if ( msg - > has_pin_protection & & msg - > pin_protection ) {
2016-11-22 20:06:39 +00:00
CHECK_PIN
2014-04-29 12:26:51 +00:00
}
if ( msg - > has_passphrase_protection & & msg - > passphrase_protection ) {
if ( ! protectPassphrase ( ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
return ;
}
}
if ( msg - > has_message ) {
resp - > has_message = true ;
memcpy ( & ( resp - > message ) , & ( msg - > message ) , sizeof ( resp - > message ) ) ;
}
msg_write ( MessageType_MessageType_Success , resp ) ;
layoutHome ( ) ;
}
void fsm_msgChangePin ( ChangePin * msg )
{
bool removal = msg - > has_remove & & msg - > remove ;
if ( removal ) {
if ( storage_hasPin ( ) ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " remove current PIN? " ) , NULL , NULL , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
} else {
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " PIN removed " ) ) ;
2014-04-29 12:26:51 +00:00
return ;
}
} else {
if ( storage_hasPin ( ) ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " change current PIN? " ) , NULL , NULL , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
} else {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " set new PIN? " ) , NULL , NULL , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
}
}
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
return ;
}
2016-11-22 20:06:39 +00:00
CHECK_PIN_UNCACHED
2014-04-29 12:26:51 +00:00
if ( removal ) {
storage_setPin ( 0 ) ;
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " PIN removed " ) ) ;
2014-04-29 12:26:51 +00:00
} else {
if ( protectChangePin ( ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " PIN changed " ) ) ;
2014-04-29 12:26:51 +00:00
} else {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
}
}
layoutHome ( ) ;
}
void fsm_msgWipeDevice ( WipeDevice * msg )
{
( void ) msg ;
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " wipe the device? " ) , NULL , _ ( " All data will be lost. " ) , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_WipeDevice , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
return ;
}
2017-07-31 00:26:28 +00:00
storage_wipe ( ) ;
2014-04-29 12:26:51 +00:00
// the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed
// usbReconnect(); // force re-enumeration because of the serial number change
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " Device wiped " ) ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
}
void fsm_msgGetEntropy ( GetEntropy * msg )
{
2017-07-19 09:54:26 +00:00
# if !DEBUG_RNG
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " send entropy? " ) , NULL , NULL , NULL , NULL ) ;
2014-04-29 12:26:51 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
return ;
}
2017-07-19 09:54:26 +00:00
# endif
2014-04-29 12:26:51 +00:00
RESP_INIT ( Entropy ) ;
uint32_t len = msg - > size ;
if ( len > 1024 ) {
len = 1024 ;
}
resp - > entropy . size = len ;
random_buffer ( resp - > entropy . bytes , len ) ;
msg_write ( MessageType_MessageType_Entropy , resp ) ;
layoutHome ( ) ;
}
void fsm_msgGetPublicKey ( GetPublicKey * msg )
{
RESP_INIT ( PublicKey ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2015-11-19 10:03:16 +00:00
2016-11-22 20:06:39 +00:00
CHECK_PIN
2015-03-30 12:38:33 +00:00
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2017-04-21 10:51:13 +00:00
if ( ! coin ) return ;
2016-04-19 16:23:12 +00:00
const char * curve = SECP256K1_NAME ;
if ( msg - > has_ecdsa_curve_name ) {
curve = msg - > ecdsa_curve_name ;
}
2016-07-04 15:42:54 +00:00
uint32_t fingerprint ;
2016-06-26 14:27:29 +00:00
HDNode * node ;
if ( msg - > address_n_count = = 0 ) {
/* get master node */
2016-07-04 15:42:54 +00:00
fingerprint = 0 ;
2016-06-26 14:27:29 +00:00
node = fsm_getDerivedNode ( curve , msg - > address_n , 0 ) ;
} else {
/* get parent node */
node = fsm_getDerivedNode ( curve , msg - > address_n , msg - > address_n_count - 1 ) ;
if ( ! node ) return ;
2016-07-04 15:42:54 +00:00
fingerprint = hdnode_fingerprint ( node ) ;
2016-06-26 14:27:29 +00:00
/* get child */
hdnode_private_ckd ( node , msg - > address_n [ msg - > address_n_count - 1 ] ) ;
}
hdnode_fill_public_key ( node ) ;
2014-04-29 12:26:51 +00:00
2015-11-19 10:48:26 +00:00
if ( msg - > has_show_display & & msg - > show_display ) {
2016-04-21 05:29:20 +00:00
layoutPublicKey ( node - > public_key ) ;
2015-11-19 10:48:26 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_PublicKey , true ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2015-11-19 10:48:26 +00:00
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
resp - > node . depth = node - > depth ;
2016-07-04 15:42:54 +00:00
resp - > node . fingerprint = fingerprint ;
2014-04-29 12:26:51 +00:00
resp - > node . child_num = node - > child_num ;
resp - > node . chain_code . size = 32 ;
memcpy ( resp - > node . chain_code . bytes , node - > chain_code , 32 ) ;
resp - > node . has_private_key = false ;
resp - > node . has_public_key = true ;
resp - > node . public_key . size = 33 ;
2016-04-21 05:29:20 +00:00
memcpy ( resp - > node . public_key . bytes , node - > public_key , 33 ) ;
2016-06-26 14:27:29 +00:00
if ( node - > public_key [ 0 ] = = 1 ) {
/* ed25519 public key */
resp - > node . public_key . bytes [ 0 ] = 0 ;
}
2014-08-07 19:53:55 +00:00
resp - > has_xpub = true ;
2017-04-21 10:55:14 +00:00
hdnode_serialize_public ( node , fingerprint , coin - > xpub_magic , resp - > xpub , sizeof ( resp - > xpub ) ) ;
2014-04-29 12:26:51 +00:00
msg_write ( MessageType_MessageType_PublicKey , resp ) ;
layoutHome ( ) ;
}
void fsm_msgLoadDevice ( LoadDevice * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_NOT_INITIALIZED
2014-04-29 12:26:51 +00:00
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " I take the risk " ) , NULL , _ ( " Loading private seed " ) , _ ( " is not recommended. " ) , _ ( " Continue only if you " ) , _ ( " know what you are " ) , _ ( " doing! " ) , NULL ) ;
2014-05-25 16:32:12 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-05-25 16:32:12 +00:00
layoutHome ( ) ;
return ;
}
2014-12-08 18:58:13 +00:00
if ( msg - > has_mnemonic & & ! ( msg - > has_skip_checksum & & msg - > skip_checksum ) ) {
if ( ! mnemonic_check ( msg - > mnemonic ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Mnemonic with wrong checksum provided " ) ) ;
2014-12-08 18:58:13 +00:00
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
storage_loadDevice ( msg ) ;
storage_commit ( ) ;
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " Device loaded " ) ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
}
void fsm_msgResetDevice ( ResetDevice * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_NOT_INITIALIZED
2014-04-29 12:26:51 +00:00
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( ! msg - > has_strength | | msg - > strength = = 128 | | msg - > strength = = 192 | | msg - > strength = = 256 , _ ( " Invalid seed strength " ) ) ;
2014-04-29 12:26:51 +00:00
reset_init (
msg - > has_display_random & & msg - > display_random ,
msg - > has_strength ? msg - > strength : 128 ,
msg - > has_passphrase_protection & & msg - > passphrase_protection ,
msg - > has_pin_protection & & msg - > pin_protection ,
msg - > has_language ? msg - > language : 0 ,
2016-10-31 15:20:15 +00:00
msg - > has_label ? msg - > label : 0 ,
2017-06-26 17:17:40 +00:00
msg - > has_u2f_counter ? msg - > u2f_counter : 0 ,
msg - > has_skip_backup ? msg - > skip_backup : false
2014-04-29 12:26:51 +00:00
) ;
}
2017-06-26 17:17:40 +00:00
void fsm_msgBackupDevice ( BackupDevice * msg )
{
CHECK_INITIALIZED
2017-08-07 14:34:07 +00:00
CHECK_PIN_UNCACHED
2017-06-26 17:17:40 +00:00
( void ) msg ;
2017-06-28 09:25:47 +00:00
reset_backup ( true ) ;
2017-06-26 17:17:40 +00:00
}
2014-04-29 12:26:51 +00:00
void fsm_msgSignTx ( SignTx * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2015-11-19 10:03:16 +00:00
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > inputs_count > 0 , _ ( " Transaction must have at least one input " ) ) ;
CHECK_PARAM ( msg - > outputs_count > 0 , _ ( " Transaction must have at least one output " ) ) ;
2014-04-29 12:26:51 +00:00
2016-11-22 20:06:39 +00:00
CHECK_PIN
2014-04-29 12:26:51 +00:00
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2015-01-26 11:51:56 +00:00
if ( ! coin ) return ;
2016-04-19 16:23:12 +00:00
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , 0 , 0 ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2016-04-16 02:47:09 +00:00
signing_init ( msg - > inputs_count , msg - > outputs_count , coin , node , msg - > version , msg - > lock_time ) ;
2014-04-29 12:26:51 +00:00
}
2016-05-24 21:14:10 +00:00
void fsm_msgTxAck ( TxAck * msg )
2016-05-23 20:27:18 +00:00
{
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_tx , _ ( " No transaction provided " ) ) ;
2016-11-22 20:39:33 +00:00
signing_txack ( & ( msg - > tx ) ) ;
2016-05-23 20:27:18 +00:00
}
2014-04-29 12:26:51 +00:00
void fsm_msgCancel ( Cancel * msg )
{
( void ) msg ;
recovery_abort ( ) ;
signing_abort ( ) ;
2016-05-24 21:22:30 +00:00
ethereum_signing_abort ( ) ;
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
}
2016-05-24 21:14:10 +00:00
void fsm_msgEthereumSignTx ( EthereumSignTx * msg )
2014-04-29 12:26:51 +00:00
{
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2016-05-24 21:22:30 +00:00
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-05-24 21:22:30 +00:00
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
ethereum_signing_init ( msg , node ) ;
2016-05-24 21:14:10 +00:00
}
void fsm_msgEthereumTxAck ( EthereumTxAck * msg )
{
2016-05-24 21:22:30 +00:00
ethereum_signing_txack ( msg ) ;
2014-04-29 12:26:51 +00:00
}
2014-06-07 12:21:59 +00:00
void fsm_msgCipherKeyValue ( CipherKeyValue * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_key , _ ( " No key provided " ) ) ;
CHECK_PARAM ( msg - > has_value , _ ( " No value provided " ) ) ;
CHECK_PARAM ( msg - > value . size % 16 = = 0 , _ ( " Value length must be a multiple of 16 " ) ) ;
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-04-19 16:23:12 +00:00
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
2014-06-07 12:21:59 +00:00
if ( ! node ) return ;
bool encrypt = msg - > has_encrypt & & msg - > encrypt ;
bool ask_on_encrypt = msg - > has_ask_on_encrypt & & msg - > ask_on_encrypt ;
bool ask_on_decrypt = msg - > has_ask_on_decrypt & & msg - > ask_on_decrypt ;
if ( ( encrypt & & ask_on_encrypt ) | | ( ! encrypt & & ask_on_decrypt ) ) {
layoutCipherKeyValue ( encrypt , msg - > key ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-06-07 12:21:59 +00:00
layoutHome ( ) ;
return ;
}
}
uint8_t data [ 256 + 4 ] ;
strlcpy ( ( char * ) data , msg - > key , sizeof ( data ) ) ;
strlcat ( ( char * ) data , ask_on_encrypt ? " E1 " : " E0 " , sizeof ( data ) ) ;
strlcat ( ( char * ) data , ask_on_decrypt ? " D1 " : " D0 " , sizeof ( data ) ) ;
hmac_sha512 ( node - > private_key , 32 , data , strlen ( ( char * ) data ) , data ) ;
2014-11-15 01:01:21 +00:00
RESP_INIT ( CipheredKeyValue ) ;
2014-06-07 12:21:59 +00:00
if ( encrypt ) {
aes_encrypt_ctx ctx ;
aes_encrypt_key256 ( data , & ctx ) ;
2015-06-29 14:36:50 +00:00
aes_cbc_encrypt ( msg - > value . bytes , resp - > value . bytes , msg - > value . size , ( ( msg - > iv . size = = 16 ) ? ( msg - > iv . bytes ) : ( data + 32 ) ) , & ctx ) ;
2014-06-07 12:21:59 +00:00
} else {
aes_decrypt_ctx ctx ;
aes_decrypt_key256 ( data , & ctx ) ;
2015-06-29 14:36:50 +00:00
aes_cbc_decrypt ( msg - > value . bytes , resp - > value . bytes , msg - > value . size , ( ( msg - > iv . size = = 16 ) ? ( msg - > iv . bytes ) : ( data + 32 ) ) , & ctx ) ;
2014-06-07 12:21:59 +00:00
}
2014-11-15 01:01:21 +00:00
resp - > has_value = true ;
resp - > value . size = msg - > value . size ;
msg_write ( MessageType_MessageType_CipheredKeyValue , resp ) ;
2014-06-07 12:21:59 +00:00
layoutHome ( ) ;
}
2014-06-17 14:03:07 +00:00
void fsm_msgClearSession ( ClearSession * msg )
{
( void ) msg ;
2015-03-31 14:31:29 +00:00
session_clear ( true ) ; // clear PIN as well
2015-04-13 17:52:38 +00:00
layoutScreensaver ( ) ;
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " Session cleared " ) ) ;
2014-06-17 14:03:07 +00:00
}
2014-04-29 12:26:51 +00:00
void fsm_msgApplySettings ( ApplySettings * msg )
{
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_label | | msg - > has_language | | msg - > has_use_passphrase | | msg - > has_homescreen , _ ( " No setting provided " ) ) ;
2016-11-22 20:39:33 +00:00
CHECK_PIN
2014-04-29 12:26:51 +00:00
if ( msg - > has_label ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " change label to " ) , msg - > label , " ? " , NULL , NULL ) ;
2014-12-13 18:29:27 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-12-13 18:29:27 +00:00
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
if ( msg - > has_language ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " change language to " ) , msg - > language , " ? " , NULL , NULL ) ;
2014-12-13 18:29:27 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-12-13 18:29:27 +00:00
layoutHome ( ) ;
return ;
}
2014-04-29 12:26:51 +00:00
}
2014-12-13 18:29:27 +00:00
if ( msg - > has_use_passphrase ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , msg - > use_passphrase ? _ ( " enable passphrase " ) : _ ( " disable passphrase " ) , _ ( " encryption? " ) , NULL , NULL , NULL ) ;
2014-12-13 18:29:27 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-12-13 18:29:27 +00:00
layoutHome ( ) ;
return ;
}
}
2015-02-04 20:27:07 +00:00
if ( msg - > has_homescreen ) {
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you really want to " ) , _ ( " change the home " ) , _ ( " screen? " ) , NULL , NULL , NULL ) ;
2015-02-04 20:27:07 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2015-02-04 20:27:07 +00:00
layoutHome ( ) ;
return ;
}
}
2016-11-22 20:06:39 +00:00
2014-04-29 12:26:51 +00:00
if ( msg - > has_label ) {
storage_setLabel ( msg - > label ) ;
}
if ( msg - > has_language ) {
storage_setLanguage ( msg - > language ) ;
}
2014-12-13 18:29:27 +00:00
if ( msg - > has_use_passphrase ) {
storage_setPassphraseProtection ( msg - > use_passphrase ) ;
}
2015-02-04 20:27:07 +00:00
if ( msg - > has_homescreen ) {
storage_setHomescreen ( msg - > homescreen . bytes , msg - > homescreen . size ) ;
}
2014-04-29 12:26:51 +00:00
storage_commit ( ) ;
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " Settings applied " ) ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
}
2017-07-17 16:36:09 +00:00
void fsm_msgApplyFlags ( ApplyFlags * msg )
{
if ( msg - > has_flags ) {
storage_applyFlags ( msg - > flags ) ;
}
fsm_sendSuccess ( _ ( " Flags applied " ) ) ;
}
2014-04-29 12:26:51 +00:00
void fsm_msgGetAddress ( GetAddress * msg )
{
RESP_INIT ( Address ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2015-11-19 10:03:16 +00:00
2016-11-22 20:06:39 +00:00
CHECK_PIN
2015-03-30 12:38:33 +00:00
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2015-01-26 11:51:56 +00:00
if ( ! coin ) return ;
2016-06-26 14:27:29 +00:00
HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2016-06-26 14:27:29 +00:00
hdnode_fill_public_key ( node ) ;
2017-03-29 14:53:45 +00:00
2017-08-23 14:36:38 +00:00
char address [ MAX_ADDR_SIZE ] ;
2017-06-18 20:22:33 +00:00
layoutProgress ( _ ( " Computing address " ) , 0 ) ;
2017-08-23 14:36:38 +00:00
if ( ! compute_address ( coin , msg - > script_type , node , msg - > has_multisig , & msg - > multisig , address ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Can't encode address " ) ) ;
2017-07-03 16:23:51 +00:00
layoutHome ( ) ;
return ;
2014-12-10 17:04:51 +00:00
}
2014-04-29 12:26:51 +00:00
2014-08-08 17:09:54 +00:00
if ( msg - > has_show_display & & msg - > show_display ) {
2015-02-18 17:30:54 +00:00
char desc [ 16 ] ;
if ( msg - > has_multisig ) {
strlcpy ( desc , " Msig __ of __: " , sizeof ( desc ) ) ;
const uint32_t m = msg - > multisig . m ;
const uint32_t n = msg - > multisig . pubkeys_count ;
desc [ 5 ] = ( m < 10 ) ? ' ' : ( ' 0 ' + ( m / 10 ) ) ;
desc [ 6 ] = ' 0 ' + ( m % 10 ) ;
desc [ 11 ] = ( n < 10 ) ? ' ' : ( ' 0 ' + ( n / 10 ) ) ;
desc [ 12 ] = ' 0 ' + ( n % 10 ) ;
} else {
2017-06-18 20:22:33 +00:00
strlcpy ( desc , _ ( " Address: " ) , sizeof ( desc ) ) ;
2015-02-18 17:30:54 +00:00
}
2017-11-16 18:22:55 +00:00
bool mismatch = false ;
if ( msg - > address_n_count = = 5 ) {
if ( msg - > address_n [ 0 ] = = ( 0x80000000 + 44 ) ) {
mismatch | = msg - > script_type ! = InputScriptType_SPENDADDRESS ;
mismatch | = coin ! = coinByCoinType ( msg - > address_n [ 1 ] ) ;
} else
if ( msg - > address_n [ 0 ] = = ( 0x80000000 + 45 ) ) {
mismatch | = msg - > script_type ! = InputScriptType_SPENDMULTISIG ;
mismatch | = coin ! = coinByCoinType ( msg - > address_n [ 1 ] ) ;
} else
if ( msg - > address_n [ 0 ] = = ( 0x80000000 + 49 ) ) {
mismatch | = ! coin - > has_segwit ;
mismatch | = ! coin - > has_address_type_p2sh ;
mismatch | = msg - > script_type ! = InputScriptType_SPENDP2SHWITNESS ;
mismatch | = coin ! = coinByCoinType ( msg - > address_n [ 1 ] ) ;
}
}
if ( mismatch ) {
layoutDialogSwipe ( & bmp_icon_warning , _ ( " Abort " ) , _ ( " Continue " ) , NULL , _ ( " Wrong address path " ) , _ ( " for selected coin. " ) , NULL , _ ( " Continue at your " ) , _ ( " own risk! " ) , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
}
2017-07-11 19:30:01 +00:00
bool qrcode = false ;
for ( ; ; ) {
2017-11-14 16:53:17 +00:00
layoutAddress ( address , desc , qrcode , msg - > script_type = = InputScriptType_SPENDWITNESS , msg - > address_n , msg - > address_n_count ) ;
2017-07-11 19:30:01 +00:00
if ( protectButton ( ButtonRequestType_ButtonRequest_Address , false ) ) {
break ;
}
qrcode = ! qrcode ;
2014-08-08 17:09:54 +00:00
}
}
2017-08-23 14:36:38 +00:00
strlcpy ( resp - > address , address , sizeof ( resp - > address ) ) ;
2014-04-29 12:26:51 +00:00
msg_write ( MessageType_MessageType_Address , resp ) ;
layoutHome ( ) ;
}
2016-05-23 20:27:18 +00:00
void fsm_msgEthereumGetAddress ( EthereumGetAddress * msg )
{
2016-05-23 20:28:33 +00:00
RESP_INIT ( EthereumAddress ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2016-05-23 20:28:33 +00:00
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-05-23 20:28:33 +00:00
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
resp - > address . size = 20 ;
2016-08-18 14:32:51 +00:00
if ( ! hdnode_get_ethereum_pubkeyhash ( node , resp - > address . bytes ) )
return ;
2016-05-23 20:28:33 +00:00
if ( msg - > has_show_display & & msg - > show_display ) {
char desc [ 16 ] ;
strlcpy ( desc , " Address: " , sizeof ( desc ) ) ;
2017-07-11 19:30:01 +00:00
char address [ 43 ] = { ' 0 ' , ' x ' } ;
ethereum_address_checksum ( resp - > address . bytes , address + 2 ) ;
2016-05-23 20:28:33 +00:00
2017-07-11 19:30:01 +00:00
bool qrcode = false ;
for ( ; ; ) {
2017-11-14 16:53:17 +00:00
layoutAddress ( address , desc , qrcode , false , msg - > address_n , msg - > address_n_count ) ;
2017-07-11 19:30:01 +00:00
if ( protectButton ( ButtonRequestType_ButtonRequest_Address , false ) ) {
break ;
}
qrcode = ! qrcode ;
2016-05-23 20:28:33 +00:00
}
}
2016-05-24 19:31:25 +00:00
msg_write ( MessageType_MessageType_EthereumAddress , resp ) ;
2016-05-23 20:28:33 +00:00
layoutHome ( ) ;
2016-05-23 20:27:18 +00:00
}
2017-07-02 14:12:56 +00:00
void fsm_msgEthereumSignMessage ( EthereumSignMessage * msg )
{
RESP_INIT ( EthereumMessageSignature ) ;
CHECK_INITIALIZED
layoutSignMessage ( msg - > message . bytes , msg - > message . size ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
CHECK_PIN
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
ethereum_message_sign ( msg , node , resp ) ;
layoutHome ( ) ;
}
void fsm_msgEthereumVerifyMessage ( EthereumVerifyMessage * msg )
{
CHECK_PARAM ( msg - > has_address , _ ( " No address provided " ) ) ;
CHECK_PARAM ( msg - > has_message , _ ( " No message provided " ) ) ;
if ( ethereum_message_verify ( msg ) ! = 0 ) {
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Invalid signature " ) ) ;
return ;
}
2017-07-12 15:51:34 +00:00
char address [ 43 ] = { ' 0 ' , ' x ' } ;
ethereum_address_checksum ( msg - > address . bytes , address + 2 ) ;
2017-07-02 14:12:56 +00:00
layoutVerifyAddress ( address ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
layoutVerifyMessage ( msg - > message . bytes , msg - > message . size ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
fsm_sendSuccess ( _ ( " Message verified " ) ) ;
layoutHome ( ) ;
}
2014-04-29 12:26:51 +00:00
void fsm_msgEntropyAck ( EntropyAck * msg )
{
if ( msg - > has_entropy ) {
reset_entropy ( msg - > entropy . bytes , msg - > entropy . size ) ;
} else {
reset_entropy ( 0 , 0 ) ;
}
}
void fsm_msgSignMessage ( SignMessage * msg )
{
RESP_INIT ( MessageSignature ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2015-11-19 10:03:16 +00:00
2014-04-29 12:26:51 +00:00
layoutSignMessage ( msg - > message . bytes , msg - > message . size ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-04-29 12:26:51 +00:00
layoutHome ( ) ;
return ;
}
2016-11-22 20:06:39 +00:00
CHECK_PIN
2014-04-29 12:26:51 +00:00
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2015-01-26 11:51:56 +00:00
if ( ! coin ) return ;
2016-06-26 14:27:29 +00:00
HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2017-06-18 20:22:33 +00:00
layoutProgressSwipe ( _ ( " Signing " ) , 0 ) ;
2017-07-24 15:40:46 +00:00
if ( cryptoMessageSign ( coin , node , msg - > script_type , msg - > message . bytes , msg - > message . size , resp - > signature . bytes ) = = 0 ) {
2014-04-29 12:26:51 +00:00
resp - > has_address = true ;
2017-07-24 15:40:46 +00:00
hdnode_fill_public_key ( node ) ;
if ( ! compute_address ( coin , msg - > script_type , node , false , NULL , resp - > address ) ) {
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Error computing address " ) ) ;
layoutHome ( ) ;
return ;
}
2014-04-29 12:26:51 +00:00
resp - > has_signature = true ;
resp - > signature . size = 65 ;
msg_write ( MessageType_MessageType_MessageSignature , resp ) ;
} else {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Error signing message " ) ) ;
2014-04-29 12:26:51 +00:00
}
layoutHome ( ) ;
}
void fsm_msgVerifyMessage ( VerifyMessage * msg )
{
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_address , _ ( " No address provided " ) ) ;
CHECK_PARAM ( msg - > has_message , _ ( " No message provided " ) ) ;
2016-11-22 20:39:33 +00:00
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2016-05-17 16:13:08 +00:00
if ( ! coin ) return ;
2017-06-18 20:22:33 +00:00
layoutProgressSwipe ( _ ( " Verifying " ) , 0 ) ;
2017-11-01 21:18:29 +00:00
if ( msg - > signature . size = = 65 & & cryptoMessageVerify ( coin , msg - > message . bytes , msg - > message . size , msg - > address , msg - > signature . bytes ) = = 0 ) {
2016-04-25 21:03:57 +00:00
layoutVerifyAddress ( msg - > address ) ;
2016-04-25 21:40:24 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2016-04-25 21:03:57 +00:00
layoutHome ( ) ;
return ;
}
2014-06-02 18:40:20 +00:00
layoutVerifyMessage ( msg - > message . bytes , msg - > message . size ) ;
2016-04-25 21:03:57 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Other , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2016-04-25 21:03:57 +00:00
layoutHome ( ) ;
return ;
}
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " Message verified " ) ) ;
2014-04-29 12:26:51 +00:00
} else {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Invalid signature " ) ) ;
2014-04-29 12:26:51 +00:00
}
layoutHome ( ) ;
}
2015-02-20 19:22:05 +00:00
void fsm_msgSignIdentity ( SignIdentity * msg )
{
RESP_INIT ( SignedIdentity ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2015-11-19 10:03:16 +00:00
2015-02-20 19:22:05 +00:00
layoutSignIdentity ( & ( msg - > identity ) , msg - > has_challenge_visual ? msg - > challenge_visual : 0 ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2015-02-20 19:22:05 +00:00
layoutHome ( ) ;
return ;
}
2016-11-22 20:06:39 +00:00
CHECK_PIN
2015-02-20 19:22:05 +00:00
uint8_t hash [ 32 ] ;
if ( ! msg - > has_identity | | cryptoIdentityFingerprint ( & ( msg - > identity ) , hash ) = = 0 ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Invalid identity " ) ) ;
2015-02-20 19:22:05 +00:00
layoutHome ( ) ;
return ;
}
2015-06-03 19:21:16 +00:00
2015-02-20 19:22:05 +00:00
uint32_t address_n [ 5 ] ;
2015-03-17 14:02:07 +00:00
address_n [ 0 ] = 0x80000000 | 13 ;
2015-02-20 19:22:05 +00:00
address_n [ 1 ] = 0x80000000 | hash [ 0 ] | ( hash [ 1 ] < < 8 ) | ( hash [ 2 ] < < 16 ) | ( hash [ 3 ] < < 24 ) ;
address_n [ 2 ] = 0x80000000 | hash [ 4 ] | ( hash [ 5 ] < < 8 ) | ( hash [ 6 ] < < 16 ) | ( hash [ 7 ] < < 24 ) ;
address_n [ 3 ] = 0x80000000 | hash [ 8 ] | ( hash [ 9 ] < < 8 ) | ( hash [ 10 ] < < 16 ) | ( hash [ 11 ] < < 24 ) ;
address_n [ 4 ] = 0x80000000 | hash [ 12 ] | ( hash [ 13 ] < < 8 ) | ( hash [ 14 ] < < 16 ) | ( hash [ 15 ] < < 24 ) ;
2016-04-19 16:23:12 +00:00
const char * curve = SECP256K1_NAME ;
if ( msg - > has_ecdsa_curve_name ) {
curve = msg - > ecdsa_curve_name ;
}
2016-06-26 14:27:29 +00:00
HDNode * node = fsm_getDerivedNode ( curve , address_n , 5 ) ;
2015-02-20 19:22:05 +00:00
if ( ! node ) return ;
2015-07-04 21:34:26 +00:00
bool sign_ssh = msg - > identity . has_proto & & ( strcmp ( msg - > identity . proto , " ssh " ) = = 0 ) ;
2016-04-15 19:04:45 +00:00
bool sign_gpg = msg - > identity . has_proto & & ( strcmp ( msg - > identity . proto , " gpg " ) = = 0 ) ;
2015-06-03 19:21:16 +00:00
int result = 0 ;
2017-06-18 20:22:33 +00:00
layoutProgressSwipe ( _ ( " Signing " ) , 0 ) ;
2015-07-04 21:34:26 +00:00
if ( sign_ssh ) { // SSH does not sign visual challenge
2016-04-22 15:49:00 +00:00
result = sshMessageSign ( node , msg - > challenge_hidden . bytes , msg - > challenge_hidden . size , resp - > signature . bytes ) ;
2016-04-15 19:04:45 +00:00
} else if ( sign_gpg ) { // GPG should sign a message digest
2016-04-22 15:49:00 +00:00
result = gpgMessageSign ( node , msg - > challenge_hidden . bytes , msg - > challenge_hidden . size , resp - > signature . bytes ) ;
2015-06-03 19:21:16 +00:00
} else {
2015-07-04 21:34:26 +00:00
uint8_t digest [ 64 ] ;
sha256_Raw ( msg - > challenge_hidden . bytes , msg - > challenge_hidden . size , digest ) ;
sha256_Raw ( ( const uint8_t * ) msg - > challenge_visual , strlen ( msg - > challenge_visual ) , digest + 32 ) ;
2017-07-24 15:40:46 +00:00
result = cryptoMessageSign ( & ( coins [ 0 ] ) , node , InputScriptType_SPENDADDRESS , digest , 64 , resp - > signature . bytes ) ;
2015-06-03 19:21:16 +00:00
}
if ( result = = 0 ) {
2016-06-26 14:27:29 +00:00
hdnode_fill_public_key ( node ) ;
2016-04-21 05:29:20 +00:00
if ( strcmp ( curve , SECP256K1_NAME ) ! = 0 ) {
2015-06-03 19:21:16 +00:00
resp - > has_address = false ;
} else {
resp - > has_address = true ;
2016-10-09 19:38:51 +00:00
hdnode_get_address ( node , 0x00 , resp - > address , sizeof ( resp - > address ) ) ; // hardcoded Bitcoin address type
2015-06-03 19:21:16 +00:00
}
2015-02-20 19:22:05 +00:00
resp - > has_public_key = true ;
resp - > public_key . size = 33 ;
2016-04-21 05:29:20 +00:00
memcpy ( resp - > public_key . bytes , node - > public_key , 33 ) ;
2016-06-26 14:27:29 +00:00
if ( node - > public_key [ 0 ] = = 1 ) {
/* ed25519 public key */
resp - > public_key . bytes [ 0 ] = 0 ;
}
2015-02-20 19:22:05 +00:00
resp - > has_signature = true ;
resp - > signature . size = 65 ;
msg_write ( MessageType_MessageType_SignedIdentity , resp ) ;
} else {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Error signing identity " ) ) ;
2015-02-20 19:22:05 +00:00
}
layoutHome ( ) ;
}
2016-06-16 19:40:21 +00:00
void fsm_msgGetECDHSessionKey ( GetECDHSessionKey * msg )
{
RESP_INIT ( ECDHSessionKey ) ;
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2016-06-16 19:40:21 +00:00
2016-07-14 16:11:20 +00:00
layoutDecryptIdentity ( & msg - > identity ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2016-07-14 16:11:20 +00:00
layoutHome ( ) ;
return ;
}
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-06-16 19:40:21 +00:00
uint8_t hash [ 32 ] ;
if ( ! msg - > has_identity | | cryptoIdentityFingerprint ( & ( msg - > identity ) , hash ) = = 0 ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_DataError , _ ( " Invalid identity " ) ) ;
2016-06-16 19:40:21 +00:00
layoutHome ( ) ;
return ;
}
uint32_t address_n [ 5 ] ;
address_n [ 0 ] = 0x80000000 | 17 ;
address_n [ 1 ] = 0x80000000 | hash [ 0 ] | ( hash [ 1 ] < < 8 ) | ( hash [ 2 ] < < 16 ) | ( hash [ 3 ] < < 24 ) ;
address_n [ 2 ] = 0x80000000 | hash [ 4 ] | ( hash [ 5 ] < < 8 ) | ( hash [ 6 ] < < 16 ) | ( hash [ 7 ] < < 24 ) ;
address_n [ 3 ] = 0x80000000 | hash [ 8 ] | ( hash [ 9 ] < < 8 ) | ( hash [ 10 ] < < 16 ) | ( hash [ 11 ] < < 24 ) ;
address_n [ 4 ] = 0x80000000 | hash [ 12 ] | ( hash [ 13 ] < < 8 ) | ( hash [ 14 ] < < 16 ) | ( hash [ 15 ] < < 24 ) ;
const char * curve = SECP256K1_NAME ;
if ( msg - > has_ecdsa_curve_name ) {
curve = msg - > ecdsa_curve_name ;
}
const HDNode * node = fsm_getDerivedNode ( curve , address_n , 5 ) ;
if ( ! node ) return ;
2016-10-13 19:32:26 +00:00
int result_size = 0 ;
if ( hdnode_get_shared_key ( node , msg - > peer_public_key . bytes , resp - > session_key . bytes , & result_size ) = = 0 ) {
2016-06-16 19:40:21 +00:00
resp - > has_session_key = true ;
2016-10-13 19:32:26 +00:00
resp - > session_key . size = result_size ;
2016-06-16 19:40:21 +00:00
msg_write ( MessageType_MessageType_ECDHSessionKey , resp ) ;
} else {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Error getting ECDH session key " ) ) ;
2016-06-16 19:40:21 +00:00
}
layoutHome ( ) ;
}
2016-05-12 19:09:00 +00:00
/* ECIES disabled
2014-10-22 17:53:25 +00:00
void fsm_msgEncryptMessage ( EncryptMessage * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_pubkey , _ ( " No public key provided " ) ) ;
CHECK_PARAM ( msg - > has_message , _ ( " No message provided " ) ) ;
CHECK_PARAM ( msg - > pubkey . size = = 33 , _ ( " Invalid public key provided " ) ) ;
2014-10-22 17:53:25 +00:00
curve_point pubkey ;
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( ecdsa_read_pubkey ( & secp256k1 , msg - > pubkey . bytes , & pubkey ) = = 1 , _ ( " Invalid public key provided " ) ) ;
2016-11-22 20:39:33 +00:00
2014-11-15 01:01:21 +00:00
bool display_only = msg - > has_display_only & & msg - > display_only ;
bool signing = msg - > address_n_count > 0 ;
RESP_INIT ( EncryptedMessage ) ;
2015-01-26 12:53:06 +00:00
const HDNode * node = 0 ;
2016-10-09 19:38:51 +00:00
uint8_t address_raw [ MAX_ADDR_RAW_SIZE ] ;
2014-11-15 01:01:21 +00:00
if ( signing ) {
2017-10-30 21:13:09 +00:00
const CoinInfo * coin = fsm_getCoin ( msg - > has_coin_name , msg - > coin_name ) ;
2016-11-22 19:00:22 +00:00
if ( ! coin ) return ;
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-04-19 16:23:12 +00:00
node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
2014-10-22 17:53:25 +00:00
if ( ! node ) return ;
2016-06-26 14:27:29 +00:00
hdnode_get_address_raw ( node , coin - > address_type , address_raw ) ;
2014-10-22 17:53:25 +00:00
}
2014-11-15 01:01:21 +00:00
layoutEncryptMessage ( msg - > message . bytes , msg - > message . size , signing ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-11-15 01:01:21 +00:00
layoutHome ( ) ;
return ;
}
2017-06-18 20:22:33 +00:00
layoutProgressSwipe ( _ ( " Encrypting " ) , 0 ) ;
2014-11-15 01:01:21 +00:00
if ( cryptoMessageEncrypt ( & pubkey , msg - > message . bytes , msg - > message . size , display_only , resp - > nonce . bytes , & ( resp - > nonce . size ) , resp - > message . bytes , & ( resp - > message . size ) , resp - > hmac . bytes , & ( resp - > hmac . size ) , signing ? node - > private_key : 0 , signing ? address_raw : 0 ) ! = 0 ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ProcessError , _ ( " Error encrypting message " ) ) ;
2014-11-15 01:01:21 +00:00
layoutHome ( ) ;
return ;
}
resp - > has_nonce = true ;
resp - > has_message = true ;
resp - > has_hmac = true ;
msg_write ( MessageType_MessageType_EncryptedMessage , resp ) ;
2014-10-22 17:53:25 +00:00
layoutHome ( ) ;
}
void fsm_msgDecryptMessage ( DecryptMessage * msg )
{
2016-11-22 19:57:45 +00:00
CHECK_INITIALIZED
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > has_nonce , _ ( " No nonce provided " ) ) ;
CHECK_PARAM ( msg - > has_message , _ ( " No message provided " ) ) ;
CHECK_PARAM ( msg - > has_hmac , _ ( " No message hmac provided " ) ) ;
2016-11-22 20:39:33 +00:00
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( msg - > nonce . size = = 33 , _ ( " Invalid nonce key provided " ) ) ;
2014-11-15 01:01:21 +00:00
curve_point nonce_pubkey ;
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( ecdsa_read_pubkey ( & secp256k1 , msg - > nonce . bytes , & nonce_pubkey ) = = 1 , _ ( " Invalid nonce provided " ) ) ;
2016-11-22 20:06:39 +00:00
CHECK_PIN
2016-04-19 16:23:12 +00:00
const HDNode * node = fsm_getDerivedNode ( SECP256K1_NAME , msg - > address_n , msg - > address_n_count ) ;
2014-10-22 17:53:25 +00:00
if ( ! node ) return ;
2014-12-16 17:28:46 +00:00
2017-06-18 20:22:33 +00:00
layoutProgressSwipe ( _ ( " Decrypting " ) , 0 ) ;
2014-11-15 01:01:21 +00:00
RESP_INIT ( DecryptedMessage ) ;
bool display_only = false ;
bool signing = false ;
2016-10-09 19:38:51 +00:00
uint8_t address_raw [ MAX_ADDR_RAW_SIZE ] ;
2014-11-15 01:01:21 +00:00
if ( cryptoMessageDecrypt ( & nonce_pubkey , msg - > message . bytes , msg - > message . size , msg - > hmac . bytes , msg - > hmac . size , node - > private_key , resp - > message . bytes , & ( resp - > message . size ) , & display_only , & signing , address_raw ) ! = 0 ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2014-11-15 01:01:21 +00:00
layoutHome ( ) ;
return ;
}
if ( signing ) {
2014-12-23 00:33:08 +00:00
base58_encode_check ( address_raw , 21 , resp - > address , sizeof ( resp - > address ) ) ;
2014-11-15 01:01:21 +00:00
}
layoutDecryptMessage ( resp - > message . bytes , resp - > message . size , signing ? resp - > address : 0 ) ;
protectButton ( ButtonRequestType_ButtonRequest_Other , true ) ;
if ( display_only ) {
resp - > has_address = false ;
resp - > has_message = false ;
2015-05-18 11:37:44 +00:00
memset ( resp - > address , 0 , sizeof ( resp - > address ) ) ;
memset ( & ( resp - > message ) , 0 , sizeof ( resp - > message ) ) ;
2014-11-15 01:01:21 +00:00
} else {
resp - > has_address = signing ;
resp - > has_message = true ;
}
msg_write ( MessageType_MessageType_DecryptedMessage , resp ) ;
2014-10-22 17:53:25 +00:00
layoutHome ( ) ;
}
2016-05-12 19:09:00 +00:00
*/
2014-10-22 17:53:25 +00:00
2014-04-29 12:26:51 +00:00
void fsm_msgRecoveryDevice ( RecoveryDevice * msg )
{
2017-06-20 19:49:17 +00:00
const bool dry_run = msg - > has_dry_run ? msg - > dry_run : false ;
if ( dry_run ) {
CHECK_PIN
} else {
CHECK_NOT_INITIALIZED
}
2016-11-22 19:57:45 +00:00
2017-06-18 20:22:33 +00:00
CHECK_PARAM ( ! msg - > has_word_count | | msg - > word_count = = 12 | | msg - > word_count = = 18 | | msg - > word_count = = 24 , _ ( " Invalid word count " ) ) ;
2016-11-22 20:39:33 +00:00
2014-04-29 12:26:51 +00:00
recovery_init (
msg - > has_word_count ? msg - > word_count : 12 ,
msg - > has_passphrase_protection & & msg - > passphrase_protection ,
msg - > has_pin_protection & & msg - > pin_protection ,
msg - > has_language ? msg - > language : 0 ,
msg - > has_label ? msg - > label : 0 ,
2016-11-23 11:56:42 +00:00
msg - > has_enforce_wordlist & & msg - > enforce_wordlist ,
msg - > has_type ? msg - > type : 0 ,
2017-06-20 19:49:17 +00:00
msg - > has_u2f_counter ? msg - > u2f_counter : 0 ,
dry_run
2014-04-29 12:26:51 +00:00
) ;
}
void fsm_msgWordAck ( WordAck * msg )
{
recovery_word ( msg - > word ) ;
}
2016-06-12 21:39:28 +00:00
void fsm_msgSetU2FCounter ( SetU2FCounter * msg )
{
2017-06-18 20:22:33 +00:00
layoutDialogSwipe ( & bmp_icon_question , _ ( " Cancel " ) , _ ( " Confirm " ) , NULL , _ ( " Do you want to set " ) , _ ( " the U2F counter? " ) , NULL , NULL , NULL , NULL ) ;
2016-09-27 21:33:28 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
2017-06-18 20:22:33 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
2016-09-27 21:33:28 +00:00
layoutHome ( ) ;
return ;
}
2016-06-12 21:39:28 +00:00
storage_setU2FCounter ( msg - > u2f_counter ) ;
2017-06-18 20:22:33 +00:00
fsm_sendSuccess ( _ ( " U2F counter set " ) ) ;
2016-09-27 21:33:28 +00:00
layoutHome ( ) ;
2016-06-12 21:39:28 +00:00
}
2017-05-29 16:07:55 +00:00
void fsm_msgNEMGetAddress ( NEMGetAddress * msg )
{
if ( ! msg - > has_network ) {
msg - > network = NEM_NETWORK_MAINNET ;
}
const char * network ;
CHECK_PARAM ( ( network = nem_network_name ( msg - > network ) ) , _ ( " Invalid NEM network " ) ) ;
CHECK_INITIALIZED
CHECK_PIN
RESP_INIT ( NEMAddress ) ;
HDNode * node = fsm_getDerivedNode ( ED25519_KECCAK_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
if ( ! hdnode_get_nem_address ( node , msg - > network , resp - > address ) )
return ;
if ( msg - > has_show_display & & msg - > show_display ) {
char desc [ 16 ] ;
strlcpy ( desc , network , sizeof ( desc ) ) ;
strlcat ( desc , " : " , sizeof ( desc ) ) ;
bool qrcode = false ;
for ( ; ; ) {
2017-11-14 16:53:17 +00:00
layoutAddress ( resp - > address , desc , qrcode , true , msg - > address_n , msg - > address_n_count ) ;
2017-05-29 16:07:55 +00:00
if ( protectButton ( ButtonRequestType_ButtonRequest_Address , false ) ) {
break ;
}
qrcode = ! qrcode ;
}
}
msg_write ( MessageType_MessageType_NEMAddress , resp ) ;
layoutHome ( ) ;
}
2017-05-30 16:41:02 +00:00
void fsm_msgNEMSignTx ( NEMSignTx * msg ) {
2017-07-16 19:54:58 +00:00
const char * reason ;
# define NEM_CHECK_PARAM(s) CHECK_PARAM( (reason = (s)) == NULL, reason)
# define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason)
2017-05-30 16:41:02 +00:00
CHECK_PARAM ( msg - > has_transaction , _ ( " No common provided " ) ) ;
2017-07-16 19:54:58 +00:00
// Ensure exactly one transaction is provided
2017-07-23 17:55:13 +00:00
unsigned int provided = msg - > has_transfer +
msg - > has_provision_namespace +
msg - > has_mosaic_creation +
msg - > has_supply_change +
2017-10-07 21:07:56 +00:00
msg - > has_aggregate_modification +
msg - > has_importance_transfer ;
2017-07-16 19:54:58 +00:00
CHECK_PARAM ( provided ! = 0 , _ ( " No transaction provided " ) ) ;
CHECK_PARAM ( provided = = 1 , _ ( " More than one transaction provided " ) ) ;
2017-07-01 13:38:04 +00:00
2017-07-16 19:54:58 +00:00
NEM_CHECK_PARAM ( nem_validate_common ( & msg - > transaction , false ) ) ;
NEM_CHECK_PARAM_WHEN ( msg - > has_transfer , nem_validate_transfer ( & msg - > transfer , msg - > transaction . network ) ) ;
2017-07-17 19:23:20 +00:00
NEM_CHECK_PARAM_WHEN ( msg - > has_provision_namespace , nem_validate_provision_namespace ( & msg - > provision_namespace , msg - > transaction . network ) ) ;
2017-07-22 18:02:41 +00:00
NEM_CHECK_PARAM_WHEN ( msg - > has_mosaic_creation , nem_validate_mosaic_creation ( & msg - > mosaic_creation , msg - > transaction . network ) ) ;
2017-07-23 14:45:20 +00:00
NEM_CHECK_PARAM_WHEN ( msg - > has_supply_change , nem_validate_supply_change ( & msg - > supply_change ) ) ;
2017-07-23 17:55:13 +00:00
NEM_CHECK_PARAM_WHEN ( msg - > has_aggregate_modification , nem_validate_aggregate_modification ( & msg - > aggregate_modification , ! msg - > has_multisig ) ) ;
2017-10-07 21:07:56 +00:00
NEM_CHECK_PARAM_WHEN ( msg - > has_importance_transfer , nem_validate_importance_transfer ( & msg - > importance_transfer ) ) ;
2017-05-30 16:41:02 +00:00
2017-07-16 19:54:58 +00:00
bool cosigning = msg - > has_cosigning & & msg - > cosigning ;
2017-07-01 13:38:04 +00:00
if ( msg - > has_multisig ) {
2017-07-16 19:54:58 +00:00
NEM_CHECK_PARAM ( nem_validate_common ( & msg - > multisig , true ) ) ;
2017-07-01 13:38:04 +00:00
CHECK_PARAM ( msg - > transaction . network = = msg - > multisig . network , _ ( " Inner transaction network is different " ) ) ;
} else {
CHECK_PARAM ( ! cosigning , _ ( " No multisig transaction to cosign " ) ) ;
}
2017-05-30 16:41:02 +00:00
CHECK_INITIALIZED
CHECK_PIN
2017-07-01 13:38:04 +00:00
const char * network = nem_network_name ( msg - > transaction . network ) ;
if ( msg - > has_multisig ) {
char address [ NEM_ADDRESS_SIZE + 1 ] ;
nem_get_address ( msg - > multisig . signer . bytes , msg - > multisig . network , address ) ;
if ( ! nem_askMultisig ( address , network , cosigning , msg - > transaction . fee ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
}
2017-07-22 18:02:41 +00:00
RESP_INIT ( NEMSignedTx ) ;
HDNode * node = fsm_getDerivedNode ( ED25519_KECCAK_NAME , msg - > transaction . address_n , msg - > transaction . address_n_count ) ;
if ( ! node ) return ;
hdnode_fill_public_key ( node ) ;
2017-07-01 13:38:04 +00:00
const NEMTransactionCommon * common = msg - > has_multisig ? & msg - > multisig : & msg - > transaction ;
2017-07-22 18:02:41 +00:00
char address [ NEM_ADDRESS_SIZE + 1 ] ;
hdnode_get_nem_address ( node , common - > network , address ) ;
2017-07-28 15:29:31 +00:00
if ( msg - > has_transfer ) {
msg - > transfer . mosaics_count = nem_canonicalizeMosaics ( msg - > transfer . mosaics , msg - > transfer . mosaics_count ) ;
}
2017-07-01 13:38:04 +00:00
if ( msg - > has_transfer & & ! nem_askTransfer ( common , & msg - > transfer , network ) ) {
2017-05-30 16:41:02 +00:00
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-07-17 19:23:20 +00:00
if ( msg - > has_provision_namespace & & ! nem_askProvisionNamespace ( common , & msg - > provision_namespace , network ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-07-22 18:02:41 +00:00
if ( msg - > has_mosaic_creation & & ! nem_askMosaicCreation ( common , & msg - > mosaic_creation , network , address ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-07-01 13:38:04 +00:00
2017-07-23 14:45:20 +00:00
if ( msg - > has_supply_change & & ! nem_askSupplyChange ( common , & msg - > supply_change , network ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-07-23 17:55:13 +00:00
if ( msg - > has_aggregate_modification & & ! nem_askAggregateModification ( common , & msg - > aggregate_modification , network , ! msg - > has_multisig ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-10-07 21:07:56 +00:00
if ( msg - > has_importance_transfer & & ! nem_askImportanceTransfer ( common , & msg - > importance_transfer , network ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , _ ( " Signing cancelled by user " ) ) ;
layoutHome ( ) ;
return ;
}
2017-05-30 16:41:02 +00:00
nem_transaction_ctx context ;
nem_transaction_start ( & context , & node - > public_key [ 1 ] , resp - > data . bytes , sizeof ( resp - > data . bytes ) ) ;
2017-07-01 13:38:04 +00:00
if ( msg - > has_multisig ) {
uint8_t buffer [ sizeof ( resp - > data . bytes ) ] ;
nem_transaction_ctx inner ;
nem_transaction_start ( & inner , msg - > multisig . signer . bytes , buffer , sizeof ( buffer ) ) ;
if ( msg - > has_transfer & & ! nem_fsmTransfer ( & inner , NULL , & msg - > multisig , & msg - > transfer ) ) {
layoutHome ( ) ;
return ;
}
2017-07-17 19:23:20 +00:00
if ( msg - > has_provision_namespace & & ! nem_fsmProvisionNamespace ( & inner , & msg - > multisig , & msg - > provision_namespace ) ) {
layoutHome ( ) ;
return ;
}
2017-07-22 18:02:41 +00:00
if ( msg - > has_mosaic_creation & & ! nem_fsmMosaicCreation ( & inner , & msg - > multisig , & msg - > mosaic_creation ) ) {
layoutHome ( ) ;
return ;
}
2017-07-23 14:45:20 +00:00
if ( msg - > has_supply_change & & ! nem_fsmSupplyChange ( & inner , & msg - > multisig , & msg - > supply_change ) ) {
layoutHome ( ) ;
return ;
}
2017-07-23 17:55:13 +00:00
if ( msg - > has_aggregate_modification & & ! nem_fsmAggregateModification ( & inner , & msg - > multisig , & msg - > aggregate_modification ) ) {
layoutHome ( ) ;
return ;
}
2017-10-07 21:07:56 +00:00
if ( msg - > has_importance_transfer & & ! nem_fsmImportanceTransfer ( & inner , & msg - > multisig , & msg - > importance_transfer ) ) {
layoutHome ( ) ;
return ;
}
2017-07-01 13:38:04 +00:00
if ( ! nem_fsmMultisig ( & context , & msg - > transaction , & inner , cosigning ) ) {
layoutHome ( ) ;
return ;
}
} else {
if ( msg - > has_transfer & & ! nem_fsmTransfer ( & context , node , & msg - > transaction , & msg - > transfer ) ) {
layoutHome ( ) ;
return ;
}
2017-07-17 19:23:20 +00:00
if ( msg - > has_provision_namespace & & ! nem_fsmProvisionNamespace ( & context , & msg - > transaction , & msg - > provision_namespace ) ) {
layoutHome ( ) ;
return ;
}
2017-07-22 18:02:41 +00:00
if ( msg - > has_mosaic_creation & & ! nem_fsmMosaicCreation ( & context , & msg - > transaction , & msg - > mosaic_creation ) ) {
layoutHome ( ) ;
return ;
}
2017-07-23 14:45:20 +00:00
if ( msg - > has_supply_change & & ! nem_fsmSupplyChange ( & context , & msg - > transaction , & msg - > supply_change ) ) {
layoutHome ( ) ;
return ;
}
2017-07-23 17:55:13 +00:00
if ( msg - > has_aggregate_modification & & ! nem_fsmAggregateModification ( & context , & msg - > transaction , & msg - > aggregate_modification ) ) {
layoutHome ( ) ;
return ;
}
2017-10-07 21:07:56 +00:00
if ( msg - > has_importance_transfer & & ! nem_fsmImportanceTransfer ( & context , & msg - > transaction , & msg - > importance_transfer ) ) {
layoutHome ( ) ;
return ;
}
2017-05-30 16:41:02 +00:00
}
resp - > has_data = true ;
resp - > data . size = nem_transaction_end ( & context , node - > private_key , resp - > signature . bytes ) ;
resp - > has_signature = true ;
resp - > signature . size = sizeof ( ed25519_signature ) ;
msg_write ( MessageType_MessageType_NEMSignedTx , resp ) ;
layoutHome ( ) ;
}
2017-10-03 11:11:53 +00:00
void fsm_msgCosiCommit ( CosiCommit * msg )
{
RESP_INIT ( CosiCommitment ) ;
CHECK_INITIALIZED
CHECK_PARAM ( msg - > has_data , _ ( " No data provided " ) ) ;
2017-10-09 19:05:59 +00:00
layoutCosiCommitSign ( msg - > address_n , msg - > address_n_count , msg - > data . bytes , msg - > data . size , false ) ;
2017-10-03 11:11:53 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
CHECK_PIN
HDNode * node = fsm_getDerivedNode ( ED25519_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
uint8_t nonce [ 32 ] ;
sha256_Raw ( msg - > data . bytes , msg - > data . size , nonce ) ;
rfc6979_state rng ;
init_rfc6979 ( node - > private_key , nonce , & rng ) ;
generate_rfc6979 ( nonce , & rng ) ;
resp - > has_commitment = true ;
resp - > has_pubkey = true ;
resp - > commitment . size = 32 ;
resp - > pubkey . size = 32 ;
ed25519_publickey ( nonce , resp - > commitment . bytes ) ;
ed25519_publickey ( node - > private_key , resp - > pubkey . bytes ) ;
msg_write ( MessageType_MessageType_CosiCommitment , resp ) ;
layoutHome ( ) ;
}
void fsm_msgCosiSign ( CosiSign * msg )
{
RESP_INIT ( CosiSignature ) ;
CHECK_INITIALIZED
CHECK_PARAM ( msg - > has_data , _ ( " No data provided " ) ) ;
CHECK_PARAM ( msg - > has_global_commitment & & msg - > global_commitment . size = = 32 , _ ( " Invalid global commitment " ) ) ;
CHECK_PARAM ( msg - > has_global_pubkey & & msg - > global_pubkey . size = = 32 , _ ( " Invalid global pubkey " ) ) ;
2017-10-09 19:05:59 +00:00
layoutCosiCommitSign ( msg - > address_n , msg - > address_n_count , msg - > data . bytes , msg - > data . size , true ) ;
2017-10-03 11:11:53 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , NULL ) ;
layoutHome ( ) ;
return ;
}
CHECK_PIN
HDNode * node = fsm_getDerivedNode ( ED25519_NAME , msg - > address_n , msg - > address_n_count ) ;
if ( ! node ) return ;
uint8_t nonce [ 32 ] ;
sha256_Raw ( msg - > data . bytes , msg - > data . size , nonce ) ;
rfc6979_state rng ;
init_rfc6979 ( node - > private_key , nonce , & rng ) ;
generate_rfc6979 ( nonce , & rng ) ;
resp - > has_signature = true ;
resp - > signature . size = 32 ;
ed25519_cosi_sign ( msg - > data . bytes , msg - > data . size , node - > private_key , nonce , msg - > global_commitment . bytes , msg - > global_pubkey . bytes , resp - > signature . bytes ) ;
msg_write ( MessageType_MessageType_CosiSignature , resp ) ;
layoutHome ( ) ;
}
2014-04-29 12:26:51 +00:00
# if DEBUG_LINK
void fsm_msgDebugLinkGetState ( DebugLinkGetState * msg )
{
( void ) msg ;
2017-07-29 20:08:51 +00:00
// Do not use RESP_INIT because it clears msg_resp, but another message
// might be being handled
DebugLinkState resp ;
memset ( & resp , 0 , sizeof ( resp ) ) ;
resp . has_layout = true ;
resp . layout . size = OLED_BUFSIZE ;
memcpy ( resp . layout . bytes , oledGetBuffer ( ) , OLED_BUFSIZE ) ;
2014-04-29 12:26:51 +00:00
if ( storage . has_pin ) {
2017-07-29 20:08:51 +00:00
resp . has_pin = true ;
strlcpy ( resp . pin , storage . pin , sizeof ( resp . pin ) ) ;
2014-04-29 12:26:51 +00:00
}
2017-07-29 20:08:51 +00:00
resp . has_matrix = true ;
strlcpy ( resp . matrix , pinmatrix_get ( ) , sizeof ( resp . matrix ) ) ;
2014-04-29 12:26:51 +00:00
2017-07-29 20:08:51 +00:00
resp . has_reset_entropy = true ;
resp . reset_entropy . size = reset_get_int_entropy ( resp . reset_entropy . bytes ) ;
2014-04-29 12:26:51 +00:00
2017-07-29 20:08:51 +00:00
resp . has_reset_word = true ;
strlcpy ( resp . reset_word , reset_get_word ( ) , sizeof ( resp . reset_word ) ) ;
2014-04-29 12:26:51 +00:00
2017-07-29 20:08:51 +00:00
resp . has_recovery_fake_word = true ;
strlcpy ( resp . recovery_fake_word , recovery_get_fake_word ( ) , sizeof ( resp . recovery_fake_word ) ) ;
2014-04-29 12:26:51 +00:00
2017-07-29 20:08:51 +00:00
resp . has_recovery_word_pos = true ;
resp . recovery_word_pos = recovery_get_word_pos ( ) ;
2014-04-29 12:26:51 +00:00
if ( storage . has_mnemonic ) {
2017-07-29 20:08:51 +00:00
resp . has_mnemonic = true ;
strlcpy ( resp . mnemonic , storage . mnemonic , sizeof ( resp . mnemonic ) ) ;
2014-04-29 12:26:51 +00:00
}
if ( storage . has_node ) {
2017-07-29 20:08:51 +00:00
resp . has_node = true ;
memcpy ( & ( resp . node ) , & ( storage . node ) , sizeof ( HDNode ) ) ;
2014-04-29 12:26:51 +00:00
}
2017-07-29 20:08:51 +00:00
resp . has_passphrase_protection = true ;
resp . passphrase_protection = storage . has_passphrase_protection & & storage . passphrase_protection ;
2014-04-29 12:26:51 +00:00
2017-07-29 20:08:51 +00:00
msg_debug_write ( MessageType_MessageType_DebugLinkState , & resp ) ;
2014-04-29 12:26:51 +00:00
}
void fsm_msgDebugLinkStop ( DebugLinkStop * msg )
{
( void ) msg ;
}
2016-05-26 18:28:11 +00:00
void fsm_msgDebugLinkMemoryRead ( DebugLinkMemoryRead * msg )
{
RESP_INIT ( DebugLinkMemory ) ;
uint32_t length = 1024 ;
if ( msg - > has_length & & msg - > length < length )
length = msg - > length ;
resp - > has_memory = true ;
memcpy ( resp - > memory . bytes , ( void * ) msg - > address , length ) ;
resp - > memory . size = length ;
msg_debug_write ( MessageType_MessageType_DebugLinkMemory , resp ) ;
}
void fsm_msgDebugLinkMemoryWrite ( DebugLinkMemoryWrite * msg )
{
uint32_t length = msg - > memory . size ;
if ( msg - > flash ) {
flash_clear_status_flags ( ) ;
flash_unlock ( ) ;
2017-07-23 20:20:51 +00:00
for ( uint32_t i = 0 ; i < length ; i + = 4 ) {
2016-08-29 21:22:49 +00:00
uint32_t word ;
memcpy ( & word , msg - > memory . bytes + i , 4 ) ;
flash_program_word ( msg - > address + i , word ) ;
2016-05-26 18:28:11 +00:00
}
flash_lock ( ) ;
} else {
memcpy ( ( void * ) msg - > address , msg - > memory . bytes , length ) ;
}
}
void fsm_msgDebugLinkFlashErase ( DebugLinkFlashErase * msg )
{
flash_clear_status_flags ( ) ;
flash_unlock ( ) ;
flash_erase_sector ( msg - > sector , FLASH_CR_PROGRAM_X32 ) ;
flash_lock ( ) ;
}
2014-04-29 12:26:51 +00:00
# endif