2014-04-29 12:26:51 +00:00
/*
* This file is part of the TREZOR project .
*
* 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/>.
*/
# 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"
# 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"
2015-06-03 19:21:16 +00:00
# include "secp256k1.h"
# include "nist256p1.h"
2014-04-29 12:26:51 +00:00
// message methods
static uint8_t msg_resp [ MSG_OUT_SIZE ] ;
2015-08-24 10:47:27 +00:00
# define RESP_INIT(TYPE) TYPE *resp = (TYPE *)msg_resp; \
_Static_assert ( sizeof ( msg_resp ) > = sizeof ( TYPE ) , # TYPE " is too large " ) ; \
memset ( resp , 0 , sizeof ( TYPE ) ) ;
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 ;
if ( text ) {
resp - > has_message = true ;
strlcpy ( resp - > message , text , sizeof ( resp - > message ) ) ;
}
msg_write ( MessageType_MessageType_Failure , resp ) ;
}
2015-01-26 11:51:56 +00:00
const CoinType * fsm_getCoin ( const char * name )
{
const CoinType * coin = coinByName ( name ) ;
if ( ! coin ) {
fsm_sendFailure ( FailureType_Failure_Other , " Invalid coin name " ) ;
layoutHome ( ) ;
return 0 ;
}
return coin ;
}
2015-01-26 12:53:06 +00:00
const HDNode * fsm_getDerivedNode ( uint32_t * address_n , size_t address_n_count )
2014-04-29 12:26:51 +00:00
{
static HDNode node ;
if ( ! storage_getRootNode ( & node ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized or passphrase request cancelled " ) ;
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 ;
}
2015-01-26 19:24:07 +00:00
if ( hdnode_private_ckd_cached ( & node , address_n , address_n_count ) = = 0 ) {
fsm_sendFailure ( FailureType_Failure_Other , " Failed to derive private key " ) ;
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 ) ) ;
}
resp - > coins_count = COINS_COUNT ;
memcpy ( resp - > coins , coins , COINS_COUNT * sizeof ( CoinType ) ) ;
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 ( ) ;
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 ) {
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " answer to ping? " , NULL , NULL , NULL , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Ping cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
if ( msg - > has_pin_protection & & msg - > pin_protection ) {
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
}
if ( msg - > has_passphrase_protection & & msg - > passphrase_protection ) {
if ( ! protectPassphrase ( ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Ping cancelled " ) ;
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 ( ) ) {
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " remove current PIN? " , NULL , NULL , NULL , NULL ) ;
} else {
fsm_sendSuccess ( " PIN removed " ) ;
return ;
}
} else {
if ( storage_hasPin ( ) ) {
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " change current PIN? " , NULL , NULL , NULL , NULL ) ;
} else {
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " set new PIN? " , NULL , NULL , NULL , NULL ) ;
}
}
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , removal ? " PIN removal cancelled " : " PIN change cancelled " ) ;
layoutHome ( ) ;
return ;
}
if ( ! protectPin ( false ) ) {
layoutHome ( ) ;
return ;
}
if ( removal ) {
storage_setPin ( 0 ) ;
fsm_sendSuccess ( " PIN removed " ) ;
} else {
if ( protectChangePin ( ) ) {
fsm_sendSuccess ( " PIN changed " ) ;
} else {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " PIN change failed " ) ;
}
}
layoutHome ( ) ;
}
void fsm_msgWipeDevice ( WipeDevice * msg )
{
( void ) msg ;
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " wipe the device? " , NULL , " All data will be lost. " , NULL , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_WipeDevice , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Wipe cancelled " ) ;
layoutHome ( ) ;
return ;
}
storage_reset ( ) ;
storage_reset_uuid ( ) ;
storage_commit ( ) ;
// 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
fsm_sendSuccess ( " Device wiped " ) ;
layoutHome ( ) ;
}
void fsm_msgFirmwareErase ( FirmwareErase * msg )
{
( void ) msg ;
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , " Not in bootloader mode " ) ;
}
void fsm_msgFirmwareUpload ( FirmwareUpload * msg )
{
( void ) msg ;
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , " Not in bootloader mode " ) ;
}
void fsm_msgGetEntropy ( GetEntropy * msg )
{
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " send entropy? " , NULL , NULL , NULL , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Entropy cancelled " ) ;
layoutHome ( ) ;
return ;
}
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 ) ;
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2015-03-30 12:38:33 +00:00
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( msg - > address_n , msg - > address_n_count ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2015-06-03 19:21:16 +00:00
uint8_t public_key [ 33 ] ; // copy public key to temporary buffer
memcpy ( public_key , node - > public_key , sizeof ( public_key ) ) ;
if ( msg - > has_ecdsa_curve_name ) {
const ecdsa_curve * curve = get_curve_by_name ( msg - > ecdsa_curve_name ) ;
if ( curve ) {
// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
ecdsa_get_public_key33 ( curve , node - > private_key , public_key ) ;
}
}
2015-11-19 10:48:26 +00:00
if ( msg - > has_show_display & & msg - > show_display ) {
layoutPublicKey ( public_key ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_PublicKey , true ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Show public key cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
resp - > node . depth = node - > depth ;
resp - > node . fingerprint = node - > fingerprint ;
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 ;
2015-06-03 19:21:16 +00:00
memcpy ( resp - > node . public_key . bytes , public_key , 33 ) ;
2014-08-07 19:53:55 +00:00
resp - > has_xpub = true ;
2014-12-23 00:33:08 +00:00
hdnode_serialize_public ( node , 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 )
{
if ( storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , " Device is already initialized. Use Wipe first. " ) ;
return ;
}
2014-05-25 16:32:12 +00:00
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " I take the risk " , NULL , " Loading private seed " , " is not recommended. " , " Continue only if you " , " know what you are " , " doing! " , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Load cancelled " ) ;
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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Mnemonic with wrong checksum provided " ) ;
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
storage_loadDevice ( msg ) ;
storage_commit ( ) ;
fsm_sendSuccess ( " Device loaded " ) ;
layoutHome ( ) ;
}
void fsm_msgResetDevice ( ResetDevice * msg )
{
if ( storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , " Device is already initialized. Use Wipe first. " ) ;
return ;
}
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 ,
msg - > has_label ? msg - > label : 0
) ;
}
void fsm_msgSignTx ( SignTx * msg )
{
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2014-04-29 12:26:51 +00:00
if ( msg - > inputs_count < 1 ) {
fsm_sendFailure ( FailureType_Failure_Other , " Transaction must have at least one input " ) ;
layoutHome ( ) ;
return ;
}
if ( msg - > outputs_count < 1 ) {
fsm_sendFailure ( FailureType_Failure_Other , " Transaction must have at least one output " ) ;
layoutHome ( ) ;
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 11:51:56 +00:00
const CoinType * coin = fsm_getCoin ( msg - > coin_name ) ;
if ( ! coin ) return ;
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( 0 , 0 ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
signing_init ( msg - > inputs_count , msg - > outputs_count , coin , node ) ;
}
void fsm_msgCancel ( Cancel * msg )
{
( void ) msg ;
recovery_abort ( ) ;
signing_abort ( ) ;
}
void fsm_msgTxAck ( TxAck * msg )
{
if ( msg - > has_tx ) {
signing_txack ( & ( msg - > tx ) ) ;
} else {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No transaction provided " ) ;
}
}
2014-06-07 12:21:59 +00:00
void fsm_msgCipherKeyValue ( CipherKeyValue * msg )
{
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2014-06-07 12:21:59 +00:00
if ( ! msg - > has_key ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No key provided " ) ;
return ;
}
if ( ! msg - > has_value ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No value provided " ) ;
return ;
}
if ( msg - > value . size % 16 ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " Value length must be a multiple of 16 " ) ;
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( 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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " CipherKeyValue cancelled " ) ;
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 ( ) ;
2014-06-17 14:03:07 +00:00
fsm_sendSuccess ( " Session cleared " ) ;
}
2014-04-29 12:26:51 +00:00
void fsm_msgApplySettings ( ApplySettings * msg )
{
if ( msg - > has_label ) {
layoutDialogSwipe ( DIALOG_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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Apply settings cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
if ( msg - > has_language ) {
layoutDialogSwipe ( DIALOG_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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Apply settings cancelled " ) ;
layoutHome ( ) ;
return ;
}
2014-04-29 12:26:51 +00:00
}
2014-12-13 18:29:27 +00:00
if ( msg - > has_use_passphrase ) {
2015-02-05 17:59:43 +00:00
layoutDialogSwipe ( DIALOG_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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Apply settings cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
2015-02-04 20:27:07 +00:00
if ( msg - > has_homescreen ) {
layoutDialogSwipe ( DIALOG_ICON_QUESTION , " Cancel " , " Confirm " , NULL , " Do you really want to " , " change the home " , " screen ? " , NULL , NULL , NULL ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Apply settings cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
if ( ! msg - > has_label & & ! msg - > has_language & & ! msg - > has_use_passphrase & & ! msg - > has_homescreen ) {
2014-12-13 18:29:27 +00:00
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No setting provided " ) ;
2014-04-29 12:26:51 +00:00
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
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 ( ) ;
fsm_sendSuccess ( " Settings applied " ) ;
layoutHome ( ) ;
}
void fsm_msgGetAddress ( GetAddress * msg )
{
RESP_INIT ( Address ) ;
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2015-03-30 12:38:33 +00:00
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 11:51:56 +00:00
const CoinType * coin = fsm_getCoin ( msg - > coin_name ) ;
if ( ! coin ) return ;
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( msg - > address_n , msg - > address_n_count ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2014-12-10 17:04:51 +00:00
if ( msg - > has_multisig ) {
2014-12-23 00:33:08 +00:00
layoutProgressSwipe ( " Preparing " , 0 ) ;
2014-12-13 19:33:49 +00:00
if ( cryptoMultisigPubkeyIndex ( & ( msg - > multisig ) , node - > public_key ) < 0 ) {
2014-12-10 17:04:51 +00:00
fsm_sendFailure ( FailureType_Failure_Other , " Pubkey not found in multisig script " ) ;
layoutHome ( ) ;
return ;
}
uint8_t buf [ 32 ] ;
if ( compile_script_multisig_hash ( & ( msg - > multisig ) , buf ) = = 0 ) {
fsm_sendFailure ( FailureType_Failure_Other , " Invalid multisig script " ) ;
layoutHome ( ) ;
return ;
}
ripemd160 ( buf , 32 , buf + 1 ) ;
2014-12-23 00:33:08 +00:00
buf [ 0 ] = coin - > address_type_p2sh ; // multisig cointype
base58_encode_check ( buf , 21 , resp - > address , sizeof ( resp - > address ) ) ;
2014-12-10 17:04:51 +00:00
} else {
2014-12-23 00:33:08 +00:00
ecdsa_get_address ( node - > public_key , coin - > address_type , resp - > address , sizeof ( resp - > address ) ) ;
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 {
strlcpy ( desc , " Address: " , sizeof ( desc ) ) ;
}
layoutAddress ( resp - > address , desc ) ;
2014-08-08 17:09:54 +00:00
if ( ! protectButton ( ButtonRequestType_ButtonRequest_Address , true ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Show address cancelled " ) ;
layoutHome ( ) ;
return ;
}
}
2014-04-29 12:26:51 +00:00
msg_write ( MessageType_MessageType_Address , resp ) ;
layoutHome ( ) ;
}
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 ) ;
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2014-04-29 12:26:51 +00:00
layoutSignMessage ( msg - > message . bytes , msg - > message . size ) ;
if ( ! protectButton ( ButtonRequestType_ButtonRequest_ProtectCall , false ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Sign message cancelled " ) ;
layoutHome ( ) ;
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 11:51:56 +00:00
const CoinType * coin = fsm_getCoin ( msg - > coin_name ) ;
if ( ! coin ) return ;
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( msg - > address_n , msg - > address_n_count ) ;
2014-04-29 12:26:51 +00:00
if ( ! node ) return ;
2014-12-21 17:58:56 +00:00
layoutProgressSwipe ( " Signing " , 0 ) ;
2014-12-08 20:21:44 +00:00
if ( cryptoMessageSign ( msg - > message . bytes , msg - > message . size , node - > private_key , resp - > signature . bytes ) = = 0 ) {
2014-04-29 12:26:51 +00:00
resp - > has_address = true ;
2014-12-08 20:21:44 +00:00
uint8_t addr_raw [ 21 ] ;
ecdsa_get_address_raw ( node - > public_key , coin - > address_type , addr_raw ) ;
2014-12-23 00:33:08 +00:00
base58_encode_check ( addr_raw , 21 , resp - > address , sizeof ( resp - > address ) ) ;
2014-04-29 12:26:51 +00:00
resp - > has_signature = true ;
resp - > signature . size = 65 ;
msg_write ( MessageType_MessageType_MessageSignature , resp ) ;
} else {
fsm_sendFailure ( FailureType_Failure_Other , " Error signing message " ) ;
}
layoutHome ( ) ;
}
void fsm_msgVerifyMessage ( VerifyMessage * msg )
{
2014-11-15 01:01:21 +00:00
if ( ! msg - > has_address ) {
fsm_sendFailure ( FailureType_Failure_Other , " No address provided " ) ;
return ;
}
if ( ! msg - > has_message ) {
fsm_sendFailure ( FailureType_Failure_Other , " No message provided " ) ;
return ;
}
2014-12-21 17:58:56 +00:00
layoutProgressSwipe ( " Verifying " , 0 ) ;
2014-11-15 01:01:21 +00:00
uint8_t addr_raw [ 21 ] ;
if ( ! ecdsa_address_decode ( msg - > address , addr_raw ) ) {
fsm_sendFailure ( FailureType_Failure_InvalidSignature , " Invalid address " ) ;
}
if ( msg - > signature . size = = 65 & & cryptoMessageVerify ( msg - > message . bytes , msg - > message . size , addr_raw , msg - > signature . bytes ) = = 0 ) {
2014-06-02 18:40:20 +00:00
layoutVerifyMessage ( msg - > message . bytes , msg - > message . size ) ;
protectButton ( ButtonRequestType_ButtonRequest_Other , true ) ;
2014-04-29 12:26:51 +00:00
fsm_sendSuccess ( " Message verified " ) ;
} else {
fsm_sendFailure ( FailureType_Failure_InvalidSignature , " Invalid signature " ) ;
}
layoutHome ( ) ;
}
2015-02-20 19:22:05 +00:00
void fsm_msgSignIdentity ( SignIdentity * msg )
{
RESP_INIT ( SignedIdentity ) ;
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Sign identity cancelled " ) ;
layoutHome ( ) ;
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
uint8_t hash [ 32 ] ;
if ( ! msg - > has_identity | | cryptoIdentityFingerprint ( & ( msg - > identity ) , hash ) = = 0 ) {
fsm_sendFailure ( FailureType_Failure_Other , " Invalid identity " ) ;
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 ) ;
const HDNode * node = fsm_getDerivedNode ( address_n , 5 ) ;
if ( ! node ) return ;
2015-06-03 19:21:16 +00:00
uint8_t public_key [ 33 ] ; // copy public key to temporary buffer
memcpy ( public_key , node - > public_key , sizeof ( public_key ) ) ;
2015-02-20 19:22:05 +00:00
2015-06-03 19:21:16 +00:00
if ( msg - > has_ecdsa_curve_name ) {
const ecdsa_curve * curve = get_curve_by_name ( msg - > ecdsa_curve_name ) ;
if ( curve ) {
// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
ecdsa_get_public_key33 ( curve , node - > private_key , public_key ) ;
}
}
2015-07-04 21:34:26 +00:00
bool sign_ssh = msg - > identity . has_proto & & ( strcmp ( msg - > identity . proto , " ssh " ) = = 0 ) ;
2015-06-03 19:21:16 +00:00
int result = 0 ;
2015-07-04 21:45:57 +00:00
layoutProgressSwipe ( " Signing " , 0 ) ;
2015-07-04 21:34:26 +00:00
if ( sign_ssh ) { // SSH does not sign visual challenge
result = sshMessageSign ( msg - > challenge_hidden . bytes , msg - > challenge_hidden . size , node - > private_key , 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 ) ;
result = cryptoMessageSign ( digest , 64 , node - > private_key , resp - > signature . bytes ) ;
2015-06-03 19:21:16 +00:00
}
if ( result = = 0 ) {
if ( sign_ssh ) {
resp - > has_address = false ;
} else {
resp - > has_address = true ;
uint8_t addr_raw [ 21 ] ;
ecdsa_get_address_raw ( node - > public_key , 0x00 , addr_raw ) ; // hardcoded Bitcoin address type
base58_encode_check ( addr_raw , 21 , resp - > address , sizeof ( resp - > address ) ) ;
}
2015-02-20 19:22:05 +00:00
resp - > has_public_key = true ;
resp - > public_key . size = 33 ;
2015-06-03 19:21:16 +00:00
memcpy ( resp - > public_key . bytes , public_key , 33 ) ;
2015-02-20 19:22:05 +00:00
resp - > has_signature = true ;
resp - > signature . size = 65 ;
msg_write ( MessageType_MessageType_SignedIdentity , resp ) ;
} else {
fsm_sendFailure ( FailureType_Failure_Other , " Error signing identity " ) ;
}
layoutHome ( ) ;
}
2014-10-22 17:53:25 +00:00
void fsm_msgEncryptMessage ( EncryptMessage * msg )
{
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2014-10-22 17:53:25 +00:00
if ( ! msg - > has_pubkey ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No public key provided " ) ;
return ;
}
if ( ! msg - > has_message ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No message provided " ) ;
return ;
}
curve_point pubkey ;
2015-06-03 19:21:16 +00:00
if ( msg - > pubkey . size ! = 33 | | ecdsa_read_pubkey ( & secp256k1 , msg - > pubkey . bytes , & pubkey ) = = 0 ) {
2014-10-22 17:53:25 +00:00
fsm_sendFailure ( FailureType_Failure_SyntaxError , " Invalid public key provided " ) ;
return ;
}
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 ) ;
const CoinType * coin = 0 ;
2015-01-26 12:53:06 +00:00
const HDNode * node = 0 ;
2014-11-15 01:01:21 +00:00
uint8_t address_raw [ 21 ] ;
if ( signing ) {
coin = coinByName ( msg - > coin_name ) ;
if ( ! coin ) {
fsm_sendFailure ( FailureType_Failure_Other , " Invalid coin name " ) ;
return ;
}
2014-10-22 17:53:25 +00:00
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 12:53:06 +00:00
node = fsm_getDerivedNode ( msg - > address_n , msg - > address_n_count ) ;
2014-10-22 17:53:25 +00:00
if ( ! node ) return ;
2015-01-26 12:53:06 +00:00
uint8_t public_key [ 33 ] ;
2015-06-03 19:21:16 +00:00
ecdsa_get_public_key33 ( & secp256k1 , node - > private_key , public_key ) ;
2015-01-26 12:53:06 +00:00
ecdsa_get_address_raw ( public_key , 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 ) ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Encrypt message cancelled " ) ;
layoutHome ( ) ;
return ;
}
2014-12-21 17:58:56 +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 ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Error encrypting message " ) ;
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 )
{
2015-11-19 10:03:16 +00:00
if ( ! storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_NotInitialized , " Device not initialized " ) ;
return ;
}
2014-11-15 01:01:21 +00:00
if ( ! msg - > has_nonce ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No nonce provided " ) ;
return ;
}
2014-10-22 17:53:25 +00:00
if ( ! msg - > has_message ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No message provided " ) ;
return ;
}
2014-11-15 01:01:21 +00:00
if ( ! msg - > has_hmac ) {
fsm_sendFailure ( FailureType_Failure_SyntaxError , " No message hmac provided " ) ;
return ;
}
curve_point nonce_pubkey ;
2015-06-03 19:21:16 +00:00
if ( msg - > nonce . size ! = 33 | | ecdsa_read_pubkey ( & secp256k1 , msg - > nonce . bytes , & nonce_pubkey ) = = 0 ) {
2014-11-15 01:01:21 +00:00
fsm_sendFailure ( FailureType_Failure_SyntaxError , " Invalid nonce provided " ) ;
2014-10-22 17:53:25 +00:00
return ;
}
if ( ! protectPin ( true ) ) {
layoutHome ( ) ;
return ;
}
2015-01-26 12:53:06 +00:00
const HDNode * node = fsm_getDerivedNode ( 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
2014-12-21 17:58:56 +00:00
layoutProgressSwipe ( " Decrypting " , 0 ) ;
2014-11-15 01:01:21 +00:00
RESP_INIT ( DecryptedMessage ) ;
bool display_only = false ;
bool signing = false ;
uint8_t address_raw [ 21 ] ;
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 ) {
fsm_sendFailure ( FailureType_Failure_ActionCancelled , " Error decrypting message " ) ;
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 ( ) ;
}
2014-04-29 12:26:51 +00:00
void fsm_msgEstimateTxSize ( EstimateTxSize * msg )
{
RESP_INIT ( TxSize ) ;
resp - > has_tx_size = true ;
resp - > tx_size = transactionEstimateSize ( msg - > inputs_count , msg - > outputs_count ) ;
msg_write ( MessageType_MessageType_TxSize , resp ) ;
}
void fsm_msgRecoveryDevice ( RecoveryDevice * msg )
{
if ( storage_isInitialized ( ) ) {
fsm_sendFailure ( FailureType_Failure_UnexpectedMessage , " Device is already initialized. Use Wipe first. " ) ;
return ;
}
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 ,
msg - > has_enforce_wordlist ? msg - > enforce_wordlist : false
) ;
}
void fsm_msgWordAck ( WordAck * msg )
{
recovery_word ( msg - > word ) ;
}
# if DEBUG_LINK
void fsm_msgDebugLinkGetState ( DebugLinkGetState * msg )
{
( void ) msg ;
RESP_INIT ( DebugLinkState ) ;
2014-06-05 21:45:01 +00:00
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 ) {
resp - > has_pin = true ;
strlcpy ( resp - > pin , storage . pin , sizeof ( resp - > pin ) ) ;
}
resp - > has_matrix = true ;
strlcpy ( resp - > matrix , pinmatrix_get ( ) , sizeof ( resp - > matrix ) ) ;
resp - > has_reset_entropy = true ;
resp - > reset_entropy . size = reset_get_int_entropy ( resp - > reset_entropy . bytes ) ;
resp - > has_reset_word = true ;
strlcpy ( resp - > reset_word , reset_get_word ( ) , sizeof ( resp - > reset_word ) ) ;
resp - > has_recovery_fake_word = true ;
strlcpy ( resp - > recovery_fake_word , recovery_get_fake_word ( ) , sizeof ( resp - > recovery_fake_word ) ) ;
resp - > has_recovery_word_pos = true ;
resp - > recovery_word_pos = recovery_get_word_pos ( ) ;
if ( storage . has_mnemonic ) {
resp - > has_mnemonic = true ;
strlcpy ( resp - > mnemonic , storage . mnemonic , sizeof ( resp - > mnemonic ) ) ;
}
if ( storage . has_node ) {
resp - > has_node = true ;
memcpy ( & ( resp - > node ) , & ( storage . node ) , sizeof ( HDNode ) ) ;
}
resp - > has_passphrase_protection = true ;
resp - > passphrase_protection = storage . has_passphrase_protection & & storage . passphrase_protection ;
msg_debug_write ( MessageType_MessageType_DebugLinkState , resp ) ;
}
void fsm_msgDebugLinkStop ( DebugLinkStop * msg )
{
( void ) msg ;
}
# endif