diff --git a/Makefile b/Makefile index 08a0fda0..5680ce57 100644 --- a/Makefile +++ b/Makefile @@ -15,61 +15,20 @@ # limitations under the License. # **************************************************************************** -ifeq ($(BOLOS_SDK),) -$(error Environment variable BOLOS_SDK is not set) -endif -include $(BOLOS_SDK)/Makefile.defines - ######################################## # Mandatory configuration # ######################################## -# Name is defined later # Application version APPVERSION_M = 2 APPVERSION_N = 3 APPVERSION_P = 0 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -# Application source files -APP_SOURCE_PATH += src - -ICON_NANOS = icons/nanos_app_$(COIN).gif -ICON_NANOX = icons/nanox_app_$(COIN).gif -ICON_NANOSP = icons/nanox_app_$(COIN).gif -ICON_STAX = icons/stax_app_$(COIN).gif - -# Application allowed derivation curves. -CURVE_APP_LOAD_PARAMS = secp256k1 -# Application allowed derivation paths. -ifeq ($(COIN),$(filter $(COIN), hydra_testnet hydra)) -PATH_APP_LOAD_PARAMS = "44'/609'" -else -PATH_APP_LOAD_PARAMS = "" -endif - -HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 -HAVE_APPLICATION_FLAG_LIBRARY = 1 - -VARIANT_PARAM = COIN -VARIANT_VALUES = BOL - -# Temporary restriction until we have a Resistance Nano X icon -ifeq ($(TARGET_NAME),TARGET_NANOS) -VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium -else VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium -endif - -ENABLE_BLUETOOTH = 1 -ENABLE_NBGL_QRCODE = 1 -ENABLE_SWAP = 1 -ifeq ($(TARGET_NAME),TARGET_STAX) -DEFINES += COIN_ICON=C_$(COIN)_64px -DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap -endif +# Application source files +# There is no additional sources for bitcoin +#APP_SOURCE_PATH += src/ # simplify for tests ifndef COIN @@ -80,135 +39,450 @@ endif #DEBUG = 1 ifeq ($(COIN),bitcoin_testnet_legacy) -# Bitcoin testnet -DEFINES += BIP44_COIN_TYPE=1 BIP44_COIN_TYPE_2=1 COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=1 +BIP44_COIN_TYPE_2=1 +COIN_P2PKH_VERSION=111 +COIN_P2SH_VERSION=196 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOIN\" +COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_SHORT=\"TEST\" +COIN_NATIVE_SEGWIT_PREFIX=\"tb\" +COIN_KIND=COIN_KIND_BITCOIN_TESTNET +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Test Legacy" + else ifeq ($(COIN),bitcoin_legacy) -# Bitcoin mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +# Horizen +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=0 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOIN\" +COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_SHORT=\"BTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"bc\" +COIN_KIND=COIN_KIND_BITCOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Legacy" -#LIB and global pin and + else ifeq ($(COIN),bitcoin_cash) # Bitcoin cash # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=145 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COINID_NAME=\"BitcoinCash\" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 +BIP44_COIN_TYPE=145 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=0 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOINCASH\" +COIN_COINID_NAME=\"BitcoinCash\" +COIN_COINID_SHORT=\"BCH\" +COIN_KIND=COIN_KIND_BITCOIN_CASH +COIN_FORKID=0 APPNAME ="Bitcoin Cash" + else ifeq ($(COIN),bitcoin_gold) # Bitcoin Gold # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=156 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COINID_NAME=\"BitcoinGold\" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT COIN_FORKID=79 +BIP44_COIN_TYPE=156 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=23 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\\x20Gold\" +COIN_COINID_HEADER=\"BITCOINGOLD\" +COIN_COINID_NAME=\"BitcoinGold\" +COIN_COINID_SHORT=\"BTG\" +COIN_KIND=COIN_KIND_BITCOIN_GOLD +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +COIN_FORKID=79 APPNAME ="Bitcoin Gold" + else ifeq ($(COIN),litecoin) # Litecoin -DEFINES += BIP44_COIN_TYPE=2 BIP44_COIN_TYPE_2=2 COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" COIN_COINID_NAME=\"Litecoin\" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=2 +BIP44_COIN_TYPE_2=2 +COIN_P2PKH_VERSION=48 +COIN_P2SH_VERSION=50 +COIN_FAMILY=1 +COIN_COINID=\"Litecoin\" +COIN_COINID_HEADER=\"LITECOIN\" +COIN_COINID_NAME=\"Litecoin\" +COIN_COINID_SHORT=\"LTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" +COIN_KIND=COIN_KIND_LITECOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Litecoin" + else ifeq ($(COIN),dogecoin) # Doge -DEFINES += BIP44_COIN_TYPE=3 BIP44_COIN_TYPE_2=3 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" COIN_COINID_NAME=\"Dogecoin\" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE +BIP44_COIN_TYPE=3 +BIP44_COIN_TYPE_2=3 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=22 +COIN_FAMILY=1 +COIN_COINID=\"Dogecoin\" +COIN_COINID_HEADER=\"DOGECOIN\" +COIN_COINID_NAME=\"Dogecoin\" +COIN_COINID_SHORT=\"DOGE\" +COIN_KIND=COIN_KIND_DOGE APPNAME ="Dogecoin" + else ifeq ($(COIN),dash) # Dash -DEFINES += BIP44_COIN_TYPE=5 BIP44_COIN_TYPE_2=5 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" COIN_COINID_NAME=\"Dash\" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH +BIP44_COIN_TYPE=5 +BIP44_COIN_TYPE_2=5 +COIN_P2PKH_VERSION=76 +COIN_P2SH_VERSION=16 +COIN_FAMILY=1 +COIN_COINID=\"DarkCoin\" +COIN_COINID_HEADER=\"DASH\" +COIN_COINID_NAME=\"Dash\" +COIN_COINID_SHORT=\"DASH\" +COIN_KIND=COIN_KIND_DASH APPNAME ="Dash" + else ifeq ($(COIN),zcash) # Zcash (deprecated, code before the NU5 hard fork) $(error the zcash variant is deprecated and no longer functional since the NU5 hard fork) -DEFINES += BIP44_COIN_TYPE=133 BIP44_COIN_TYPE_2=133 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" COIN_COINID_HEADER=\"ZCASH\" COIN_COINID_NAME=\"Zcash\" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH +BIP44_COIN_TYPE=133 +BIP44_COIN_TYPE_2=133 +COIN_P2PKH_VERSION=7352 +COIN_P2SH_VERSION=7357 +COIN_FAMILY=1 +COIN_COINID=\"Zcash\" +COIN_COINID_HEADER=\"ZCASH\" +COIN_COINID_NAME=\"Zcash\" +COIN_COINID_SHORT=\"ZEC\" +COIN_KIND=COIN_KIND_ZCASH # Switch to Canopy over Heartwood -DEFINES += COIN_CONSENSUS_BRANCH_ID=0xE9FF75A6 +BRANCH_ID=0xE9FF75A6 APPNAME ="Zcash" + else ifeq ($(COIN),horizen) # Horizen -DEFINES += BIP44_COIN_TYPE=121 BIP44_COIN_TYPE_2=121 COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" COIN_COINID_NAME=\"Horizen\" COINID=$(COIN) COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN +BIP44_COIN_TYPE=121 +BIP44_COIN_TYPE_2=121 +COIN_P2PKH_VERSION=8329 +COIN_P2SH_VERSION=8342 +COIN_FAMILY=4 +COIN_COINID=\"Horizen\" +COIN_COINID_HEADER=\"HORIZEN\" +COIN_COINID_NAME=\"Horizen\" +COIN_COINID_SHORT=\"ZEN\" +COIN_KIND=COIN_KIND_HORIZEN APPNAME ="Horizen" + else ifeq ($(COIN),komodo) # Komodo -DEFINES += BIP44_COIN_TYPE=141 BIP44_COIN_TYPE_2=141 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" COIN_COINID_NAME=\"Komodo\" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO +BIP44_COIN_TYPE=141 +BIP44_COIN_TYPE_2=141 +COIN_P2PKH_VERSION=60 +COIN_P2SH_VERSION=85 +COIN_FAMILY=1 +COIN_COINID=\"Komodo\" +COIN_COINID_HEADER=\"KOMODO\" +COIN_COINID_NAME=\"Komodo\" +COIN_COINID_SHORT=\"KMD\" +COIN_KIND=COIN_KIND_KOMODO APPNAME ="Komodo" + else ifeq ($(COIN),stratis) # Stratis -DEFINES += BIP44_COIN_TYPE=105105 BIP44_COIN_TYPE_2=105105 COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" COIN_COINID_NAME=\"Stratis\" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=105105 +BIP44_COIN_TYPE_2=105105 +COIN_P2PKH_VERSION=75 +COIN_P2SH_VERSION=140 +COIN_FAMILY=2 +COIN_COINID=\"Stratis\" +COIN_COINID_HEADER=\"STRATIS\" +COIN_COINID_NAME=\"Stratis\" +COIN_COINID_SHORT=\"STRAX\" +COIN_KIND=COIN_KIND_STRATIS +COIN_FLAGS=FLAG_PEERCOIN_SUPPORT APPNAME ="Stratis" + else ifeq ($(COIN),xrhodium) #Xrhodium -DEFINES += BIP44_COIN_TYPE=10291 BIP44_COIN_TYPE_2=10291 COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" COIN_COINID_NAME=\"xRhodium\" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM +BIP44_COIN_TYPE=10291 +BIP44_COIN_TYPE_2=10291 +COIN_P2PKH_VERSION=61 +COIN_P2SH_VERSION=123 +COIN_FAMILY=1 +COIN_COINID=\"xrhodium\" +COIN_COINID_HEADER=\"XRHODIUM\" +COIN_COINID_NAME=\"xRhodium\" +COIN_COINID_SHORT=\"XRC\" +COIN_KIND=COIN_KIND_XRHODIUM APPNAME ="xRhodium" + else ifeq ($(COIN),peercoin) # Peercoin -DEFINES += BIP44_COIN_TYPE=6 BIP44_COIN_TYPE_2=6 COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" COIN_COINID_NAME=\"Peercoin\" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=6 +BIP44_COIN_TYPE_2=6 +COIN_P2PKH_VERSION=55 +COIN_P2SH_VERSION=117 +COIN_FAMILY=2 +COIN_COINID=\"PPCoin\" +COIN_COINID_HEADER=\"PEERCOIN\" +COIN_COINID_NAME=\"Peercoin\" +COIN_COINID_SHORT=\"PPC\" +COIN_KIND=COIN_KIND_PEERCOIN +COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Peercoin" + else ifeq ($(COIN),pivx) # PivX # 77 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=119 BIP44_COIN_TYPE_2=77 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" COIN_COINID_NAME=\"PivX\" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX +BIP44_COIN_TYPE=119 +BIP44_COIN_TYPE_2=77 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=13 +COIN_FAMILY=1 +COIN_COINID=\"DarkNet\" +COIN_COINID_HEADER=\"PIVX\" +COIN_COINID_NAME=\"PivX\" +COIN_COINID_SHORT=\"PIVX\" +COIN_KIND=COIN_KIND_PIVX APPNAME ="PivX" + else ifeq ($(COIN),stealth) # Stealth -DEFINES += BIP44_COIN_TYPE=125 BIP44_COIN_TYPE_2=125 COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" COIN_COINID_NAME=\"Stealth\" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=125 +BIP44_COIN_TYPE_2=125 +COIN_P2PKH_VERSION=62 +COIN_P2SH_VERSION=85 +COIN_FAMILY=4 +COIN_COINID=\"Stealth\" +COIN_COINID_HEADER=\"STEALTH\" +COIN_COINID_NAME=\"Stealth\" +COIN_COINID_SHORT=\"XST\" +COIN_KIND=COIN_KIND_STEALTH +COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Stealth" + else ifeq ($(COIN),viacoin) # Viacoin -DEFINES += BIP44_COIN_TYPE=14 BIP44_COIN_TYPE_2=14 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" COIN_COINID_NAME=\"Viacoin\" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=14 +BIP44_COIN_TYPE_2=14 +COIN_P2PKH_VERSION=71 +COIN_P2SH_VERSION=33 +COIN_FAMILY=1 +COIN_COINID=\"Viacoin\" +COIN_COINID_HEADER=\"VIACOIN\" +COIN_COINID_NAME=\"Viacoin\" +COIN_COINID_SHORT=\"VIA\" +COIN_KIND=COIN_KIND_VIACOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Viacoin" + else ifeq ($(COIN),vertcoin) # Vertcoin # 128 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=28 BIP44_COIN_TYPE_2=128 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" COIN_COINID_NAME=\"Vertcoin\" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=28 +BIP44_COIN_TYPE_2=128 +COIN_P2PKH_VERSION=71 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Vertcoin\" +COIN_COINID_HEADER=\"VERTCOIN\" +COIN_COINID_NAME=\"Vertcoin\" +COIN_COINID_SHORT=\"VTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" +COIN_KIND=COIN_KIND_VERTCOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Vertcoin" + else ifeq ($(COIN),digibyte) -DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COINID_NAME=\"DigiByte\" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=20 +BIP44_COIN_TYPE_2=20 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=63 +COIN_FAMILY=1 +COIN_COINID=\"DigiByte\" +COIN_COINID_HEADER=\"DIGIBYTE\" +COIN_COINID_NAME=\"DigiByte\" +COIN_COINID_SHORT=\"DGB\" +COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" +COIN_KIND=COIN_KIND_DIGIBYTE +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Digibyte" + else ifeq ($(COIN),qtum) $(error the qtum variant is deprecated and has been moved to its dedicated repo else ifeq ($(COIN),firo) -DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO +BIP44_COIN_TYPE=136 +BIP44_COIN_TYPE_2=136 +COIN_P2PKH_VERSION=82 +COIN_P2SH_VERSION=7 +COIN_FAMILY=1 +COIN_COINID=\"Zcoin\" +COIN_COINID_HEADER=\"FIRO\" +COIN_COINID_NAME=\"Firo\" +COIN_COINID_SHORT=\"FIRO\" +COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" + else ifeq ($(COIN),bitcoin_private) # Bitcoin Private # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId # Note : might need a third lock on ZClassic -DEFINES += BIP44_COIN_TYPE=183 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COINID_NAME=\"BPrivate\" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 +BIP44_COIN_TYPE=183 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=4901 +COIN_P2SH_VERSION=5039 +COIN_FAMILY=1 +COIN_COINID=\"BPrivate\" +COIN_COINID_HEADER=\"BITCOINPRIVATE\" +COIN_COINID_NAME=\"BPrivate\" +COIN_COINID_SHORT=\"BTCP\" +COIN_KIND=COIN_KIND_BITCOIN_PRIVATE +COIN_FORKID=42 APPNAME ="Bitcoin Private" + else ifeq ($(COIN),gamecredits) # GameCredits -DEFINES += BIP44_COIN_TYPE=101 BIP44_COIN_TYPE_2=101 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COINID_NAME=\"GameCredits\" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=101 +BIP44_COIN_TYPE_2=101 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=62 +COIN_FAMILY=1 +COIN_COINID=\"GameCredits\" +COIN_COINID_HEADER=\"GAMECREDITS\" +COIN_COINID_NAME=\"GameCredits\" +COIN_COINID_SHORT=\"GAME\" +COIN_KIND=COIN_KIND_GAMECREDITS +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="GameCredits" + else ifeq ($(COIN),zclassic) # ZClassic -DEFINES += BIP44_COIN_TYPE=147 BIP44_COIN_TYPE_2=147 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COINID_NAME=\"ZClassic\" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC +BIP44_COIN_TYPE=147 +BIP44_COIN_TYPE_2=147 +COIN_P2PKH_VERSION=7352 +COIN_P2SH_VERSION=7357 +COIN_FAMILY=1 +COIN_COINID=\"ZClassic\" +COIN_COINID_HEADER=\"ZCLASSIC\" +COIN_COINID_NAME=\"ZClassic\" +COIN_COINID_SHORT=\"ZCL\" +COIN_KIND=COIN_KIND_ZCLASSIC APPNAME ="ZClassic" + else ifeq ($(COIN),xsn) # XSN mainnet -DEFINES += BIP44_COIN_TYPE=384 BIP44_COIN_TYPE_2=384 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" COIN_COINID_NAME=\"XSN\" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=384 +BIP44_COIN_TYPE_2=384 +COIN_P2PKH_VERSION=76 +COIN_P2SH_VERSION=16 +COIN_FAMILY=1 +COIN_COINID=\"XSN\" +COIN_COINID_HEADER=\"XSN\" +COIN_COINID_NAME=\"XSN\" +COIN_COINID_SHORT=\"XSN\" +COIN_NATIVE_SEGWIT_PREFIX=\"xc\" +COIN_KIND=COIN_KIND_XSN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="XSN" + else ifeq ($(COIN),nix) # NIX -DEFINES += BIP44_COIN_TYPE=400 BIP44_COIN_TYPE_2=400 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" COIN_COINID_NAME=\"NIX\" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=400 +BIP44_COIN_TYPE_2=400 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=53 +COIN_FAMILY=1 +COIN_COINID=\"NIX\" +COIN_COINID_HEADER=\"NIX\" +COIN_COINID_NAME=\"NIX\" +COIN_COINID_SHORT=\"NIX\" +COIN_NATIVE_SEGWIT_PREFIX=\"nix\" +COIN_KIND=COIN_KIND_NIX +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="NIX" + else ifeq ($(COIN),lbry) # LBRY -DEFINES += BIP44_COIN_TYPE=140 BIP44_COIN_TYPE_2=140 COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" COIN_COINID_NAME=\"LBRY\" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY +BIP44_COIN_TYPE=140 +BIP44_COIN_TYPE_2=140 +COIN_P2PKH_VERSION=85 +COIN_P2SH_VERSION=122 +COIN_FAMILY=1 +COIN_COINID=\"LBRY\" +COIN_COINID_HEADER=\"LBRY\" +COIN_COINID_NAME=\"LBRY\" +COIN_COINID_SHORT=\"LBC\" +COIN_KIND=COIN_KIND_LBRY APPNAME ="LBRY" + else ifeq ($(COIN),resistance) # Resistance -DEFINES += BIP44_COIN_TYPE=356 BIP44_COIN_TYPE_2=356 COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE +BIP44_COIN_TYPE=356 +BIP44_COIN_TYPE_2=356 +COIN_P2PKH_VERSION=7063 +COIN_P2SH_VERSION=7068 +COIN_FAMILY=1 +COIN_COINID=\"Res\" +COIN_COINID_HEADER=\"RES\" +COIN_COINID_NAME=\"Res\" +COIN_COINID_SHORT=\"RES\" +COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" + else ifeq ($(COIN),ravencoin) # Ravencoin -DEFINES += BIP44_COIN_TYPE=175 BIP44_COIN_TYPE_2=175 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COINID_NAME=\"Ravencoin\" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN +BIP44_COIN_TYPE=175 +BIP44_COIN_TYPE_2=175 +COIN_P2PKH_VERSION=60 +COIN_P2SH_VERSION=122 +COIN_FAMILY=1 +COIN_COINID=\"Ravencoin\" +COIN_COINID_HEADER=\"RAVENCOIN\" +COIN_COINID_NAME=\"Ravencoin\" +COIN_COINID_SHORT=\"RVN\" +COIN_KIND=COIN_KIND_RAVENCOIN APPNAME ="Ravencoin" + else ifeq ($(COIN),hydra_testnet) # Hydra testnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=66 +COIN_P2SH_VERSION=128 +COIN_FAMILY=3 +COIN_COINID=\"Hydra\" +COIN_COINID_HEADER=\"HYDRA\" +COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_SHORT=\"HYDRA\" +COIN_NATIVE_SEGWIT_PREFIX=\"hc\" +COIN_KIND=COIN_KIND_HYDRA +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra Test" +APP_LOAD_PARAMS += --path "44'/609'" + else ifeq ($(COIN),hydra) # Hydra mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=40 +COIN_P2SH_VERSION=63 +COIN_FAMILY=3 +COIN_COINID=\"Hydra\" +COIN_COINID_HEADER=\"HYDRA\" +COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_SHORT=\"HYDRA\" +COIN_NATIVE_SEGWIT_PREFIX=\"hc\" +COIN_KIND=COIN_KIND_HYDRA +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra" -else -ifeq ($(filter clean,$(MAKECMDGOALS)),) +APP_LOAD_PARAMS += --path "44'/609'" + +else ifeq ($(filter clean,$(MAKECMDGOALS)),) $(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, bitcoin_private, firo, gamecredits, zclassic, xsn, nix, lbry, resistance, ravencoin, hydra, hydra_testnet, xrhodium) endif -endif -include $(BOLOS_SDK)/Makefile.standard_app +include lib-app-bitcoin/Makefile diff --git a/include/apdu_constants.h b/include/apdu_constants.h deleted file mode 100644 index 1aa127d3..00000000 --- a/include/apdu_constants.h +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef APDU_CONSTANTS_H - -#define APDU_CONSTANTS_H - -#define CLA 0xE0 -#define ADM_CLA 0xD0 -#define NFCPAYMENT_CLA 0xF0 - -#define INS_SETUP 0x20 -#define INS_VERIFY_PIN 0x22 -#define INS_GET_OPERATION_MODE 0x24 -#define INS_SET_OPERATION_MODE 0x26 -#define INS_SET_KEYBOARD_CFG 0x28 -#define INS_GET_WALLET_PUBLIC_KEY 0x40 -#define INS_GET_TRUSTED_INPUT 0x42 -#define INS_HASH_INPUT_START 0x44 -#define INS_HASH_INPUT_FINALIZE 0x46 -#define INS_HASH_SIGN 0x48 -#define INS_HASH_INPUT_FINALIZE_FULL 0x4A -#define INS_GET_INTERNAL_CHAIN_INDEX 0x4C -#define INS_SIGN_MESSAGE 0x4E -#define INS_GET_TRANSACTION_LIMIT 0xA0 -#define INS_SET_TRANSACTION_LIMIT 0xA2 -#define INS_IMPORT_PRIVATE_KEY 0xB0 -#define INS_GET_PUBLIC_KEY 0xB2 -#define INS_DERIVE_BIP32_KEY 0xB4 -#define INS_SIGNVERIFY_IMMEDIATE 0xB6 -#define INS_GET_RANDOM 0xC0 -#define INS_GET_ATTESTATION 0xC2 -#define INS_GET_FIRMWARE_VERSION 0xC4 -#define INS_COMPOSE_MOFN_ADDRESS 0xC6 -#define INS_GET_POS_SEED 0xCA -#define INS_DEBUG 0xD0 - -#define INS_ADM_INIT_KEYS 0x20 -#define INS_ADM_INIT_ATTESTATION 0x22 -#define INS_ADM_GET_UPDATE_ID 0x24 -#define INS_ADM_SET_KEYCARD_SEED 0x26 -#define INS_ADM_FIRMWARE_UPDATE 0x42 - -#define INS_SET_USER_KEYCARD 0x10 -#define INS_SETUP_SECURE_SCREEN 0x12 -#define INS_SET_ALTERNATE_COIN_VER 0x14 -#define INS_GET_COIN_VER 0x16 - -#define INS_STORE_TRUST_ROOT_BIP70 0x30 -#define INS_CREATE_CERTIFICATE_BIP70 0x32 -#define INS_CREATE_PAYMENT_REQ_BIP70 0x34 -#define INS_PROCESS_CERTIFICATE_BIP70 0x36 -#define INS_PARSE_PAYMENT_REQ_BIP70 0x38 -#define INS_HASH_INPUT_FINALIZE_BIP70 0x3A -#define INS_ADM_SET_ROOT_BIP70 0x28 -#define INS_ADM_SET_BIP39_SHUFFLE 0x2A - -#define INS_NFCPAYMENT_SET_CONFIG 0x20 -#define INS_NFCPAYMENT_GET_CONFIG 0x22 -#define INS_NFCPAYMENT_STORE_UTXO 0x40 -#define INS_NFCPAYMENT_STORE_SCRIPT 0x42 -#define INS_NFCPAYMENT_GET_UTXO 0x44 -#define INS_NFCPAYMENT_DELETE_UTXO 0x46 -#define INS_NFCPAYMENT_GET_PAYMENT_TX 0x50 -#define INS_NFCPAYMENT_GET_LAST_TX 0x52 -#define INS_NFCPAYMENT_CONFIRM_TX 0x54 -#define INS_NFCPAYMENT_CONFIRM_CHANGE 0x56 -#define INS_NFCPAYMENT_GET_LAST_STAT 0x58 -#define INS_NFCPAYMENT_GET_DATA 0xC0 - -#define SW_PIN_REMAINING_ATTEMPTS 0x63C0 -#define SW_INCORRECT_LENGTH 0x6700 -#define SW_COMMAND_INCOMPATIBLE_FILE_STRUCTURE 0x6981 -#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 -#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 -#define SW_INCORRECT_DATA 0x6A80 -#define SW_NOT_ENOUGH_MEMORY_SPACE 0x6A84 -#define SW_REFERENCED_DATA_NOT_FOUND 0x6A88 -#define SW_FILE_ALREADY_EXISTS 0x6A89 -#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A -#define SW_INCORRECT_P1_P2 0x6B00 -#define SW_INS_NOT_SUPPORTED 0x6D00 -#define SW_CLA_NOT_SUPPORTED 0x6E00 -#define SW_TECHNICAL_PROBLEM 0x6F00 -#define SW_OK 0x9000 -#define SW_MEMORY_PROBLEM 0x9240 -#define SW_NO_EF_SELECTED 0x9400 -#define SW_INVALID_OFFSET 0x9402 -#define SW_FILE_NOT_FOUND 0x9404 -#define SW_INCONSISTENT_FILE 0x9408 -#define SW_ALGORITHM_NOT_SUPPORTED 0x9484 -#define SW_INVALID_KCV 0x9485 -#define SW_CODE_NOT_INITIALIZED 0x9802 -#define SW_ACCESS_CONDITION_NOT_FULFILLED 0x9804 -#define SW_CONTRADICTION_SECRET_CODE_STATUS 0x9808 -#define SW_CONTRADICTION_INVALIDATION 0x9810 -#define SW_CODE_BLOCKED 0x9840 -#define SW_MAX_VALUE_REACHED 0x9850 -#define SW_GP_AUTH_FAILED 0x6300 -#define SW_LICENSING 0x6F42 -#define SW_HALTED 0x6FAA -#define SW_APP_HALTED SW_CONDITIONS_OF_USE_NOT_SATISFIED - -#define ISO_OFFSET_CLA 0x00 -#define ISO_OFFSET_INS 0x01 -#define ISO_OFFSET_P1 0x02 -#define ISO_OFFSET_P2 0x03 -#define ISO_OFFSET_LC 0x04 -#define ISO_OFFSET_CDATA 0x05 - -#define BITID_DERIVE 0xB11D -#define BITID_DERIVE_MULTIPLE 0xB11E - -#include "os.h" -#include "secure_value.h" - -void commit_operation_mode(secu8 operationMode); - -unsigned short apdu_get_wallet_public_key(void); -unsigned short apdu_get_trusted_input(void); -unsigned short apdu_hash_input_start(void); -unsigned short apdu_hash_input_finalize(void); -unsigned short apdu_hash_sign(void); -unsigned short apdu_hash_input_finalize_full(void); -unsigned short apdu_sign_message(void); - -unsigned short apdu_get_firmware_version(void); - -unsigned short apdu_get_coin_version(void); - -#endif diff --git a/include/config.h b/include/config.h deleted file mode 100644 index dac4e214..00000000 --- a/include/config.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef CONFIG_H - -#define CONFIG_H - -//#define DISABLE_SECURE_VALUE - -#define VERBOSE_6F - -#define os_crc cx_crc16 - -#endif diff --git a/include/filesystem.h b/include/filesystem.h deleted file mode 100644 index fe994dc9..00000000 --- a/include/filesystem.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef FS_H - -#define FS_H - -#include "os.h" -#include "config.h" -#include "context.h" -#include "filesystem_tx.h" - -enum supported_modes_e { - SUPPORTED_MODE_WALLET = 0x01, - SUPPORTED_MODE_RELAXED_WALLET = 0x02, - SUPPORTED_MODE_SERVER = 0x04, - SUPPORTED_MODE_DEVELOPER = 0x08 -}; - -enum family_e { - FAMILY_BITCOIN = 0x01, - FAMILY_PEERCOIN = 0x02, - FAMILY_STEALTH = 0x04 -}; - -struct config_s { - secu8 supportedModes; - secu8 operationMode; - unsigned char options; - // unsigned short payToAddressVersion; - // unsigned short payToScriptHashVersion; - // unsigned char coinFamily; - // /** Current Coin ID */ - // unsigned char coinId[MAX_COIN_ID]; - // /** Current short Coin ID */ - // unsigned char shortCoinId[MAX_SHORT_COIN_ID]; - // /** Current Coin ID length */ - // unsigned char coinIdLength; - // /** Current short Coin ID length */ - // unsigned char shortCoinIdLength; -}; -typedef struct config_s config_t; - -typedef struct backup_area_s { - config_t config; - uint8_t trustedinput_key[32]; -} backup_area_t; - -typedef struct storage_s { - unsigned char storageInitialized; - - unsigned char config_valid; - backup_area_t bkp; - - unsigned char fidoTransport; - - uint8_t pubKeyRequestRestriction; - -} storage_t; - -// the global nvram memory variable -#if 0 -extern storage_t N_real; -#define N_btchip (*(storage_t *)PIC(&N_real)) -#else -extern storage_t const N_real; -#define N_btchip (*(volatile storage_t *)PIC(&N_real)) -#endif - -void set_operation_mode(unsigned char operationMode); - -#endif diff --git a/include/secure_value.h b/include/secure_value.h deleted file mode 100644 index 8052084a..00000000 --- a/include/secure_value.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef SECURE_VALUE_H - -#define SECURE_VALUE_H - -#include "os.h" - -typedef unsigned short secu8; -typedef unsigned long int secu16; - -void sbSet(secu8 *target, unsigned char source); -void sbCheck(secu8 source); -void ssSet(secu16 *target, unsigned short source); -void ssCheck(secu16 source); - -#define SB_GET(x) ((unsigned char)x) - -#define SB_SET(x, y) sbSet(&x, y); - -#define SB_CHECK(x) sbCheck(x); - -#define SS_GET(x) ((unsigned short)x) - -#define SS_SET(x, y) ssSet(&x, y); - -#define SS_CHECK(x) ssCheck(x); - -#define SSEC_DEF(x) unsigned char x = 0; -#define SSEC_INC(x) x++; -#define SSEC_CHECK(x, value) \ - if (x != value) \ - reset(); - -#endif diff --git a/include/swap_lib_calls.h b/include/swap_lib_calls.h deleted file mode 100644 index 806e5f09..00000000 --- a/include/swap_lib_calls.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -/* This file is the shared API between Exchange and the apps started in Library mode for Exchange - * - * DO NOT MODIFY THIS FILE IN APPLICATIONS OTHER THAN EXCHANGE - * On modification in Exchange, forward the changes to all applications supporting Exchange - */ - -#include "stdbool.h" -#include "stdint.h" -#include "context.h" - -#define RUN_APPLICATION 1 - -#define SIGN_TRANSACTION 2 - -#define CHECK_ADDRESS 3 - -#define GET_PRINTABLE_AMOUNT 4 - -/* - * Amounts are stored as bytes, with a max size of 16 (see protobuf - * specifications). Max 16B integer is 340282366920938463463374607431768211455 - * in decimal, which is a 32-long char string. - * The printable amount also contains spaces, the ticker symbol (with variable - * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50 - * bytes total should be a fair maximum. - */ -#define MAX_PRINTABLE_AMOUNT_SIZE 50 - -// structure that should be send to specific coin application to get address -typedef struct check_address_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - // serialized path, segwit, version prefix, hash used, dictionary etc. - // fields and serialization format depends on specific coin app - uint8_t *address_parameters; - uint8_t address_parameters_length; - char *address_to_check; - char *extra_id_to_check; - // OUT - int result; -} check_address_parameters_t; - -// structure that should be send to specific coin application to get printable amount -typedef struct get_printable_amount_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - bool is_fee; - // OUT - char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; -} get_printable_amount_parameters_t; - -typedef struct create_transaction_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - uint8_t *fee_amount; - uint8_t fee_amount_length; - char *destination_address; - char *destination_address_extra_id; - // OUT - uint8_t result; -} create_transaction_parameters_t; - -typedef struct libargs_s { - unsigned int id; - unsigned int command; - altcoin_config_t *coin_config; - union { - check_address_parameters_t *check_address; - create_transaction_parameters_t *create_transaction; - get_printable_amount_parameters_t *get_printable_amount; - }; -} libargs_t; diff --git a/lib-app-bitcoin/Makefile b/lib-app-bitcoin/Makefile new file mode 100644 index 00000000..b19b0cc3 --- /dev/null +++ b/lib-app-bitcoin/Makefile @@ -0,0 +1,145 @@ +# **************************************************************************** +# Ledger App Bitcoin +# (c) 2023 Ledger SAS. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# **************************************************************************** + +ifeq ($(BOLOS_SDK),) +$(error Environment variable BOLOS_SDK is not set) +endif +include $(BOLOS_SDK)/Makefile.defines + +######################################## +# Mandatory configuration # +######################################## +# Name is defined later + +ifeq ($(APPVERSION_M),) +$(error APPVERSION_M must be defined) +endif +ifeq ($(APPVERSION_N),) +$(error APPVERSION_N must be defined) +endif +ifeq ($(APPVERSION_P),) +$(error APPVERSION_P must be defined) +endif + +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" + +APP_SOURCE_PATH += lib-app-bitcoin/ + +ICON_NANOS = icons/nanos_app_$(COIN).gif +ICON_NANOX = icons/nanox_app_$(COIN).gif +ICON_NANOSP = icons/nanox_app_$(COIN).gif +ICON_STAX = icons/stax_app_$(COIN).gif + +ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += COIN_ICON=C_$(COIN)_64px +DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap +endif + +# Application allowed derivation curves. +CURVE_APP_LOAD_PARAMS = secp256k1 + +# Application allowed derivation paths. +PATH_APP_LOAD_PARAMS = "" + +HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +HAVE_APPLICATION_FLAG_LIBRARY = 1 + +VARIANT_PARAM = COIN + +ENABLE_BLUETOOTH = 1 +ENABLE_NBGL_QRCODE = 1 +ENABLE_SWAP = 1 + +ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += COIN_ICON=C_$(COIN)_64px +DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap +endif + +ifndef BIP44_COIN_TYPE +$(error BIP44_COIN_TYPE must be defined) +endif + +ifndef BIP44_COIN_TYPE_2 +$(error BIP44_COIN_TYPE_2 must be defined) +endif + +ifndef COIN_P2PKH_VERSION +$(error COIN_P2PKH_VERSION must be defined) +endif + +ifndef COIN_P2SH_VERSION +$(error COIN_P2SH_VERSION must be defined) +endif + +ifndef COIN_FAMILY +$(error COIN_FAMILY must be defined) +endif + +ifndef COIN_COINID +$(error COIN_COINID must be defined) +endif + +ifndef COIN_COINID_HEADER +$(error COIN_COINID_HEADER must be defined) +endif + +ifndef COIN_COINID_NAME +$(error COIN_COINID_NAME must be defined) +endif + +ifndef COIN_COINID_SHORT +$(error COIN_COINID_SHORT must be defined) +endif + +ifndef COIN_NATIVE_SEGWIT_PREFIX +$(info COIN_NATIVE_SEGWIT_PREFIX automatically set to 0) +COIN_NATIVE_SEGWIT_PREFIX=0 +endif + +ifndef COIN_KIND +$(error COIN_KIND must be defined) +endif + +ifndef COIN_FLAGS +$(info COIN_FLAGS automatically set to 0) +COIN_FLAGS=0 +endif + +ifndef COIN_FORKID +$(info COIN_FORKID automatically set to 0) +COIN_FORKID=0 +endif + +ifeq ($(APPNAME),) +$(error APPNAME must be defined) +endif + +DEFINES +=BIP44_COIN_TYPE=$(BIP44_COIN_TYPE) +DEFINES +=BIP44_COIN_TYPE_2=$(BIP44_COIN_TYPE_2) +DEFINES +=COIN_P2PKH_VERSION=$(COIN_P2PKH_VERSION) +DEFINES +=COIN_P2SH_VERSION=$(COIN_P2SH_VERSION) +DEFINES +=COIN_FAMILY=$(COIN_FAMILY) +DEFINES +=COIN_COINID=$(COIN_COINID) +DEFINES +=COIN_COINID_HEADER=$(COIN_COINID_HEADER) +DEFINES +=COIN_COINID_NAME=$(COIN_COINID_NAME) +DEFINES +=COIN_COINID_SHORT=$(COIN_COINID_SHORT) +DEFINES +=COIN_NATIVE_SEGWIT_PREFIX=$(COIN_NATIVE_SEGWIT_PREFIX) +DEFINES +=COIN_KIND=$(COIN_KIND) +DEFINES +=COIN_FLAGS=$(COIN_FLAGS) +DEFINES +=COIN_FORKID=$(COIN_FORKID) + +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/lib-app-bitcoin/apdu/apdu_constants.h b/lib-app-bitcoin/apdu/apdu_constants.h new file mode 100644 index 00000000..f5265425 --- /dev/null +++ b/lib-app-bitcoin/apdu/apdu_constants.h @@ -0,0 +1,60 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#include "os.h" +#include "buffer.h" +#include "macros.h" + +#define CLA 0xE0 + +#define INS_GET_WALLET_PUBLIC_KEY 0x40 +#define INS_GET_TRUSTED_INPUT 0x42 +#define INS_HASH_INPUT_START 0x44 +#define INS_HASH_SIGN 0x48 +#define INS_HASH_INPUT_FINALIZE_FULL 0x4A +#define INS_SIGN_MESSAGE 0x4E +#define INS_GET_FIRMWARE_VERSION 0xC4 +#define INS_GET_COIN_VER 0x16 + +#define SW_INCORRECT_LENGTH 0x6700 +#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 +#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 +#define SW_INCORRECT_DATA 0x6A80 +#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A +#define SW_INCORRECT_P1_P2 0x6B00 +#define SW_INS_NOT_SUPPORTED 0x6D00 +#define SW_CLA_NOT_SUPPORTED 0x6E00 +#define SW_TECHNICAL_PROBLEM 0x6F00 +#define SW_TECHNICAL_PROBLEM_2 0x6F0F +#define SW_OK 0x9000 + +#define BITID_DERIVE 0xB11D +#define BITID_DERIVE_MULTIPLE 0xB11E + +#define ZCASH_USING_OVERWINTER 0x01 +#define ZCASH_USING_OVERWINTER_SAPLING 0x02 + +unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_firmware_version(void); +unsigned short handler_get_coin_version(void); + diff --git a/lib-app-bitcoin/apdu/dispatcher.c b/lib-app-bitcoin/apdu/dispatcher.c new file mode 100644 index 00000000..7e2c6c0e --- /dev/null +++ b/lib-app-bitcoin/apdu/dispatcher.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * Ledger App Boilerplate. + * (c) 2020 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#include +#include + +#include "buffer.h" +#include "io.h" +#include "ledger_assert.h" + +#include "dispatcher.h" +#include "apdu_constants.h" + +int apdu_dispatcher(const command_t *cmd) { + LEDGER_ASSERT(cmd != NULL, "NULL cmd"); + + if (cmd->cla != CLA) { + return io_send_sw(SW_CLA_NOT_SUPPORTED); + } + + buffer_t buf = {0}; + + switch (cmd->ins) { + case INS_GET_WALLET_PUBLIC_KEY: + PRINTF("Get wallet public key\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_wallet_public_key(&buf, cmd->p1, cmd->p2); + + case INS_GET_TRUSTED_INPUT: + PRINTF("Get trusted input\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_trusted_input(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_START: + PRINTF("Hash input start\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_start(&buf, cmd->p1, cmd->p2); + + case INS_HASH_SIGN: + PRINTF("Hash sign\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_sign(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_FINALIZE_FULL: + PRINTF("Hash input finalize full\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_finalize_full(&buf, cmd->p1, cmd->p2); + + case INS_SIGN_MESSAGE: + PRINTF("Sign message\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_sign_message(&buf, cmd->p1, cmd->p2); + + case INS_GET_FIRMWARE_VERSION: + PRINTF("Get firmware version\n"); + + return handler_get_firmware_version(); + + case INS_GET_COIN_VER: + PRINTF("Get coin version\n"); + + return handler_get_coin_version(); + + default: + PRINTF("Instruction not supported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } +} diff --git a/lib-app-bitcoin/apdu/dispatcher.h b/lib-app-bitcoin/apdu/dispatcher.h new file mode 100644 index 00000000..36e1f60c --- /dev/null +++ b/lib-app-bitcoin/apdu/dispatcher.h @@ -0,0 +1,14 @@ +#pragma once + +#include "parser.h" + +/** + * Dispatch APDU command received to the right handler. + * + * @param[in] cmd + * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). + * + * @return zero or positive integer if success, negative integer otherwise. + * + */ +int apdu_dispatcher(const command_t *cmd); diff --git a/lib-app-bitcoin/app_main.c b/lib-app-bitcoin/app_main.c new file mode 100644 index 00000000..d25e5be5 --- /dev/null +++ b/lib-app-bitcoin/app_main.c @@ -0,0 +1,72 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "swap.h" +#include "io.h" + +#include "context.h" +#include "apdu_constants.h" +#include "dispatcher.h" +#include "ui.h" + + +void app_main(void) { + // Structured APDU command + command_t cmd; + + io_init(); + + if (!G_called_from_swap) { + ui_idle_flow(); + } + + context_init(); + + for (;;) { + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; + + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; + } + + // Parse APDU command from G_io_apdu_buffer + if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { + PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); + io_send_sw(SW_INCORRECT_LENGTH); + continue; + } + + PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", + cmd.cla, + cmd.ins, + cmd.p1, + cmd.p2, + cmd.lc, + cmd.lc, + cmd.data); + + context_D.outLength = 0; + + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } + } +} diff --git a/src/context.c b/lib-app-bitcoin/context.c similarity index 93% rename from src/context.c rename to lib-app-bitcoin/context.c index 3ff49151..8fff1710 100644 --- a/src/context.c +++ b/lib-app-bitcoin/context.c @@ -15,10 +15,11 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "swap.h" +#include "context.h" +#include "filesystem.h" -void autosetup(void); +context_t context_D; +storage_t const N_real; /** * Initialize the application context on boot @@ -27,7 +28,6 @@ void context_init() { PRINTF("Context init\n"); PRINTF("Backup size %d\n", sizeof(N_btchip.bkp)); memset(&context_D, 0, sizeof(context_D)); - G_called_from_swap = 0; context_D.currentOutputOffset = 0; context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; memset(context_D.totalOutputAmount, 0, @@ -35,3 +35,4 @@ void context_init() { context_D.changeOutputFound = 0; context_D.segwitWarningSeen = 0; } + diff --git a/include/context.h b/lib-app-bitcoin/context.h similarity index 91% rename from include/context.h rename to lib-app-bitcoin/context.h index 4f23f4db..0b000e00 100644 --- a/include/context.h +++ b/lib-app-bitcoin/context.h @@ -15,13 +15,10 @@ * limitations under the License. ********************************************************************************/ -#ifndef CONTEXT_H - -#define CONTEXT_H +#pragma once #include "os.h" #include "cx.h" -#include "secure_value.h" #include "filesystem_tx.h" #ifdef HAVE_NBGL #include "nbgl_types.h" @@ -33,27 +30,6 @@ #define MAX_SHORT_COIN_ID 5 #define MAGIC_TRUSTED_INPUT 0x32 -#define MAGIC_DEV_KEY 0x01 - -#define ZCASH_USING_OVERWINTER 0x01 -#define ZCASH_USING_OVERWINTER_SAPLING 0x02 - -enum modes_e { - MODE_ISSUER = 0x00, - MODE_SETUP_NEEDED = 0xff, - MODE_WALLET = 0x01, - MODE_RELAXED_WALLET = 0x02, - MODE_SERVER = 0x04, - MODE_DEVELOPER = 0x08, -}; - -enum options_e { - OPTION_UNCOMPRESSED_KEYS = 0x01, - OPTION_DETERMINISTIC_SIGNATURE = 0x02, - OPTION_FREE_SIGHASHTYPE = 0x04, - OPTION_SKIP_2FA_P2SH = 0x08, - OPTION_ALLOW_ARBITRARY_CHANGE = 0x10 -}; /** * Current state of an untrusted transaction hashing @@ -156,8 +132,6 @@ struct tmp_output_s { typedef struct tmp_output_s tmp_output_t; struct context_s { - /** Flag if dongle has been halted */ - secu8 halted; /** Index of the output to convert into a trusted input in a transaction */ unsigned long int trustedInputIndex; /** (Integrity protected) transaction context */ @@ -200,9 +174,6 @@ struct context_s { /** Length of the outgoing command */ unsigned short outLength; - /** IO flags to reply with at the end of an APDU handler */ - unsigned char io_flags; - /** Status Word of the response */ unsigned short sw; @@ -284,4 +255,4 @@ typedef enum coin_kind_e { void context_init(void); -#endif +extern context_t context_D; diff --git a/lib-app-bitcoin/customizable_helpers.c b/lib-app-bitcoin/customizable_helpers.c new file mode 100644 index 00000000..78e70a39 --- /dev/null +++ b/lib-app-bitcoin/customizable_helpers.c @@ -0,0 +1,151 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "macros.h" + +#include "context.h" +#include "customizable_helpers.h" + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { + 0x19, 0x76, 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { + 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { + 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL + +const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { + 0x3D, 0xA9, + 0x14}; // script length, OP_HASH160, address length + +const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { + 0x87, // OP_EQUAL + 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, + 0x1C, 0x03, 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, + 0xBA, 0x97, 0xF0, 0xE3, 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, + 0x00, 0x00, 0x00, // ParamHash + 0x03, // Push 3 bytes to stack to make ParamHeight line up properly + 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped + 0xB4}; // OP_CHECKBLOCKATHEIGHT + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; + +const unsigned char ZEN_OUTPUT_SCRIPT_PRE[] = { + 0x3F, 0x76, 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { + 0x88, 0xAC, // OP_EQUALVERIFY, OP_CHECKSIG + 0x20, 0x9e, 0xc9, 0x84, 0x5a, 0xcb, 0x02, 0xfa, 0xb2, 0x4e, 0x1c, 0x03, + 0x68, 0xb3, 0xb5, 0x17, 0xc1, 0xa4, 0x48, 0x8f, 0xba, 0x97, 0xf0, 0xe3, + 0x45, 0x9a, 0xc0, 0x53, 0xea, 0x01, 0x00, 0x00, 0x00, // ParamHash + 0x03, // Push 3 bytes to stack to make ParamHeight line up properly + 0xc0, 0x1f, 0x02, // ParamHeight (139200) -> hex -> endianness swapped + 0xb4 // OP_CHECKBLOCKATHEIGHT +}; // BIP0115 Replay Protection + +WEAK unsigned char output_script_is_regular(unsigned char *buffer) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; + } + } + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, + sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, + ZEN_OUTPUT_SCRIPT_POST, + sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } + } + + return 0; +} + +WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } + } + return 0; +} + +WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; + } + } + return 0; +} + +WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); + } + else { + return (buffer[1] == 0x6A); + } +} + +WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, + size_t size, + unsigned char value) { + return (!output_script_is_regular(buffer) && + !output_script_is_p2sh(buffer) && + !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && + (buffer[0] < size) && + (buffer[buffer[0]] == value)); +} + +WEAK unsigned char output_script_is_op_create(unsigned char *buffer, + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC1); +} + +WEAK unsigned char output_script_is_op_call(unsigned char *buffer, + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC2); +} + diff --git a/include/bcd.h b/lib-app-bitcoin/customizable_helpers.h similarity index 58% rename from include/bcd.h rename to lib-app-bitcoin/customizable_helpers.h index 42eb41ff..ab7ac1c9 100644 --- a/include/bcd.h +++ b/lib-app-bitcoin/customizable_helpers.h @@ -15,14 +15,17 @@ * limitations under the License. ********************************************************************************/ -#ifndef BCD_H +#pragma once -#define BCD_H +#include "os.h" +#include "cx.h" -unsigned char -convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out); +unsigned char output_script_is_regular(unsigned char *buffer); +unsigned char output_script_is_p2sh(unsigned char *buffer); +unsigned char output_script_is_op_return(unsigned char *buffer); +unsigned char output_script_is_native_witness(unsigned char *buffer); +unsigned char output_script_is_op_create(unsigned char *buffer, + size_t size); +unsigned char output_script_is_op_call(unsigned char *buffer, + size_t size); -unsigned char -convert_hex_amount_to_displayable(unsigned char *amount); - -#endif diff --git a/lib-app-bitcoin/customizable_ui.c b/lib-app-bitcoin/customizable_ui.c new file mode 100644 index 00000000..fe81b443 --- /dev/null +++ b/lib-app-bitcoin/customizable_ui.c @@ -0,0 +1,117 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "customizable_ui.h" +#include "customizable_helpers.h" +#include "helpers.h" +#include "context.h" +#include "display_variables.h" +#include "segwit_addr.h" +#include "cashaddr.h" +#include "be_operations.h" +#include "display_utils.h" +#include "read.h" + + +WEAK void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { + if (output_script_is_op_return(script)) { + strncpy(out, "OP_RETURN", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_create(script, script_size)) { + strncpy(out, "OP_CREATE", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_call(script, script_size)) { + strncpy(out, "OP_CALL", out_size); + return; + } + if (output_script_is_native_witness(script)) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + segwit_addr_encode( + out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, + script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, + script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); + } + return; + } + unsigned char versionSize; + unsigned char address[22]; + unsigned short textSize; + int addressOffset = 3; + unsigned short version = COIN_P2SH_VERSION; + + if (output_script_is_regular(script)) { + addressOffset = 4; + version = COIN_P2PKH_VERSION; + } + + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, script + addressOffset, 20); + + // Prepare address + if (context_D.usingCashAddr) { + cashaddr_encode( + address + versionSize, 20, (uint8_t *)out, out_size, + (version == COIN_P2SH_VERSION + ? CASHADDR_P2SH + : CASHADDR_P2PKH)); + } else { + textSize = public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)out, + out_size, version, 1); + out[textSize] = '\0'; + } +} + +WEAK uint8_t prepare_fees(void) { + if (context_D.transactionContext.relaxed) { + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + vars.tmp.feesAmount[7] = '\0'; + } else { + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); + if (borrow && COIN_KIND == COIN_KIND_KOMODO) { + memmove(vars.tmp.feesAmount, "REWARD", 6); + vars.tmp.feesAmount[6] = '\0'; + } + else { + if (borrow) { + PRINTF("Error : Fees not consistent"); + goto error; + } + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)read_u64_be(fees, 0), // Cast prevents weird compilo bug + vars.tmp.feesAmount); + } + } + return 1; +error: + return 0; +} diff --git a/include/ecc.h b/lib-app-bitcoin/customizable_ui.h similarity index 82% rename from include/ecc.h rename to lib-app-bitcoin/customizable_ui.h index 4a07074d..75649c2b 100644 --- a/include/ecc.h +++ b/lib-app-bitcoin/customizable_ui.h @@ -14,13 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ - -#ifndef ECC_H - -#define ECC_H - +#pragma once #include "os.h" +#include "macros.h" -void compress_public_key_value(unsigned char *value); +void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size); -#endif +uint8_t prepare_fees(void); diff --git a/lib-app-bitcoin/display_utils.c b/lib-app-bitcoin/display_utils.c new file mode 100644 index 00000000..4bfae3f5 --- /dev/null +++ b/lib-app-bitcoin/display_utils.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include "ledger_assert.h" +#include "read.h" +#include "filesystem_tx.h" + +#include "./display_utils.h" + +// Division and modulus operators over uint64_t causes the inclusion of the __udivmoddi4 and other +// library functions that occupy more than 400 bytes. Since performance is not critical and division +// by 10 is sufficient, we avoid it with a binary search instead. +static uint64_t div10(uint64_t n) { + if (n < 10) return 0; // special case needed to make sure that n - 10 is safe + + // Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of overflow + uint64_t low = 0; + uint64_t high = UINT64_MAX / 10; + + while (true) { + uint64_t mid = (low + high) / 2; + + // the result equals mid if and only if mid * 10 <= n < mid * 10 + 10 + // care is taken to make sure overflows and underflows are impossible + if (mid * 10 > n - 10 && n >= mid * 10) { + return mid; + } else if (n < mid * 10) { + high = mid - 1; + } else /* n >= 10 * mid + 10 */ { + low = mid + 1; + } + } +} + +static uint64_t div100000000(uint64_t n) { + uint64_t res = n; + for (int i = 0; i < 8; i++) res = div10(res); + return res; +} + +static size_t n_digits(uint64_t number) { + size_t count = 0; + do { + count++; + + // HACK: avoid __udivmoddi4 + // number /= 10; + + number = div10(number); + } while (number != 0); + return count; +} + +void format_sats_amount(const char *coin_name, + uint64_t amount, + char out[static MAX_AMOUNT_LENGTH + 1]) { + size_t coin_name_len = strlen(coin_name); + strncpy(out, coin_name, MAX_AMOUNT_LENGTH + 1); + out[coin_name_len] = ' '; + + char *amount_str = out + coin_name_len + 1; + + // HACK: avoid __udivmoddi4 + // uint64_t integral_part = amount / 100000000; + // uint32_t fractional_part = (uint32_t) (amount % 100000000); + uint64_t integral_part = div100000000(amount); + uint32_t fractional_part = (uint32_t) (amount - integral_part * 100000000); + + // format the integral part, starting from the least significant digit + size_t integral_part_digit_count = n_digits(integral_part); + for (unsigned int i = 0; i < integral_part_digit_count; i++) { + // HACK: avoid __udivmoddi4 + // amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % 10); + // integral_part /= 10; + + uint64_t tmp_quotient = div10(integral_part); + char tmp_remainder = (char) (integral_part - 10 * tmp_quotient); + amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder; + integral_part = tmp_quotient; + } + + if (fractional_part == 0) { + amount_str[integral_part_digit_count] = '\0'; + } else { + // format the fractional part (exactly 8 digits, possibly with trailing zeros) + amount_str[integral_part_digit_count] = '.'; + char *fract_part_str = amount_str + integral_part_digit_count + 1; + snprintf(fract_part_str, 8 + 1, "%08u", fractional_part); + + // drop trailing zeros + for (int i = 7; i > 0 && fract_part_str[i] == '0'; i--) { + fract_part_str[i] = '\0'; + } + } +} + +unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len) { + + unsigned char bip32PathLength; + unsigned char i, offset; + unsigned int current_level; + bool hardened; + + bip32PathLength = bip32Path[0]; + + LEDGER_ASSERT(bip32PathLength <= MAX_BIP32_PATH, "Wrong path len: %d", bip32PathLength); + + bip32Path++; + out[0] = ' '; + offset=1; + for (i = 0; i < bip32PathLength; i++) { + current_level = read_u32_be(bip32Path, 0); + hardened = (bool)(current_level & 0x80000000); + if(hardened) { + //remove hardening flag + current_level ^= 0x80000000; + } + bip32Path += 4; + snprintf(out+offset, max_out_len-offset, "%u", current_level); + offset = strnlen(out, max_out_len); + LEDGER_ASSERT(offset < max_out_len - 2, "OVERFLOW"); + if(hardened) out[offset++] = '\''; + + out[offset++] = '/'; + out[offset] = '\0'; + } + // remove last '/' + out[offset-1] = '\0'; + + return offset -1; +} + diff --git a/lib-app-bitcoin/display_utils.h b/lib-app-bitcoin/display_utils.h new file mode 100644 index 00000000..f5f28ba7 --- /dev/null +++ b/lib-app-bitcoin/display_utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +// up to 5 chars for ticker, 1 space, up to 20 digits (20 = digits of 2^64), + 1 decimal separator +#define MAX_AMOUNT_LENGTH (5 + 1 + 20 + 1) + +/** + * Converts a 64-bits unsigned integer into a decimal rapresentation, where the `amount` is a + * multiple of 1/100_000_000th. Trailing decimal zeros are not appended (and no decimal point is + * present if the `amount` is a multiple of 100_000_000). The resulting string is prefixed with a + * ticker name (up to 5 characters long), followed by a space. + * + * @param coin_name a zero-terminated ticker name, at most 5 characterso long (not including the + * terminating 0) + * @param amount the amount to format + * @param out the output array which must be at least MAX_AMOUNT_LENGTH + 1 bytes long + */ +void format_sats_amount(const char *coin_name, + uint64_t amount, + char out[static MAX_AMOUNT_LENGTH + 1]); + +unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len); + diff --git a/src/display_variables.c b/lib-app-bitcoin/display_variables.c similarity index 100% rename from src/display_variables.c rename to lib-app-bitcoin/display_variables.c diff --git a/src/public_ram_variables.h b/lib-app-bitcoin/filesystem.h similarity index 65% rename from src/public_ram_variables.h rename to lib-app-bitcoin/filesystem.h index 3251c5da..2dcf16f2 100644 --- a/src/public_ram_variables.h +++ b/lib-app-bitcoin/filesystem.h @@ -15,14 +15,26 @@ * limitations under the License. ********************************************************************************/ -#ifndef _PUBLIC_RAM_VARIABLES_H_ -#define _PUBLIC_RAM_VARIABLES_H_ +#pragma once -#include "config.h" - -#include "secure_value.h" +#include "os.h" #include "context.h" +#include "filesystem_tx.h" + +enum family_e { + FAMILY_BITCOIN = 0x01, + FAMILY_PEERCOIN = 0x02, + FAMILY_STEALTH = 0x04 +}; + +typedef struct backup_area_s { + uint8_t trustedinput_key[32]; +} backup_area_t; -extern context_t context_D; +typedef struct storage_s { + backup_area_t bkp; +} storage_t; -#endif /* _PUBLIC_RAM_VARIABLES_H_ */ +// the global nvram memory variable +extern storage_t const N_real; +#define N_btchip (*(volatile storage_t *)PIC(&N_real)) diff --git a/include/filesystem_tx.h b/lib-app-bitcoin/filesystem_tx.h similarity index 100% rename from include/filesystem_tx.h rename to lib-app-bitcoin/filesystem_tx.h diff --git a/src/apdu_get_coin_version.c b/lib-app-bitcoin/handler/get_coin_version.c similarity index 78% rename from src/apdu_get_coin_version.c rename to lib-app-bitcoin/handler/get_coin_version.c index 97e0ac72..e47f939c 100644 --- a/src/apdu_get_coin_version.c +++ b/lib-app-bitcoin/handler/get_coin_version.c @@ -15,19 +15,21 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "apdu_constants.h" +#include "io.h" +#include "write.h" -#define P1_VERSION_ONLY 0x00 -#define P1_VERSION_COINID 0x01 +#include "context.h" +#include "apdu_constants.h" -unsigned short apdu_get_coin_version() { +WEAK unsigned short handler_get_coin_version(void) { uint8_t offset = 0; - G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION >> 8; - G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION; - G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION >> 8; - G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION; + write_u16_be(G_io_apdu_buffer, offset, COIN_P2PKH_VERSION); + offset += 2; + + write_u16_be(G_io_apdu_buffer, offset, COIN_P2SH_VERSION); + offset += 2; + G_io_apdu_buffer[offset++] = COIN_FAMILY; G_io_apdu_buffer[offset++] = strlen(COIN_COINID); memmove(G_io_apdu_buffer + offset, COIN_COINID, @@ -39,5 +41,5 @@ unsigned short apdu_get_coin_version() { offset += strlen(COIN_COINID_SHORT); context_D.outLength = offset; - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } diff --git a/src/apdu_get_firmware_version.c b/lib-app-bitcoin/handler/get_firmware_version.c similarity index 54% rename from src/apdu_get_firmware_version.c rename to lib-app-bitcoin/handler/get_firmware_version.c index b2b90954..d3f100d1 100644 --- a/src/apdu_get_firmware_version.c +++ b/lib-app-bitcoin/handler/get_firmware_version.c @@ -14,52 +14,37 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ +#include "io.h" -#include "internal.h" +#include "context.h" #include "apdu_constants.h" -#define FEATURES_COMPRESSED_KEYS 0x01 #define FEATURES_SELF_SCREEN_BUTTONS 0x02 -#define FEATURES_EXTERNAL_SCREEN_BUTTONS 0x04 #define FEATURES_NFC 0x08 #define FEATURES_BLE 0x10 -#define FEATURES_TEE 0x20 #define MODE_SETUP 0x01 #define MODE_OPERATION 0x02 +#define FEATURES (FEATURES_NFC | FEATURES_BLE | FEATURES_SELF_SCREEN_BUTTONS) +#define MODE (MODE_SETUP | MODE_OPERATION) + #define ARCH_ID 0x30 -// Java Card is 0x60 #define TCS_LOADER_PATCH_VERSION 0 -void get_firmware_version(unsigned char *buffer) { - buffer[0] = ARCH_ID; - buffer[1] = MAJOR_VERSION; - buffer[2] = MINOR_VERSION; - buffer[3] = PATCH_VERSION; - buffer[4] = 1; - buffer[5] = TCS_LOADER_PATCH_VERSION; -} - -unsigned short apdu_get_firmware_version() { - G_io_apdu_buffer[0] = - (((N_btchip.bkp.config.options & OPTION_UNCOMPRESSED_KEYS) != 0) - ? 0x00 - : 0x01); - - G_io_apdu_buffer[0] |= FEATURES_NFC; - G_io_apdu_buffer[0] |= FEATURES_BLE; - - G_io_apdu_buffer[0] |= FEATURES_SELF_SCREEN_BUTTONS; - - get_firmware_version(G_io_apdu_buffer + 1); +WEAK unsigned short handler_get_firmware_version() { - G_io_apdu_buffer[7] = 0x00; - G_io_apdu_buffer[7] |= MODE_SETUP; - G_io_apdu_buffer[7] |= MODE_OPERATION; + G_io_apdu_buffer[0] = FEATURES; + G_io_apdu_buffer[1] = ARCH_ID; + G_io_apdu_buffer[2] = MAJOR_VERSION; + G_io_apdu_buffer[3] = MINOR_VERSION; + G_io_apdu_buffer[4] = PATCH_VERSION; + G_io_apdu_buffer[5] = 1; + G_io_apdu_buffer[6] = TCS_LOADER_PATCH_VERSION; + G_io_apdu_buffer[7] = MODE; context_D.outLength = 0x08; - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } diff --git a/src/apdu_get_trusted_input.c b/lib-app-bitcoin/handler/get_trusted_input.c similarity index 77% rename from src/apdu_get_trusted_input.c rename to lib-app-bitcoin/handler/get_trusted_input.c index 48fa119a..6c07bb96 100644 --- a/src/apdu_get_trusted_input.c +++ b/lib-app-bitcoin/handler/get_trusted_input.c @@ -14,24 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" #include "lib_standard_app/read.h" #include "lib_standard_app/write.h" +#include "io.h" + +#include "context.h" +#include "filesystem.h" +#include "transaction.h" +#include "apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 -unsigned short apdu_get_trusted_input() { - unsigned char apduLength; +WEAK unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned char dataOffset = 0; - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { + if (p1 == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize context_D.transactionTargetInput = - read_u32_be(G_io_apdu_buffer, ISO_OFFSET_CDATA); + read_u32_be(buffer->ptr, 0); context_D.transactionContext.transactionState = TRANSACTION_NONE; context_D.trustedInputProcessed = 0; @@ -40,16 +41,16 @@ unsigned short apdu_get_trusted_input() { context_D.transactionHashOption = TRANSACTION_HASH_FULL; context_D.usingSegwit = 0; context_D.usingOverwinter = 0; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { - return SW_INCORRECT_P1_P2; + } else if (p1 != GET_TRUSTED_INPUT_P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); } - if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { - return SW_INCORRECT_P1_P2; + if (p2 != 0x00) { + return io_send_sw(SW_INCORRECT_P1_P2); } - context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; - context_D.transactionDataRemaining = apduLength - dataOffset; + + context_D.transactionBufferPointer = (uint8_t* ) buffer->ptr + dataOffset; + context_D.transactionDataRemaining = buffer->size - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); @@ -60,12 +61,12 @@ unsigned short apdu_get_trusted_input() { TRANSACTION_NONE; if (!context_D.trustedInputProcessed) { // Output was not found - return SW_INCORRECT_DATA; + return io_send_sw(SW_INCORRECT_DATA); } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { - return SW_TECHNICAL_PROBLEM; + return io_send_sw(SW_TECHNICAL_PROBLEM); } // Otherwise prepare @@ -84,5 +85,5 @@ unsigned short apdu_get_trusted_input() { TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32); context_D.outLength = TRUSTED_INPUT_TOTAL_SIZE; } - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } diff --git a/src/apdu_get_wallet_public_key.c b/lib-app-bitcoin/handler/get_wallet_public_key.c similarity index 64% rename from src/apdu_get_wallet_public_key.c rename to lib-app-bitcoin/handler/get_wallet_public_key.c index 53baced4..da1c32ba 100644 --- a/src/apdu_get_wallet_public_key.c +++ b/lib-app-bitcoin/handler/get_wallet_public_key.c @@ -15,18 +15,28 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" +#include "context.h" +#include "helpers.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "segwit_addr.h" #include "cashaddr.h" -#include "apdu_get_wallet_public_key.h" #include "lib_standard_app/read.h" #include "swap.h" +#include "io.h" -int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 +#define P1_REQUEST_TOKEN 0x02 + +#define P2_LEGACY 0x00 +#define P2_SEGWIT 0x01 +#define P2_NATIVE_SEGWIT 0x02 +#define P2_CASHADDR 0x03 + +static int get_public_key_chain_code(const unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { uint8_t public_key[65]; int keyLength = 0; @@ -42,59 +52,57 @@ int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, unsign return keyLength; } -unsigned short apdu_get_wallet_public_key() { +WEAK unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned char keyLength; unsigned char chainCode[32]; uint8_t is_derivation_path_unusual = 0; - bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool segwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_SEGWIT); - bool nativeSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NATIVE_SEGWIT); - bool cashAddr = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_CASHADDR); + bool display = (p1 == P1_DISPLAY); + bool segwit = (p2 == P2_SEGWIT); + bool nativeSegwit = (p2 == P2_NATIVE_SEGWIT); + bool cashAddr = (p2 == P2_CASHADDR); + if (display && G_called_from_swap) { - return SW_INCORRECT_DATA; + PRINTF("Refused INS when in SWAP mode\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); } - switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_NO_DISPLAY: - case P1_DISPLAY: - case P1_REQUEST_TOKEN: - break; - default: - return SW_INCORRECT_P1_P2; + + if (p1 != P1_NO_DISPLAY && p1 != P1_DISPLAY) { + PRINTF("Wrong P1 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } - switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { - case P2_NATIVE_SEGWIT: - if (!(COIN_NATIVE_SEGWIT_PREFIX)) { - return SW_INCORRECT_P1_P2; - } - __attribute__((fallthrough)); - case P2_LEGACY: - case P2_SEGWIT: - break; - case P2_CASHADDR: - if (COIN_KIND != COIN_KIND_BITCOIN_CASH) { - return SW_INCORRECT_P1_P2; - } - break; - default: - return SW_INCORRECT_P1_P2; + if (p2 == P2_NATIVE_SEGWIT && !COIN_NATIVE_SEGWIT_PREFIX) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } - if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { - return SW_INCORRECT_LENGTH; + if (p2 == P2_CASHADDR && COIN_KIND != COIN_KIND_BITCOIN_CASH) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } + + if (p2 != P2_NATIVE_SEGWIT && p2 != P2_LEGACY && p2 != P2_SEGWIT && p2 != P2_CASHADDR) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (buffer->size < 0x01) { + PRINTF("Wrong size\n"); + return io_send_sw(SW_INCORRECT_LENGTH); + } + if (display) { - is_derivation_path_unusual = set_key_path_to_display(G_io_apdu_buffer + ISO_OFFSET_CDATA); + is_derivation_path_unusual = set_key_path_to_display(buffer->ptr); } - unsigned char bip44_enforced = enforce_bip44_coin_type(G_io_apdu_buffer + ISO_OFFSET_CDATA, true); + unsigned char bip44_enforced = enforce_bip44_coin_type(buffer->ptr, true); G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); + keyLength = get_public_key_chain_code(buffer->ptr, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); if (keyLength == 0) { - return SW_TECHNICAL_PROBLEM; + return io_send_sw(SW_TECHNICAL_PROBLEM); } if (cashAddr) { @@ -155,31 +163,24 @@ unsigned short apdu_get_wallet_public_key() { if (display) { if (keyLength > 50) { - return SW_INCORRECT_DATA; + return io_send_sw(SW_INCORRECT_DATA); } // Hax, avoid wasting space memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_display_public_key(is_derivation_path_unusual); + display_public_key(is_derivation_path_unusual); + return 0; } - - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } -void bagl_user_action_display(unsigned char confirming) { - unsigned short sw = SW_OK; +int user_action_display(unsigned char confirming) { // confirm and finish the apdu exchange //spaghetti if (confirming) { - context_D.outLength -= - 2; // status was already set by the last call + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; context_D.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } diff --git a/src/apdu_hash_input_finalize_full.c b/lib-app-bitcoin/handler/hash_input_finalize_full.c similarity index 80% rename from src/apdu_hash_input_finalize_full.c rename to lib-app-bitcoin/handler/hash_input_finalize_full.c index 3e69d334..a1ed5acd 100644 --- a/src/apdu_hash_input_finalize_full.c +++ b/lib-app-bitcoin/handler/hash_input_finalize_full.c @@ -18,13 +18,18 @@ // TODO Trustlet, BAGL : process each output separately. // review nvm_write policy -#include "internal.h" +#include "crypto_helpers.h" +#include "read.h" +#include "swap.h" +#include "io.h" + +#include "context.h" +#include "helpers.h" +#include "customizable_helpers.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "ui.h" -#include "lib_standard_app/crypto_helpers.h" -#include "lib_standard_app/read.h" -#include "swap.h" +#include "be_operations.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 @@ -35,7 +40,7 @@ #define FLAG_SIGNATURE 0x01 #define FLAG_CHANGE_VALIDATED 0x80 -void apdu_hash_input_finalize_full_reset(void) { +void hash_input_finalize_full_reset(void) { context_D.currentOutputOffset = 0; context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; memset(context_D.totalOutputAmount, 0, @@ -43,11 +48,10 @@ void apdu_hash_input_finalize_full_reset(void) { context_D.changeOutputFound = 0; } -static bool check_output_displayable() { - bool displayable = true; +static int check_output_displayable(bool* displayable) { + *displayable = true; unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, nullAmount = 1; - unsigned char isOpCreate, isOpCall; for (j = 0; j < 8; j++) { if (context_D.currentOutput[j] != 0) { @@ -65,10 +69,11 @@ static bool check_output_displayable() { isP2sh = output_script_is_p2sh(context_D.currentOutput + 8); isNativeSegwit = output_script_is_native_witness( context_D.currentOutput + 8); - isOpCreate = +#ifndef __clang_analyzer__ + unsigned char isOpCreate = output_script_is_op_create(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8); - isOpCall = + unsigned char isOpCall = output_script_is_op_call(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8); if (((COIN_KIND == COIN_KIND_HYDRA) && @@ -78,8 +83,9 @@ static bool check_output_displayable() { !output_script_is_regular(context_D.currentOutput + 8) && !isP2sh && !(nullAmount && isOpReturn))) { PRINTF("Error : Unrecognized output script"); - THROW(EXCEPTION); + return -1; } +#endif if (context_D.tmpCtx.output.changeInitialized && !isOpReturn) { bool changeFound = false; unsigned char addressOffset = @@ -105,27 +111,26 @@ static bool check_output_displayable() { } else { // Attempt to avoid fatal failures on Bitcoin Cash PRINTF("Error : Non spendable Segwit change"); - THROW(EXCEPTION); + return -1; } } } if (changeFound) { if (context_D.changeOutputFound) { PRINTF("Error : Multiple change output found"); - THROW(EXCEPTION); + return -1; } context_D.changeOutputFound = true; - displayable = false; + *displayable = false; } } - - return displayable; + return 0; } -bool handle_output_state() { +int handle_output_state(unsigned int* processed) { uint32_t discardSize = 0; context_D.discardSize = 0; - bool processed = false; + *processed = 0; switch (context_D.outputParsingState) { case OUTPUT_PARSING_NUMBER_OUTPUTS: { context_D.totalOutputs = 0; @@ -137,7 +142,7 @@ bool handle_output_state() { context_D.currentOutput[0]; discardSize = 1; context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; + *processed = 1; break; } if (context_D.currentOutput[0] == 0xFD) { @@ -149,7 +154,7 @@ bool handle_output_state() { context_D.currentOutput[1]; discardSize = 3; context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; + *processed = 1; break; } else if (context_D.currentOutput[0] == 0xFE) { if (context_D.currentOutputOffset < 5) { @@ -159,15 +164,15 @@ bool handle_output_state() { read_u32_le(context_D.currentOutput, 1); discardSize = 5; context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; + *processed = 1; break; } else { - THROW(EXCEPTION); + return -1; } } break; case OUTPUT_PARSING_OUTPUT: { - unsigned int scriptSize; + unsigned int scriptSize = 0; if (context_D.currentOutputOffset < 9) { break; } @@ -182,7 +187,7 @@ bool handle_output_state() { discardSize = 3; } else { // Unrealistically large script - THROW(EXCEPTION); + return -1; } if (context_D.currentOutputOffset < 8 + discardSize + scriptSize) { @@ -190,24 +195,28 @@ bool handle_output_state() { break; } - processed = true; + *processed = 1; discardSize += 8 + scriptSize; - if (check_output_displayable()) { - context_D.io_flags |= IO_ASYNCH_REPLY; + bool displayable; + if (check_output_displayable(&displayable)) { + return -1; + } + if (displayable) { // The output can be processed by the UI context_D.discardSize = discardSize; discardSize = 0; + *processed = 2; } else { context_D.remainingOutputs--; } } break; default: - THROW(EXCEPTION); + return -1; } if (discardSize != 0) { @@ -217,38 +226,32 @@ bool handle_output_state() { context_D.currentOutputOffset -= discardSize; } - return processed; + return 0; } // out should be 32 bytes, even only 20 bytes is significant for output int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { cx_ecfp_public_key_t public_key; - int keyLength; if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { return -1; } - compress_public_key_value(public_key.W); - keyLength = 33; public_key_hash160( public_key.W, // IN - keyLength, // INLEN + 33, // INLEN out // OUT ); return 0; } -unsigned short apdu_hash_input_finalize_full_internal( - transaction_summary_t *transactionSummary) { +static unsigned short hash_input_finalize_full_internal(transaction_summary_t *transactionSummary, buffer_t* buffer, uint8_t p1, uint8_t p2, bool *async) { unsigned char authorizationHash[32]; - unsigned char apduLength; unsigned short sw = SW_OK; unsigned char *target = G_io_apdu_buffer; - unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; unsigned char hashOffset = 0; - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; + (void) p2; if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && (p1 != FINALIZE_P1_CHANGEINFO)) { @@ -258,7 +261,7 @@ unsigned short apdu_hash_input_finalize_full_internal( // See if there is a hashing offset if (context_D.usingSegwit && (context_D.tmpCtx.output.multipleOutput == 0)) { - unsigned char firstByte = G_io_apdu_buffer[ISO_OFFSET_CDATA]; + unsigned char firstByte = buffer->ptr[0]; if (firstByte < 0xfd) { hashOffset = 1; } else if (firstByte == 0xfd) { @@ -278,7 +281,6 @@ unsigned short apdu_hash_input_finalize_full_internal( if (p1 == FINALIZE_P1_CHANGEINFO) { if (!context_D.transactionContext.firstSigned) { // Already validated, should be prevented on the client side -return_OK: return SW_OK; } if (!context_D.tmpCtx.output.changeAccepted) { @@ -287,17 +289,17 @@ unsigned short apdu_hash_input_finalize_full_internal( } memset(transactionSummary, 0, sizeof(transaction_summary_t)); - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { + if (buffer->ptr[0] == 0x00) { // Called with no change path, abort, should be prevented on // the client side - goto return_OK; + return SW_OK; } memmove(transactionSummary->keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, + buffer->ptr, MAX_BIP32_PATH_LENGTH); if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), context_D.tmpCtx.output.changeAddress)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } PRINTF("Change address = %.*H\n", 20, context_D.tmpCtx.output.changeAddress); @@ -312,41 +314,41 @@ unsigned short apdu_hash_input_finalize_full_internal( sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - context_D.io_flags |= IO_ASYNCH_REPLY; + *async = true; context_D.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; - bagl_request_change_path_approval(transactionSummary->keyPath); + request_change_path_approval(transactionSummary->keyPath); } - goto return_OK; + return SW_OK; } // Always update the transaction & authorization hashes with the // given data // For SegWit, this has been reset to hold hashOutputs if (!context_D.segwitParsedOnce) { - if ((int)(apduLength - hashOffset) < 0) { + if ((int)(buffer->size - hashOffset) < 0) { sw = SW_INCORRECT_DATA; goto discardTransaction; } if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, buffer->ptr + hashOffset, buffer->size - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", buffer->size - hashOffset, buffer->ptr + hashOffset); if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + buffer->ptr + hashOffset, + buffer->size - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } } if (context_D.transactionContext.firstSigned) { - if ((context_D.currentOutputOffset + apduLength) > + if ((context_D.currentOutputOffset + buffer->size) > sizeof(context_D.currentOutput)) { PRINTF("Output is too long to be checked\n"); sw = SW_INCORRECT_DATA; @@ -354,46 +356,53 @@ unsigned short apdu_hash_input_finalize_full_internal( } memmove(context_D.currentOutput + context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); - context_D.currentOutputOffset += apduLength; + buffer->ptr, buffer->size); + context_D.currentOutputOffset += buffer->size; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + if (processed == 2) { + *async = true; + } // Finalize the TX if necessary if ((context_D.remainingOutputs == 0) && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) { - context_D.io_flags |= IO_ASYNCH_REPLY; + (!*async)) { + *async = true; context_D.outputParsingState = OUTPUT_FINALIZE_TX; } } - if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { + if (p1 == FINALIZE_P1_MORE) { if (!context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); if (cx_hash_no_throw( &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength, + 0, buffer->ptr, buffer->size, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } G_io_apdu_buffer[0] = 0x00; context_D.outLength = 1; context_D.tmpCtx.output.multipleOutput = 1; - goto return_OK; + return SW_OK; } if (!context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, - apduLength, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + CX_LAST, buffer->ptr, + buffer->size, authorizationHash, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } @@ -402,7 +411,7 @@ unsigned short apdu_hash_input_finalize_full_internal( if (!context_D.segwitParsedOnce) { if (context_D.usingOverwinter) { if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, context_D.segwit.cache.hashedOutputs, 0, context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } @@ -411,11 +420,11 @@ unsigned short apdu_hash_input_finalize_full_internal( CX_LAST, context_D.segwit.cache.hashedOutputs, 0, context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, @@ -423,7 +432,7 @@ unsigned short apdu_hash_input_finalize_full_internal( context_D.segwit.cache.hashedOutputs, sizeof(context_D.segwit.cache.hashedOutputs), context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } } @@ -431,7 +440,7 @@ unsigned short apdu_hash_input_finalize_full_internal( if (cx_hash_no_throw( &context_D.transactionHashAuthorization.header, CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); @@ -442,7 +451,7 @@ unsigned short apdu_hash_input_finalize_full_internal( (unsigned char *)&context_D.segwit.cache, sizeof(context_D.segwit.cache), authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discardTransaction; } PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); @@ -479,7 +488,7 @@ unsigned short apdu_hash_input_finalize_full_internal( memmove(transactionSummary->authorizationHash, authorizationHash, sizeof(transactionSummary->authorizationHash)); - goto return_OK; + return SW_OK; } else { if (os_secure_memcmp( authorizationHash, @@ -501,13 +510,12 @@ unsigned short apdu_hash_input_finalize_full_internal( context_D.transactionContext.transactionState = TRANSACTION_SIGN_READY; } - sw = SW_OK; + hash_input_finalize_full_reset(); + return SW_OK; } - apdu_hash_input_finalize_full_reset(); - return sw; discardTransaction: - apdu_hash_input_finalize_full_reset(); + hash_input_finalize_full_reset(); ui_transaction_error(); context_D.transactionContext.transactionState = TRANSACTION_NONE; @@ -519,37 +527,43 @@ unsigned short apdu_hash_input_finalize_full_internal( return sw; } -unsigned short apdu_hash_input_finalize_full() { +unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2) { + bool is_async = false; PRINTF("state=%d\n", context_D.outputParsingState); - unsigned short sw = apdu_hash_input_finalize_full_internal( - &context_D.transactionSummary); - if (context_D.io_flags & IO_ASYNCH_REPLY) { + unsigned short sw = hash_input_finalize_full_internal( + &context_D.transactionSummary, buffer, p1, p2, &is_async); + + if (is_async) { // if the UI reject the processing of the request, then reply // immediately - bool status; + int status; if(context_D.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - return sw; + return 0; } else if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - status = bagl_finalize_tx(); + status = finalize_tx(); } else { - status = bagl_confirm_single_output(); + status = confirm_single_output(); } - if (!status) { + if (status == 0) { ui_transaction_error(); - context_D.io_flags &= ~IO_ASYNCH_REPLY; context_D.transactionContext.transactionState = TRANSACTION_NONE; context_D.outLength = 0; sw = SW_INCORRECT_DATA; + return io_send_sw(sw); + } + else if (status == 2) { + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } + return 0; } - return sw; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, sw); } -unsigned char bagl_user_action(unsigned char confirming) { +unsigned char user_action(unsigned char confirming) { unsigned short sw = SW_OK; // confirm and finish the apdu exchange //spaghetti @@ -570,12 +584,18 @@ unsigned char bagl_user_action(unsigned char confirming) { context_D.discardSize); context_D.currentOutputOffset -= context_D.discardSize; - context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (context_D.io_flags & IO_ASYNCH_REPLY) { - if (!bagl_confirm_single_output()) { + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } + } + + if (processed == 2) { + if (!confirm_single_output()) { context_D.transactionContext.transactionState = TRANSACTION_NONE; sw = SW_INCORRECT_DATA; @@ -594,7 +614,7 @@ unsigned char bagl_user_action(unsigned char confirming) { OUTPUT_PARSING_OUTPUT) && (context_D.remainingOutputs == 0)) { context_D.outputParsingState = OUTPUT_FINALIZE_TX; - if (!bagl_finalize_tx()) { + if (!finalize_tx()) { context_D.outputParsingState = OUTPUT_PARSING_NONE; context_D.transactionContext.transactionState = @@ -622,8 +642,6 @@ unsigned char bagl_user_action(unsigned char confirming) { TRANSACTION_SIGN_READY; } } - context_D.outLength -= - 2; // status was already set by the last call } else { // Discard transaction context_D.transactionContext.transactionState = @@ -631,17 +649,13 @@ unsigned char bagl_user_action(unsigned char confirming) { sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; context_D.outLength = 0; } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; if ((context_D.outputParsingState == OUTPUT_FINALIZE_TX) || (sw != SW_OK)) { // we've finished the processing of the input - apdu_hash_input_finalize_full_reset(); + hash_input_finalize_full_reset(); } + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, sw); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); - - return 0; } diff --git a/src/apdu_hash_input_start.c b/lib-app-bitcoin/handler/hash_input_start.c similarity index 53% rename from src/apdu_hash_input_start.c rename to lib-app-bitcoin/handler/hash_input_start.c index bc315ae5..f2906c67 100644 --- a/src/apdu_hash_input_start.c +++ b/lib-app-bitcoin/handler/hash_input_start.c @@ -15,9 +15,12 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" +#include "io.h" + +#include "context.h" +#include "transaction.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "swap.h" #define P1_FIRST 0x00 @@ -29,58 +32,59 @@ #define P2_NEW_SEGWIT_SAPLING 0x05 #define P2_CONTINUE 0x80 -#define IS_INPUT() \ - (G_io_apdu_buffer[ISO_OFFSET_LC] - 1 > 8 \ - && G_io_apdu_buffer[ISO_OFFSET_LC] - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA] <= 0x02) \ - -#define IS_INPUT_TRUSTED() \ - (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x01 \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 1] == TRUSTED_INPUT_TOTAL_SIZE \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 2] == MAGIC_TRUSTED_INPUT \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 3] == 0x00) +#define IS_INPUT() \ + (buffer->size - 1 > 8 \ + && buffer->size - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 \ + && buffer->ptr[0] <= 0x02) \ -unsigned short apdu_hash_input_start() { - unsigned char apduLength; - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; +#define IS_INPUT_TRUSTED() \ + (buffer->ptr[0] == 0x01 \ + && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE \ + && buffer->ptr[2] == MAGIC_TRUSTED_INPUT \ + && buffer->ptr[3] == 0x00) - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { +WEAK unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2) { + if (p1 == P1_FIRST) { // Initialize context_D.transactionContext.transactionState = TRANSACTION_NONE; context_D.transactionHashOption = TRANSACTION_HASH_BOTH; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { - return SW_INCORRECT_P1_P2; + } else if (p1 != P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); } - if ((G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING)) { - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { + if ((p2 == P2_NEW) || + (p2 == P2_NEW_SEGWIT) || + (p2 == P2_NEW_SEGWIT_CASHADDR) || + (p2 == P2_NEW_SEGWIT_OVERWINTER) || + (p2 == P2_NEW_SEGWIT_SAPLING)) { + if (p1 == P1_FIRST) { unsigned char usingSegwit = - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING); - unsigned char usingCashAddr = - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR); + (p2 == P2_NEW_SEGWIT) || + (p2 == P2_NEW_SEGWIT_CASHADDR) || + (p2 == P2_NEW_SEGWIT_OVERWINTER) || + (p2 == P2_NEW_SEGWIT_SAPLING); // Master transaction reset context_D.transactionContext.firstSigned = 1; context_D.transactionContext.consumeP2SH = 0; context_D.transactionContext.relaxed = 0; context_D.usingSegwit = usingSegwit; - context_D.usingCashAddr = - (COIN_KIND == COIN_KIND_BITCOIN_CASH ? usingCashAddr - : 0); + + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + unsigned char usingCashAddr = (p2 == P2_NEW_SEGWIT_CASHADDR); + context_D.usingCashAddr = usingCashAddr; + } + else { + context_D.usingCashAddr = 0; + } + context_D.usingOverwinter = 0; if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || (COIN_KIND == COIN_KIND_ZCLASSIC) || (COIN_KIND == COIN_KIND_RESISTANCE)) { - if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) { + if (p2 == P2_NEW_SEGWIT_OVERWINTER) { context_D.usingOverwinter = ZCASH_USING_OVERWINTER; } else - if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING) { + if (p2 == P2_NEW_SEGWIT_SAPLING) { context_D.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; } } @@ -94,15 +98,15 @@ unsigned short apdu_hash_input_start() { // segwit input when coontinuing from a previous session (P2=0x80) context_D.segwitWarningSeen = 0; } - } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { - return SW_INCORRECT_P1_P2; + } else if (p2 != P2_CONTINUE) { + return io_send_sw(SW_INCORRECT_P1_P2); } // In segwit mode, warn user one time only to update its client wallet... if (context_D.usingSegwit && !context_D.segwitWarningSeen - &&(G_io_apdu_buffer[ISO_OFFSET_P1] == P1_NEXT) - && (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) + && (p1 == P1_NEXT) + && (p2 != P2_CONTINUE) // ...if input is not passed as a TrustedInput && IS_INPUT() && !IS_INPUT_TRUSTED()) @@ -110,19 +114,23 @@ unsigned short apdu_hash_input_start() { if(G_called_from_swap){ /* There is no point in displaying a warning when the app is signing in silent mode, as its UI is hidden behind the exchange app*/ - return SW_SWAP_WITHOUT_TRUSTED_INPUTS; + return io_send_sw(SW_SWAP_WITHOUT_TRUSTED_INPUTS); } context_D.segwitWarningSeen = 1; - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_request_segwit_input_approval(); + request_segwit_input_approval(); + // Start parsing of the 1st chunk + context_D.transactionBufferPointer = (uint8_t*) buffer->ptr; + context_D.transactionDataRemaining = buffer->size; + + transaction_parse(PARSE_MODE_SIGNATURE); + return 0; } // Start parsing of the 1st chunk - context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA; - context_D.transactionDataRemaining = apduLength; + context_D.transactionBufferPointer = (uint8_t*) buffer->ptr; + context_D.transactionDataRemaining = buffer->size; transaction_parse(PARSE_MODE_SIGNATURE); - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } diff --git a/src/apdu_hash_sign.c b/lib-app-bitcoin/handler/hash_sign.c similarity index 71% rename from src/apdu_hash_sign.c rename to lib-app-bitcoin/handler/hash_sign.c index 9f670031..bd505aa7 100644 --- a/src/apdu_hash_sign.c +++ b/lib-app-bitcoin/handler/hash_sign.c @@ -15,15 +15,19 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" +#include "macros.h" +#include "io.h" +#include "ledger_assert.h" +#include "read.h" +#include "write.h" +#include "swap.h" + +#include "context.h" +#include "helpers.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "display_variables.h" #include "ui.h" -#include "ledger_assert.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/write.h" -#include "swap.h" #define SIGHASH_ALL 0x01 @@ -31,21 +35,20 @@ #define COIN_FORKID 0 #endif -unsigned short apdu_hash_sign() { +WEAK unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned long int lockTime; uint32_t sighashType; unsigned char dataBuffer[8]; unsigned char authorizationLength; - unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA; - unsigned short sw = SW_TECHNICAL_DETAILS(0xF); + unsigned char *parameters = (uint8_t*)buffer->ptr; - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) || - (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { - return SW_INCORRECT_P1_P2; + if ((p1 != 0) || (p2 != 0)) { + return io_send_sw(SW_INCORRECT_P1_P2); } - if (G_io_apdu_buffer[ISO_OFFSET_LC] < (1 + 1 + 4 + 1)) { - return SW_INCORRECT_LENGTH; +#define HASH_LENGTH 1 + 1 + 4 + 1 + if (buffer->size < HASH_LENGTH) { + return io_send_sw(SW_INCORRECT_LENGTH); } // Zcash special - store parameters for later @@ -55,7 +58,7 @@ unsigned short apdu_hash_sign() { (context_D.segwitParsedOnce) && (context_D.transactionContext.transactionState == TRANSACTION_NONE)) { unsigned long int expiryHeight; - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; + parameters += (4 * buffer->ptr[0]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; lockTime = read_u32_be(parameters, 0); @@ -66,31 +69,31 @@ unsigned short apdu_hash_sign() { write_u32_le(context_D.sigHashType, 0, sighashType); write_u32_le(context_D.nExpiryHeight, 0, expiryHeight); context_D.overwinterSignReady = 1; - return SW_OK; + return io_send_sw(SW_OK); } if (context_D.transactionContext.transactionState != TRANSACTION_SIGN_READY) { PRINTF("Invalid transaction state %d\n", context_D.transactionContext.transactionState); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } if (context_D.usingOverwinter && !context_D.overwinterSignReady) { PRINTF("Overwinter not ready to sign\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } // Read parameters - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; + if (buffer->ptr[0] > MAX_BIP32_PATH) { + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } memmove(context_D.transactionSummary.keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, + buffer->ptr, MAX_BIP32_PATH_LENGTH); - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; + parameters += (4 * buffer->ptr[0]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; lockTime = read_u32_be(parameters, 0); @@ -98,18 +101,20 @@ unsigned short apdu_hash_sign() { sighashType = *(parameters++); context_D.transactionSummary.sighashType = sighashType; - // if bitcoin cash OR forkid is set, then use the fork id - if (COIN_KIND == COIN_KIND_BITCOIN_CASH || (COIN_FORKID)) { + // if bitcoin cash OR forkid is set, then use the fork id + if ((COIN_KIND == COIN_KIND_BITCOIN_CASH) || + (COIN_FORKID)) { #define SIGHASH_FORKID 0x40 if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } sighashType |= (COIN_FORKID << 8); + } else { if (sighashType != SIGHASH_ALL) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } } @@ -120,20 +125,19 @@ unsigned short apdu_hash_sign() { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, dataBuffer, sizeof(dataBuffer), NULL, 0)) { - goto discardTransaction; + context_D.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } } // Check if the path needs to be enforced if (!enforce_bip44_coin_type(context_D.transactionSummary.keyPath, false)) { - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_request_sign_path_approval(context_D.transactionSummary.keyPath); + request_sign_path_approval(context_D.transactionSummary.keyPath); } else { // Sign immediately - bagl_user_action_signtx(1, 1); + user_action_signtx(1, 0); } - sw = SW_OK; if (G_called_from_swap) { // if we signed all outputs we should exit, // but only after sending response, so lets raise the @@ -142,17 +146,12 @@ unsigned short apdu_hash_sign() { if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { vars.swap_data.should_exit = 1; } + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } - - return sw; - - discardTransaction: - context_D.transactionContext.transactionState = TRANSACTION_NONE; - return sw; + return 0; } -void bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { - unsigned short sw = SW_OK; +int user_action_signtx(unsigned char confirming, unsigned char direct) { // confirm and finish the apdu exchange //spaghetti if (confirming) { unsigned char hash[32]; @@ -174,23 +173,20 @@ void bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { context_D.transactionSummary.keyPath, sizeof(context_D.transactionSummary.keyPath), hash, sizeof(hash), - G_io_apdu_buffer, &out_len, - 1); + G_io_apdu_buffer, &out_len); context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[context_D.outLength++] = context_D.transactionSummary.sighashType; ui_transaction_finish(); } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; context_D.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } if (!direct) { - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, SW_OK); } + return 0; } diff --git a/src/apdu_sign_message.c b/lib-app-bitcoin/handler/sign_message.c similarity index 71% rename from src/apdu_sign_message.c rename to lib-app-bitcoin/handler/sign_message.c index 9a5bbc54..782e27b4 100644 --- a/src/apdu_sign_message.c +++ b/lib-app-bitcoin/handler/sign_message.c @@ -15,11 +15,13 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" +#include "context.h" +#include "helpers.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "lib_standard_app/read.h" #include "swap.h" +#include "io.h" #define P1_PREPARE 0x00 #define P1_SIGN 0x80 @@ -31,11 +33,11 @@ #define BITID_POWERCYCLE 1 #define BITID_MULTIPLE 2 -//#define SLIP_13 0x8000000D +unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', + 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; -unsigned short compute_hash(void); - -unsigned char checkBitId(unsigned char *bip32Path) { +// TODO : support longer messages +unsigned char message_check_bit_id(unsigned char *bip32Path) { unsigned char i; unsigned char bip32PathLength = bip32Path[0]; bip32Path++; @@ -53,21 +55,48 @@ unsigned char checkBitId(unsigned char *bip32Path) { return BITID_NONE; } -// TODO : support longer messages +unsigned short message_compute_hash(void) { + unsigned char hash[32]; + unsigned short sw = SW_OK; + + context_D.outLength = 0; + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, hash, + 0, hash, 32)) { + goto discard; + } + + if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { + goto discard; + } + + size_t out_len = 100; + sign_finalhash( + context_D.transactionSummary.keyPath, + sizeof(context_D.transactionSummary.keyPath), + hash, sizeof(hash), // IN + G_io_apdu_buffer, &out_len); // OUT + context_D.outLength = G_io_apdu_buffer[1] + 2; + memset(&context_D.transactionSummary, 0, + sizeof(transaction_summary_t)); + return sw; -unsigned short apdu_sign_message_internal() { + discard: + sw = SW_TECHNICAL_PROBLEM_2; + return sw; +} + + +static unsigned short sign_message_internal(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned short sw = SW_OK; - unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; - unsigned char p2 = G_io_apdu_buffer[ISO_OFFSET_P2]; - unsigned char apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - unsigned short offset = ISO_OFFSET_CDATA; + unsigned char apduLength = buffer->size; + unsigned short offset = 0; if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { - return SW_INCORRECT_P1_P2; + return io_send_sw(SW_INCORRECT_P1_P2); } if (p1 == P1_PREPARE) { if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { - return SW_INCORRECT_P1_P2; + return io_send_sw(SW_INCORRECT_P1_P2); } } @@ -78,7 +107,7 @@ unsigned short apdu_sign_message_internal() { unsigned char messageLengthSize; memset(&context_D.transactionSummary, 0, sizeof(transaction_summary_t)); - if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { + if (buffer->ptr[0] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); sw = SW_INCORRECT_DATA; goto discard; @@ -87,16 +116,16 @@ unsigned short apdu_sign_message_internal() { context_D.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; memmove( context_D.transactionSummary.keyPath, - G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); - offset += (4 * G_io_apdu_buffer[offset]) + 1; + buffer->ptr, MAX_BIP32_PATH_LENGTH); + offset += (4 * buffer->ptr[0]) + 1; if (p2 == P2_LEGACY) { context_D.transactionSummary.messageLength = - G_io_apdu_buffer[offset]; + buffer->ptr[offset]; offset++; } else { context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | - (G_io_apdu_buffer[offset + 1]); + (buffer->ptr[offset] << 8) | + (buffer->ptr[offset + 1]); offset += 2; } if (context_D.transactionSummary.messageLength == @@ -106,20 +135,16 @@ unsigned short apdu_sign_message_internal() { goto discard; } context_D.hashedMessageLength = 0; - if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (cx_sha256_init_no_throw( - &context_D.transactionHashAuthorization)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } + // Horizen signed message magic header is "Zcash" // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 const char* magicHeader = (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; + + cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256); + cx_sha256_init_no_throw(&context_D.transactionHashAuthorization); + chunkLength = - strlen(magicHeader) + SIGNMAGIC_LENGTH; + strlen(magicHeader) + sizeof(SIGNMAGIC); if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, &chunkLength, 1, NULL, 0)) { goto discard; @@ -127,12 +152,12 @@ unsigned short apdu_sign_message_internal() { if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, (uint8_t *)magicHeader, strlen(magicHeader), NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + (unsigned char *)SIGNMAGIC, sizeof(SIGNMAGIC), NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } if (context_D.transactionSummary.messageLength < @@ -153,10 +178,10 @@ unsigned short apdu_sign_message_internal() { } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, messageLength, messageLengthSize, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } - chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); + chunkLength = apduLength - offset; if ((context_D.hashedMessageLength + chunkLength) > context_D.transactionSummary.messageLength) { PRINTF("Invalid data length\n"); @@ -164,14 +189,14 @@ unsigned short apdu_sign_message_internal() { goto discard; } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } if (cx_hash_no_throw( &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + 0, buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } context_D.hashedMessageLength += chunkLength; @@ -191,14 +216,14 @@ unsigned short apdu_sign_message_internal() { goto discard; } if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } if (cx_hash_no_throw( &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); + 0, buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; goto discard; } context_D.hashedMessageLength += apduLength; @@ -219,72 +244,36 @@ unsigned short apdu_sign_message_internal() { sw = SW_INCORRECT_DATA; goto discard; } - if (checkBitId(context_D.transactionSummary.keyPath) != BITID_NONE) { - sw = compute_hash(); + if (message_check_bit_id(context_D.transactionSummary.keyPath) != BITID_NONE) { + sw = message_compute_hash(); } else { - context_D.io_flags |= IO_ASYNCH_REPLY; - return SW_OK; + confirm_message_signature(); + return 0; } } - return sw; + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, sw); discard : memset(&context_D.transactionSummary, 0, sizeof(transaction_summary_t)); - return sw; + return io_send_sw(sw); } -unsigned short apdu_sign_message() { +WEAK unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2) { if (G_called_from_swap) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } - unsigned short sw = apdu_sign_message_internal(); - if (context_D.io_flags & IO_ASYNCH_REPLY) { - bagl_confirm_message_signature(); + return io_send_sw(SW_SECURITY_STATUS_NOT_SATISFIED); } - return sw; -} -unsigned short compute_hash() { - unsigned char hash[32]; - unsigned short sw = SW_OK; - - context_D.outLength = 0; - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, hash, - 0, hash, 32)) { - goto discard; - } - - if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { - goto discard; - } - - size_t out_len = 100; - sign_finalhash( - context_D.transactionSummary.keyPath, - sizeof(context_D.transactionSummary.keyPath), - hash, sizeof(hash), // IN - G_io_apdu_buffer, &out_len, // OUT - 1); - context_D.outLength = G_io_apdu_buffer[1] + 2; - memset(&context_D.transactionSummary, 0, - sizeof(transaction_summary_t)); - return sw; - - discard: - sw = SW_TECHNICAL_DETAILS(0x0F); - return sw; + return sign_message_internal(buffer, p1, p2); } -void bagl_user_action_message_signing(unsigned char confirming) { +int user_action_message_signing(unsigned char confirming) { unsigned short sw; if (confirming) { - sw = compute_hash(); + sw = message_compute_hash(); + return io_send_response_pointer(G_io_apdu_buffer, context_D.outLength, sw); } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context_D.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } diff --git a/lib-app-bitcoin/helpers.c b/lib-app-bitcoin/helpers.c new file mode 100644 index 00000000..b640fb6c --- /dev/null +++ b/lib-app-bitcoin/helpers.c @@ -0,0 +1,233 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "lib_standard_app/crypto_helpers.h" +#include "lib_standard_app/bip32.h" +#include "ledger_assert.h" +#include "io.h" +#include "base58.h" +#include "read.h" + +#include "context.h" +#include "helpers.h" + +void public_key_hash160(unsigned char *in, unsigned short inlen, + unsigned char *out) { + cx_ripemd160_t riprip; + unsigned char buffer[32]; + cx_hash_sha256(in, inlen, buffer, 32); + cx_ripemd160_init(&riprip); + LEDGER_ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20) == CX_OK, "hash160"); +} + +void compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { + unsigned char checksumBuffer[32]; + cx_hash_sha256(in, inlen, checksumBuffer, 32); + cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); + + PRINTF("Checksum\n%.*H\n",4,checksumBuffer); + memmove(output, checksumBuffer, 4); +} + +unsigned short public_key_to_encoded_base58( + unsigned char *in, unsigned short inlen, unsigned char *out, + unsigned short outlen, unsigned short version, + unsigned char alreadyHashed) { + unsigned char tmpBuffer[34]; + + unsigned char versionSize = (version > 255 ? 2 : 1); + short outputLen; + + if (!alreadyHashed) { + PRINTF("To hash\n%.*H\n",inlen,in); + public_key_hash160(in, inlen, tmpBuffer + versionSize); + PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); + if (version > 255) { + tmpBuffer[0] = (version >> 8); + tmpBuffer[1] = version; + } else { + tmpBuffer[0] = version; + } + } else { + memmove(tmpBuffer, in, 20 + versionSize); + } + + compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); + + outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); + LEDGER_ASSERT(outputLen >= 0, "Error encoding public key"); + + return outputLen; +} + +void swap_bytes(unsigned char *target, unsigned char *source, + unsigned char size) { + unsigned char i; + for (i = 0; i < size; i++) { + target[i] = source[size - 1 - i]; + } +} + +/* +Checks if the values of a derivation path are within "normal" (arbitrary) ranges: +Account < 100, change == 1 or 0, address index < 50000 +Returns 1 if the path is unusual, or not compliant with BIP44*/ +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path) { + unsigned char path_len; + bip32_path_t bip32PathInt; + + path_len = bip32Path[0]; + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning + if(path_len != BIP44_PATH_LEN || + ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { + return 1; + } + + // If the coin type doesn't match, return a warning + if ((BIP44_COIN_TYPE != 0) && + (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { + return 1; + } + + // If the account or address index is very high or if the change isn't 1, return a warning + if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || + bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + return 1; + } + + return 0; +} + +/* +Only enforce the structure or coin type for consumed UTXOs or a public address +Returns 0 if the path is non compliant, or 1 if compliant +*/ +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey) { + bip32_path_t bip32PathInt; + // No enforcement required + if (BIP44_COIN_TYPE == 0) { + return 1; + } + // Path is too short - always require a user validation if signing + if (bip32Path[0] < 2) { + return for_pubkey; + } + + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // Path is not compliant with BIP 44 or derivatives - valid if not signing + if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { + return for_pubkey; + } + + if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { + // Valid BIP 44 path + return 1; + } + // Everything else needs a user validation + return 0; +} + +int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, + unsigned char *out, size_t* outlen) { + + unsigned int info = 0; + + io_seproxyhal_io_heartbeat(); + + bip32_path_t bip32Path; + bip32Path.length = path[0]; + + if (!parse_serialized_path(&bip32Path, path, path_len)) { + return -1; + } + + if (bip32_derive_ecdsa_sign_hash_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + CX_LAST | CX_RND_RFC6979, + CX_SHA256, + in, + inlen, + out, + outlen, + &info) != CX_OK) { + return -1; + } + + // Store information about the parity of the 'y' coordinate + if (info & CX_ECCINFO_PARITY_ODD) { + out[0] |= 0x01; + } + + io_seproxyhal_io_heartbeat(); + return 0; +} + +int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { + + bip32_path_t bip32Path; + + if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { + return -1; + } + + if (bip32_derive_get_pubkey_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + raw_pubkey, + chainCode, + CX_SHA512) != CX_OK) + { + return -1; + } + + return 0; +} + +void compress_public_key_value(unsigned char *value) { + bool odd = (value[64] & 1); + value[0] = odd ? 0x03 : 0x02; +} + +bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length) { + if (serialized_path_length < 1 || + serialized_path[0] > MAX_BIP32_PATH || + serialized_path[0] * 4 + 1 > serialized_path_length) + return false; + path->length = serialized_path[0]; + serialized_path++; + for (int i = 0; i < path->length; i += 1, serialized_path += 4) { + path->path[i] = read_u32_be(serialized_path, 0); + } + return true; +} diff --git a/include/helpers.h b/lib-app-bitcoin/helpers.h similarity index 57% rename from include/helpers.h rename to lib-app-bitcoin/helpers.h index febe122a..713dfa1b 100644 --- a/include/helpers.h +++ b/lib-app-bitcoin/helpers.h @@ -15,13 +15,12 @@ * limitations under the License. ********************************************************************************/ -#ifndef HELPERS_H - -#define HELPERS_H +#pragma once #include "os.h" #include "cx.h" #include "stdbool.h" +#include "filesystem_tx.h" #define OUTPUT_SCRIPT_REGULAR_PRE_LENGTH 4 #define OUTPUT_SCRIPT_REGULAR_POST_LENGTH 2 @@ -30,15 +29,10 @@ #define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3 -unsigned char output_script_is_regular(unsigned char *buffer); -unsigned char output_script_is_p2sh(unsigned char *buffer); -unsigned char output_script_is_op_return(unsigned char *buffer); -unsigned char output_script_is_native_witness(unsigned char *buffer); - -unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size); -unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size); +typedef struct bip32_path { + unsigned char length; + unsigned int path[MAX_BIP32_PATH]; +} bip32_path_t; void public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out); @@ -46,20 +40,18 @@ unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed); -unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path); -unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey); -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len); +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path); +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey); void swap_bytes(unsigned char *target, unsigned char *source, unsigned char size); int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen, - unsigned char rfc6979); + unsigned char *out, size_t* outlen); + +int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); -void transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh); -int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); +void compress_public_key_value(unsigned char *value); -#endif +bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length); diff --git a/src/swap/handle_check_address.c b/lib-app-bitcoin/swap/handle_check_address.c similarity index 93% rename from src/swap/handle_check_address.c rename to lib-app-bitcoin/swap/handle_check_address.c index 1fd13dec..95e6d166 100644 --- a/src/swap/handle_check_address.c +++ b/lib-app-bitcoin/swap/handle_check_address.c @@ -1,14 +1,19 @@ #include "handle_check_address.h" -#include "os.h" #include "helpers.h" -#include "bip32_path.h" -#include "ecc.h" -#include "apdu_get_wallet_public_key.h" +#include "context.h" #include "cashaddr.h" #include "segwit_addr.h" -#include -bool derive_compressed_public_key( +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 +#define P1_REQUEST_TOKEN 0x02 + +#define P2_LEGACY 0x00 +#define P2_SEGWIT 0x01 +#define P2_NATIVE_SEGWIT 0x02 +#define P2_CASHADDR 0x03 + +static bool derive_compressed_public_key( unsigned char* serialized_path, unsigned char serialized_path_length, unsigned char* public_key, unsigned char public_key_length) { UNUSED(public_key_length); @@ -23,7 +28,7 @@ bool derive_compressed_public_key( return true; } -bool get_address_from_compressed_public_key( +static bool get_address_from_compressed_public_key( unsigned char format, unsigned char* compressed_pub_key, unsigned short payToAddressVersion, diff --git a/src/swap/handle_check_address.h b/lib-app-bitcoin/swap/handle_check_address.h similarity index 91% rename from src/swap/handle_check_address.h rename to lib-app-bitcoin/swap/handle_check_address.h index 01d8e138..2e5eaa54 100644 --- a/src/swap/handle_check_address.h +++ b/lib-app-bitcoin/swap/handle_check_address.h @@ -2,7 +2,6 @@ #define _HANDLE_CHECK_ADDRESS_H_ #include "swap_lib_calls.h" -#include "context.h" void swap_handle_check_address(check_address_parameters_t* check_address_params); diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.c b/lib-app-bitcoin/swap/handle_get_printable_amount.c new file mode 100644 index 00000000..d801bfab --- /dev/null +++ b/lib-app-bitcoin/swap/handle_get_printable_amount.c @@ -0,0 +1,20 @@ +#include "read.h" + +#include "handle_get_printable_amount.h" +#include "display_utils.h" + +void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { + params->printable_amount[0] = 0; + if (params->amount_length > 8) { + PRINTF("Amount is too big"); + return; + } + unsigned char amount[8]; + memset(amount, 0, 8); + memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); + + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)(read_u64_be(amount, 0)), // Cast prevents weird compilo bug + params->printable_amount); + return; +} \ No newline at end of file diff --git a/src/swap/handle_get_printable_amount.h b/lib-app-bitcoin/swap/handle_get_printable_amount.h similarity index 100% rename from src/swap/handle_get_printable_amount.h rename to lib-app-bitcoin/swap/handle_get_printable_amount.h diff --git a/src/swap/handle_swap_sign_transaction.c b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c similarity index 98% rename from src/swap/handle_swap_sign_transaction.c rename to lib-app-bitcoin/swap/handle_swap_sign_transaction.c index c29af60c..61e4d0a1 100644 --- a/src/swap/handle_swap_sign_transaction.c +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c @@ -1,6 +1,5 @@ #include "handle_swap_sign_transaction.h" #include "os_io_seproxyhal.h" -#include "public_ram_variables.h" #include "display_variables.h" #include "context.h" #include "usbd_core.h" diff --git a/src/swap/handle_swap_sign_transaction.h b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h similarity index 94% rename from src/swap/handle_swap_sign_transaction.h rename to lib-app-bitcoin/swap/handle_swap_sign_transaction.h index 7203d065..be98246e 100644 --- a/src/swap/handle_swap_sign_transaction.h +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h @@ -2,7 +2,6 @@ #define _HANDLE_SWAP_SIGN_TRANSACTION_H_ #include "swap_lib_calls.h" -#include "context.h" bool swap_copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); diff --git a/src/transaction.c b/lib-app-bitcoin/transaction.c similarity index 89% rename from src/transaction.c rename to lib-app-bitcoin/transaction.c index 2806d623..cf47caa4 100644 --- a/src/transaction.c +++ b/lib-app-bitcoin/transaction.c @@ -15,14 +15,19 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "apdu_constants.h" -#include "display_variables.h" #include "ledger_assert.h" #include "lib_standard_app/read.h" #include "lib_standard_app/write.h" #include "swap.h" +#include "apdu_constants.h" +#include "display_variables.h" +#include "be_operations.h" +#include "transaction.h" +#include "context.h" +#include "filesystem.h" +#include "helpers.h" + #ifndef COIN_CONSENSUS_BRANCH_ID #define COIN_CONSENSUS_BRANCH_ID 0 #endif @@ -31,6 +36,12 @@ #define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb #define CONSENSUS_BRANCH_ID_ZCLASSIC 0x930b540d +unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0 }; +unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + // Check if fOverwintered flag is set and if nVersion is >= 0x03 #define TRUSTED_INPUT_OVERWINTER ( (COIN_KIND == COIN_KIND_ZCASH || \ COIN_KIND == COIN_KIND_ZCLASSIC || \ @@ -39,59 +50,15 @@ (read_u32_le(context_D.transactionVersion, 0) ^ (1<<31)) >= 0x03 \ ) -#define DEBUG_LONG "%d" - -void check_transaction_available(unsigned char x) { - if (context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", context_D.transactionDataRemaining, x); - THROW(EXCEPTION); - } +static void check_transaction_available(unsigned char x) { + LEDGER_ASSERT(context_D.transactionDataRemaining >= x, "Check transaction available failed %d < %d\n", context_D.transactionDataRemaining, x); } #define OP_HASH160 0xA9 #define OP_EQUAL 0x87 #define OP_CHECKMULTISIG 0xAE -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { - unsigned char carry = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); - carry = (val > 255); - target[8 - 1 - i] = (val & 255); - } - return carry; -} - -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { - unsigned char borrow = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short tmpA = a[8 - 1 - i]; - unsigned short tmpB = b[8 - 1 - i]; - if (borrow) { - if (tmpA <= tmpB) { - tmpA += (255 + 1) - 1; - } else { - borrow = 0; - tmpA--; - } - } - if (tmpA < tmpB) { - borrow = 1; - tmpA += 255 + 1; - } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); - } - - return borrow; -} - -void transaction_offset(unsigned char value) { +static void transaction_offset(unsigned char value) { if ((context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, context_D.transactionBufferPointer); if (context_D.usingOverwinter) { @@ -110,13 +77,13 @@ void transaction_offset(unsigned char value) { } } -void transaction_offset_increase(unsigned char value) { +static void transaction_offset_increase(unsigned char value) { transaction_offset(value); context_D.transactionBufferPointer += value; context_D.transactionDataRemaining -= value; } -unsigned long int transaction_get_varint(void) { +static unsigned long int transaction_get_varint(void) { unsigned char firstByte; check_transaction_available(1); firstByte = *context_D.transactionBufferPointer; @@ -142,17 +109,12 @@ unsigned long int transaction_get_varint(void) { transaction_offset_increase(4); return result; } else { - PRINTF("Varint parsing failed\n"); - THROW(INVALID_PARAMETER); - return 0; + LEDGER_ASSERT(false, "Varint parsing failed"); + __builtin_unreachable(); } } void transaction_parse(unsigned char parseMode) { - unsigned char optionP2SHSkip2FA = - ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); - BEGIN_TRY { - TRY { for (;;) { switch (context_D.transactionContext.transactionState) { case TRANSACTION_NONE: { @@ -334,7 +296,7 @@ void transaction_parse(unsigned char parseMode) { context_D.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); - PRINTF("Number of inputs : " DEBUG_LONG "\n",context_D.transactionContext.transactionRemainingInputsOutputs); + PRINTF("Number of inputs : %d\n", context_D.transactionContext.transactionRemainingInputsOutputs); if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { // remember number of inputs to know when to exit from library // we will count number of already signed inputs and compare with this value @@ -408,14 +370,6 @@ void transaction_parse(unsigned char parseMode) { PRINTF("Invalid trusted input flag\n"); goto fail; } - /* - trustedInputLength = - *(context_D.transactionBufferPointer + 1); - if (trustedInputLength > sizeof(trustedInput)) { - PRINTF("Trusted input too long\n"); - goto fail; - } - */ // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit TI if (trustedInputFlag) { trustedInputLength = *( @@ -514,21 +468,8 @@ void transaction_parse(unsigned char parseMode) { } // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && data[0]==0x00) else if (!trustedInputFlag) { - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - context_D.transactionBufferPointer++; - context_D.transactionDataRemaining--; - check_transaction_available( - 36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - PRINTF("Marking relaxed input\n"); - context_D.transactionContext.relaxed = 1; - /* - PRINTF("Clearing P2SH consumption\n"); - context_D.transactionContext.consumeP2SH = 0; - */ + PRINTF("Untrusted input not authorized\n"); + goto fail; } // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 & data[0]==0x01) else if (trustedInputFlag && !context_D.usingSegwit) { @@ -543,15 +484,6 @@ void transaction_parse(unsigned char parseMode) { // Update the hash with prevout data savePointer = context_D.transactionBufferPointer; - /* - // Check if a P2SH script is used - if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == - 0) { - PRINTF("Clearing P2SH consumption\n"); - context_D.transactionContext.consumeP2SH = - 0; - } - */ context_D.transactionBufferPointer = trustedInput + 4; PRINTF("Trusted input hash\n%.*H\n",36,context_D.transactionBufferPointer); @@ -589,7 +521,7 @@ void transaction_parse(unsigned char parseMode) { // Read the script length context_D.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + PRINTF("Script to read %d\n", context_D.transactionContext.scriptRemaining); if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag && !context_D.usingSegwit) { @@ -598,9 +530,7 @@ void transaction_parse(unsigned char parseMode) { if (context_D.transactionContext .scriptRemaining != 0) { PRINTF("Request to sign relaxed input\n"); - if (!optionP2SHSkip2FA) { - goto fail; - } + goto fail; } } // Move on @@ -611,7 +541,7 @@ void transaction_parse(unsigned char parseMode) { } case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + PRINTF("Process input script, remaining %d\n", context_D.transactionContext.scriptRemaining); if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; @@ -623,11 +553,8 @@ void transaction_parse(unsigned char parseMode) { 1) { if (*context_D.transactionBufferPointer == OP_CHECKMULTISIG) { - if (optionP2SHSkip2FA) { - PRINTF("Marking P2SH consumption\n"); - context_D.transactionContext - .consumeP2SH = 1; - } + PRINTF("Marking P2SH consumption\n"); + context_D.transactionContext.consumeP2SH = 1; } else { // When using the P2SH shortcut, all inputs must use // P2SH @@ -819,7 +746,7 @@ void transaction_parse(unsigned char parseMode) { transaction_get_varint(); context_D.transactionContext .transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : " DEBUG_LONG "\n", + PRINTF("Number of outputs : %d\n", context_D.transactionContext.transactionRemainingInputsOutputs); // Ready to proceed context_D.transactionContext.transactionState = @@ -857,7 +784,7 @@ void transaction_parse(unsigned char parseMode) { context_D.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + PRINTF("Script to read %d\n", context_D.transactionContext.scriptRemaining); // Move on context_D.transactionContext.transactionState = TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; @@ -866,21 +793,7 @@ void transaction_parse(unsigned char parseMode) { } case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); - /* - // Special check if consuming a P2SH script - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - // Assume the full input script is sent in a single APDU, - then do the ghetto validation - if ((context_D.transactionBufferPointer[0] == - OP_HASH160) && - (context_D.transactionBufferPointer[context_D.transactionDataRemaining - - 1] == OP_EQUAL)) { - PRINTF("Marking P2SH output\n"); - context_D.transactionContext.consumeP2SH = 1; - } - } - */ + PRINTF("Process output script, remaining %d\n", context_D.transactionContext.scriptRemaining); if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; @@ -986,20 +899,8 @@ void transaction_parse(unsigned char parseMode) { } fail: - PRINTF("Transaction parse - fail\n"); - THROW(EXCEPTION); - ok : {} - } - CATCH_OTHER(e) { - PRINTF("Transaction parse - surprise fail\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - THROW(e); - } - // before the finally to restore the surrounding context if an exception - // is raised during finally - FINALLY { - } - } - END_TRY; + LEDGER_ASSERT(false, "Transaction parse - fail\n"); + ok: + return; + } diff --git a/include/btchip.h b/lib-app-bitcoin/transaction.h similarity index 67% rename from include/btchip.h rename to lib-app-bitcoin/transaction.h index f53e0e1d..fa88a83b 100644 --- a/include/btchip.h +++ b/lib-app-bitcoin/transaction.h @@ -15,22 +15,19 @@ * limitations under the License. ********************************************************************************/ -#ifndef H +#pragma once -#define H -#include "config.h" -#include "os.h" -#include "os_io_seproxyhal.h" +#define TRANSACTION_HASH_NONE 0x00 +#define TRANSACTION_HASH_FULL 0x01 +#define TRANSACTION_HASH_AUTHORIZATION 0x02 +#define TRANSACTION_HASH_BOTH 0x03 -#include "stdlib.h" -#include "stdbool.h" -#include "string.h" +#define PARSE_MODE_TRUSTED_INPUT 0x01 +#define PARSE_MODE_SIGNATURE 0x02 -#define L_DEBUG_NOPREFIX(x) +#define TRUSTED_INPUT_SIZE 48 +#define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) -#define SW_TECHNICAL_DETAILS(x) SW_TECHNICAL_PROBLEM +void transaction_parse(unsigned char parseMode); -#include "secure_value.h" - -#endif diff --git a/src/display_variables.h b/lib-app-bitcoin/ui/display_variables.h similarity index 87% rename from src/display_variables.h rename to lib-app-bitcoin/ui/display_variables.h index c0ac6f8f..723009ab 100644 --- a/src/display_variables.h +++ b/lib-app-bitcoin/ui/display_variables.h @@ -1,7 +1,7 @@ -#ifndef _DISPLAY_VARIABLES_H_ -#define _DISPLAY_VARIABLES_H_ +#pragma once #include "os.h" + // A path contains 10 elements max, which max length in ascii is 1 whitespace + 10 char + optional quote "'" + "/" + \0" #define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10*(10+2) + 1 #define MAX_CHAR_PER_LINE 25 @@ -26,8 +26,8 @@ union display_variables { // of char fullAddress[65]; // the address - char fullAmount[20]; // full amount - char feesAmount[20]; // fees + char fullAmount[28]; // full amount + char feesAmount[28]; // fees } tmp; struct { @@ -38,5 +38,3 @@ union display_variables { }; extern union display_variables vars; - -#endif diff --git a/src/bagl_extensions.h b/lib-app-bitcoin/ui/extensions.h similarity index 57% rename from src/bagl_extensions.h rename to lib-app-bitcoin/ui/extensions.h index c3029694..7aed64c9 100644 --- a/src/bagl_extensions.h +++ b/lib-app-bitcoin/ui/extensions.h @@ -15,44 +15,40 @@ * limitations under the License. ********************************************************************************/ -#ifndef _BAGL_H_ -#define _BAGL_H_ +#pragma once // btchip asking the per-output UI -unsigned int bagl_confirm_single_output(void); +unsigned int confirm_single_output(void); // btchip display token -void bagl_display_token(void); +void display_token(void); // btchip finalizing the transaction -unsigned int bagl_finalize_tx(void); +unsigned int finalize_tx(void); // UI response to btchip to finish the exchange -unsigned char bagl_user_action(unsigned char confirming); +unsigned char user_action(unsigned char confirming); // request the UI to redisplay the idle screen -void bagl_idle(void); +void idle(void); // btchip asking message signing confirmation -void bagl_confirm_message_signature(void); +void confirm_message_signature(void); // UI response to message signature -void bagl_user_action_message_signing(unsigned char confirming); +int user_action_message_signing(unsigned char confirming); // Public key display -uint8_t set_key_path_to_display(unsigned char* keyPath); -void bagl_display_public_key(uint8_t is_derivation_path_unusual); -void bagl_user_action_display(unsigned char confirming); +uint8_t set_key_path_to_display(const unsigned char* keyPath); +void display_public_key(uint8_t is_derivation_path_unusual); +int user_action_display(unsigned char confirming); -void bagl_request_pubkey_approval(void); -void bagl_request_change_path_approval(unsigned char* change_path); +void request_pubkey_approval(void); +void request_change_path_approval(unsigned char* change_path); // UI to confirm processing of tx with segwit inputs -void bagl_request_segwit_input_approval(void); +void request_segwit_input_approval(void); // UI to confirm signing path -void bagl_request_sign_path_approval(unsigned char *derivation_path); -void bagl_user_action_signtx(unsigned char confirming, unsigned char direct); - - -#endif /* _BAGL_H_ */ +void request_sign_path_approval(unsigned char* change_path); +int user_action_signtx(unsigned char confirming, unsigned char direct); diff --git a/lib-app-bitcoin/ui/main_ui.c b/lib-app-bitcoin/ui/main_ui.c new file mode 100644 index 00000000..850e6016 --- /dev/null +++ b/lib-app-bitcoin/ui/main_ui.c @@ -0,0 +1,311 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "os.h" +#include "cx.h" +#include "format.h" +#include "read.h" +#include "write.h" +#include "bip32.h" +#include "swap.h" +#include "string.h" + + +#include "context.h" +#include "helpers.h" +#include "customizable_helpers.h" +#include "customizable_ui.h" +#include "extensions.h" +#include "display_utils.h" +#include "ux.h" +#include "display_variables.h" +#include "swap_lib_calls.h" +#include "handle_swap_sign_transaction.h" +#include "handle_get_printable_amount.h" +#include "handle_check_address.h" +#include "ui.h" +#include "be_operations.h" + +#define OMNI_ASSETID 1 +#define MAIDSAFE_ASSETID 3 +#define USDT_ASSETID 31 + +static uint8_t check_fee_swap() { + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); + if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) + return 0; + context_D.transactionContext.firstSigned = 0; + + if (context_D.usingSegwit && !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + context_D.sw = 0x9000; + context_D.outLength = 0; + G_io_apdu_buffer[context_D.outLength++] = 0x90; + G_io_apdu_buffer[context_D.outLength++] = 0x00; + + return 1; +} + +#define OMNI_ASSETID 1 +#define MAIDSAFE_ASSETID 3 +#define USDT_ASSETID 31 + +static void prepare_single_output(void) { + // TODO : special display for OP_RETURN + unsigned char amount[8]; + unsigned int offset = 0; + char tmp[80] = {0}; + + swap_bytes(amount, context_D.currentOutput + offset, 8); + offset += 8; + + get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); + strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); + + // Prepare amount + + // Handle Omni simple send + if ((context_D.currentOutput[offset + 2] == 0x14) && + (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + uint32_t omniAssetId = read_u32_be(context_D.currentOutput, offset + 3 + 4 + 4); + switch(omniAssetId) { + case OMNI_ASSETID: + strcpy(vars.tmp.fullAmount, "OMNI "); + break; + case USDT_ASSETID: + strcpy(vars.tmp.fullAmount, "USDT "); + break; + case MAIDSAFE_ASSETID: + strcpy(vars.tmp.fullAmount, "MAID "); + break; + default: + snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); + break; + } + format_sats_amount(vars.tmp.fullAmount, + (uint64_t) read_u64_be(context_D.currentOutput, offset + 3 + 4 + 4 + 4), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } + else { + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)read_u64_be(amount, 0), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } +} + +static uint8_t prepare_message_signature(void) { + uint8_t buffer[32]; + + if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, + (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { + return 0; + } + + format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); + + return 1; +} + + +extern int handle_output_state(unsigned int* processed); +extern void hash_input_finalize_full_reset(void); + +// Analog of confirm_single_output to work +// in silent mode, when called from SWAP app +unsigned int silent_confirm_single_output() { + char tmp[80] = {0}; + unsigned char amount[8]; + while (true) { + // in swap operation we can only have 1 "external" output + if (vars.swap_data.was_address_checked) { + PRINTF("Address was already checked\n"); + return 0; + } + vars.swap_data.was_address_checked = 1; + // check amount + swap_bytes(amount, context_D.currentOutput, 8); + if (memcmp(amount, vars.swap_data.amount, 8) != 0) { + PRINTF("Amount not matched\n"); + return 0; + } + get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); + if (strcmp(tmp, vars.swap_data.destination_address) != 0) { + PRINTF("Address not matched\n"); + return 0; + } + + // Check if all inputs have been confirmed + + if (context_D.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context_D.remainingOutputs--; + if (context_D.remainingOutputs == 0) + break; + } + + memmove(context_D.currentOutput, + context_D.currentOutput + + context_D.discardSize, + context_D.currentOutputOffset - + context_D.discardSize); + context_D.currentOutputOffset -= context_D.discardSize; + unsigned int processed = true; + while (processed == 1) { + if (handle_output_state(&processed)) { + PRINTF("Error in handle output state \n"); + return 0; + } + } + + if (processed != 2) { + // Out of data to process, wait for the next call + break; + } + } + + if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context_D.remainingOutputs == 0)) { + context_D.outputParsingState = OUTPUT_FINALIZE_TX; + // check fees + unsigned char fees[8]; + + if ((transaction_amount_sub_be(fees, + context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount) != 0) || + (memcmp(fees, vars.swap_data.fees, 8) != 0)) { + PRINTF("Fees is not matched\n"); + return 0; + } + } + + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + context_D.transactionContext.firstSigned = 0; + + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + } + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + // we've finished the processing of the input + hash_input_finalize_full_reset(); + } + + return 1; +} + +unsigned int confirm_single_output(void) { + if (G_called_from_swap) { + if (silent_confirm_single_output()) { + return 2; + } + return 0; + } + prepare_single_output(); + + ui_confirm_single_flow(); + return 1; +} + +unsigned int finalize_tx(void) { + if (G_called_from_swap) { + if (check_fee_swap()) { + return 2; + } + } + + if (!prepare_fees()) { + return 0; + } + + ui_finalize_flow(); + return 1; +} + +void confirm_message_signature(void) { + if (!prepare_message_signature()) { + return; + } + + ui_sign_message_flow(); +} + +uint8_t set_key_path_to_display(const unsigned char* keyPath) { + format_path(keyPath, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + return bip44_derivation_guard(keyPath, false); +} + +void display_public_key(uint8_t is_derivation_path_unusual) { + // append a white space at the end of the address to avoid glitch on nano S + strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); + + if (is_derivation_path_unusual) { + ui_display_public_with_warning_flow(); + } + else { + ui_display_public_flow(); + } +} + +void display_token(void) +{ + ui_display_token_flow(); +} + +void request_pubkey_approval(void) +{ + ui_request_pubkey_approval_flow(); +} + +void request_change_path_approval(unsigned char* change_path) +{ + format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_change_path_approval_flow(); +} + +void request_sign_path_approval(unsigned char* change_path) +{ + format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_sign_path_approval_flow(); +} + +void request_segwit_input_approval(void) +{ + ui_request_segwit_input_approval_flow(); +} + + diff --git a/src/ui.h b/lib-app-bitcoin/ui/ui.h similarity index 100% rename from src/ui.h rename to lib-app-bitcoin/ui/ui.h diff --git a/src/ui_bagl.c b/lib-app-bitcoin/ui/ui_bagl.c similarity index 97% rename from src/ui_bagl.c rename to lib-app-bitcoin/ui/ui_bagl.c index 6c4ee66e..a7e0e1b8 100644 --- a/src/ui_bagl.c +++ b/lib-app-bitcoin/ui/ui_bagl.c @@ -18,17 +18,18 @@ #ifdef HAVE_BAGL ////////////////////////////////////////////////////////////////////// #include "display_variables.h" -#include "internal.h" +#include "transaction.h" +#include "context.h" #include "ui.h" -#include "bagl_extensions.h" +#include "extensions.h" bagl_element_t tmp_element; static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - if (!bagl_user_action(0)) { + if (!user_action(0)) { // redraw ui ui_idle_flow(); } @@ -38,7 +39,7 @@ static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - if (!bagl_user_action(1)) { + if (!user_action(1)) { // redraw ui ui_idle_flow(); } @@ -49,7 +50,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_message_signing(0); + user_action_message_signing(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -59,7 +60,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_message_signing(1); + user_action_message_signing(1); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -69,7 +70,7 @@ static unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_display(0); + user_action_display(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -78,16 +79,15 @@ io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_display(1); // redraw ui ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON + return user_action_display(1); } static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_signtx(0, 0); + user_action_signtx(0, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -96,7 +96,7 @@ static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_signtx(1, 0); + user_action_signtx(1, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -107,8 +107,7 @@ void io_seproxyhal_display(const bagl_element_t *element) { io_seproxyhal_display_default((bagl_element_t *)element); } } - -////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_idle_flow_1_step, nn, { "Application", diff --git a/src/ui_menu_nbgl.c b/lib-app-bitcoin/ui/ui_menu_nbgl.c similarity index 97% rename from src/ui_menu_nbgl.c rename to lib-app-bitcoin/ui/ui_menu_nbgl.c index 20b865e6..de876fc7 100644 --- a/src/ui_menu_nbgl.c +++ b/lib-app-bitcoin/ui/ui_menu_nbgl.c @@ -17,10 +17,9 @@ #ifdef HAVE_NBGL #include "display_variables.h" -#include "internal.h" #include "ui.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "nbgl_use_case.h" #define NB_INFO_FIELDS 2 diff --git a/src/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c similarity index 97% rename from src/ui_nbgl.c rename to lib-app-bitcoin/ui/ui_nbgl.c index ee41f795..642b8747 100644 --- a/src/ui_nbgl.c +++ b/lib-app-bitcoin/ui/ui_nbgl.c @@ -19,9 +19,9 @@ #include "ui.h" #include "nbgl_use_case.h" #include "display_variables.h" -#include "internal.h" +#include "context.h" -#include "bagl_extensions.h" +#include "extensions.h" typedef enum { MESSAGE_TYPE, @@ -55,55 +55,55 @@ static UiContext_t uiContext = {.transaction_prompt_done = 0}; // User action callbacks static void approved_user_action_callback(void) { - if (!bagl_user_action(1)) { + if (!user_action(1)) { ui_idle_flow(); } } static void approved_user_action_processing_callback(void) { - if (!bagl_user_action(1)) { + if (!user_action(1)) { nbgl_useCaseSpinner("Processing"); } } static void abandon_user_action_callback(void) { - if (!bagl_user_action(0)) { + if (!user_action(0)) { ui_idle_flow(); } } static void approved_user_action_message_signing_callback(void) { - bagl_user_action_message_signing(1); + user_action_message_signing(1); ui_idle_flow(); } static void abandon_user_action_message_signing_callback(void) { - bagl_user_action_message_signing(0); + user_action_message_signing(0); ui_idle_flow(); } static void approved_user_action_display_processing_callback(void) { - bagl_user_action_display(1); + user_action_display(1); nbgl_useCaseSpinner("Processing"); } static void approved_user_action_display_callback(void) { - bagl_user_action_display(1); + user_action_display(1); ui_idle_flow(); } static void abandon_user_action_display_callback(void) { - bagl_user_action_display(0); + user_action_display(0); ui_idle_flow(); } static void approved_user_action_signtx_callback(void) { - bagl_user_action_signtx(1, 0); + user_action_signtx(1, 0); ui_idle_flow(); } static void abandon_user_action_signtx_callback(void) { - bagl_user_action_signtx(0, 0); + user_action_signtx(0, 0); ui_idle_flow(); } @@ -479,7 +479,7 @@ static void prompt_public_key(bool warning) { } } -static void display_public_key(bool warning) { +static void display_show_public_key(bool warning) { uiContext.abandon_status = "Address verification\ncancelled"; uiContext.approved_status = "ADDRESS\nVERIFIED"; uiContext.prompt_cancel_message = "Reject\nAddress?"; @@ -507,11 +507,11 @@ static void display_public_key(bool warning) { } void ui_display_public_with_warning_flow(void) { - display_public_key(true); + display_show_public_key(true); } void ui_display_public_flow(void) { - display_public_key(false); + display_show_public_key(false); } void ui_transaction_finish(void) { diff --git a/lib-app-bitcoin/utils/be_operations.c b/lib-app-bitcoin/utils/be_operations.c new file mode 100644 index 00000000..43c916e3 --- /dev/null +++ b/lib-app-bitcoin/utils/be_operations.c @@ -0,0 +1,42 @@ +#include "be_operations.h" + +unsigned char transaction_amount_add_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { + unsigned char carry = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); + carry = (val > 255); + target[8 - 1 - i] = (val & 255); + } + return carry; +} + +unsigned char transaction_amount_sub_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { + unsigned char borrow = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short tmpA = a[8 - 1 - i]; + unsigned short tmpB = b[8 - 1 - i]; + if (borrow) { + if (tmpA <= tmpB) { + tmpA += (255 + 1) - 1; + } else { + borrow = 0; + tmpA--; + } + } + if (tmpA < tmpB) { + borrow = 1; + tmpA += 255 + 1; + } + target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + } + + return borrow; +} + + diff --git a/src/transaction.h b/lib-app-bitcoin/utils/be_operations.h similarity index 71% rename from src/transaction.h rename to lib-app-bitcoin/utils/be_operations.h index 01b50048..8dc7a9a2 100644 --- a/src/transaction.h +++ b/lib-app-bitcoin/utils/be_operations.h @@ -15,23 +15,7 @@ * limitations under the License. ********************************************************************************/ -#ifndef _TRANSACTION_H_ -#define _TRANSACTION_H_ - -#include "secure_value.h" - -#define TRANSACTION_HASH_NONE 0x00 -#define TRANSACTION_HASH_FULL 0x01 -#define TRANSACTION_HASH_AUTHORIZATION 0x02 -#define TRANSACTION_HASH_BOTH 0x03 - -#define PARSE_MODE_TRUSTED_INPUT 0x01 -#define PARSE_MODE_SIGNATURE 0x02 - -#define TRUSTED_INPUT_SIZE 48 -#define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) - -void transaction_parse(unsigned char parseMode); +#pragma once // target = a + b unsigned char transaction_amount_add_be(unsigned char *target, @@ -42,5 +26,3 @@ unsigned char transaction_amount_add_be(unsigned char *target, unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b); - -#endif /* _TRANSACTION_H_ */ diff --git a/src/cashaddr.c b/lib-app-bitcoin/utils/cashaddr.c similarity index 100% rename from src/cashaddr.c rename to lib-app-bitcoin/utils/cashaddr.c diff --git a/src/cashaddr.h b/lib-app-bitcoin/utils/cashaddr.h similarity index 100% rename from src/cashaddr.h rename to lib-app-bitcoin/utils/cashaddr.h diff --git a/src/segwit_addr.c b/lib-app-bitcoin/utils/segwit_addr.c similarity index 100% rename from src/segwit_addr.c rename to lib-app-bitcoin/utils/segwit_addr.c diff --git a/src/segwit_addr.h b/lib-app-bitcoin/utils/segwit_addr.h similarity index 100% rename from src/segwit_addr.h rename to lib-app-bitcoin/utils/segwit_addr.h diff --git a/src/apdu_get_wallet_public_key.h b/src/apdu_get_wallet_public_key.h deleted file mode 100644 index 429076d6..00000000 --- a/src/apdu_get_wallet_public_key.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _APDU_GET_WALLET_PUBLIC_KEY_H_ -#define _APDU_GET_WALLET_PUBLIC_KEY_H_ - -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 -#define P1_REQUEST_TOKEN 0x02 - -#define P2_LEGACY 0x00 -#define P2_SEGWIT 0x01 -#define P2_NATIVE_SEGWIT 0x02 -#define P2_CASHADDR 0x03 - -#endif //_APDU_GET_WALLET_PUBLIC_KEY_H_ \ No newline at end of file diff --git a/src/bcd.c b/src/bcd.c deleted file mode 100644 index a7878d0b..00000000 --- a/src/bcd.c +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#define SCRATCH_SIZE 21 - -unsigned char -convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out) { - unsigned char LOOP1; - unsigned char LOOP2; - if (!(config_flag & FLAG_PEERCOIN_UNITS)) { - LOOP1 = 13; - LOOP2 = 8; - } else { - LOOP1 = 15; - LOOP2 = 6; - } - unsigned short scratch[SCRATCH_SIZE]; - unsigned char offset = 0; - unsigned char nonZero = 0; - unsigned char i; - unsigned char targetOffset = 0; - unsigned char workOffset; - unsigned char j; - unsigned char nscratch = SCRATCH_SIZE; - unsigned char smin = nscratch - 2; - unsigned char comma = 0; - - for (i = 0; i < SCRATCH_SIZE; i++) { - scratch[i] = 0; - } - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - unsigned char k; - unsigned short shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 - : (short)0; - for (k = smin; k < nscratch; k++) { - scratch[k] += ((scratch[k] >= 5) ? 3 : 0); - } - if (scratch[smin] >= 8) { - smin -= 1; - } - for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); - } - scratch[nscratch - 1] = ((scratch[nscratch - 1] << 1) & 0x0F) | - (shifted_in == 1 ? 1 : 0); - } - } - - for (i = 0; i < LOOP1; i++) { - if (!nonZero && (scratch[offset] == 0)) { - offset++; - } else { - nonZero = 1; - out[targetOffset++] = scratch[offset++] + '0'; - } - } - if (targetOffset == 0) { - out[targetOffset++] = '0'; - } - workOffset = offset; - for (i = 0; i < LOOP2; i++) { - unsigned char allZero = 1; - for (j = i; j < LOOP2; j++) { - if (scratch[workOffset + j] != 0) { - allZero = 0; - break; - } - } - if (allZero) { - break; - } - if (!comma) { - out[targetOffset++] = '.'; - comma = 1; - } - out[targetOffset++] = scratch[offset++] + '0'; - } - return targetOffset; -} - -unsigned char -convert_hex_amount_to_displayable(unsigned char *amount) { - return convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, context_D.tmp); -} diff --git a/src/bip32_path.c b/src/bip32_path.c deleted file mode 100644 index 8be5d787..00000000 --- a/src/bip32_path.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "lib_standard_app/read.h" -#include "bip32_path.h" -#include "helpers.h" - -bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, unsigned char serialized_path_length) { - if (serialized_path_length < 1 || - serialized_path[0] > MAX_BIP32_PATH || - serialized_path[0] * 4 + 1 > serialized_path_length) - return false; - path->length = serialized_path[0]; - serialized_path++; - for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = read_u32_be(serialized_path, 0); - } - return true; -} diff --git a/src/bip32_path.h b/src/bip32_path.h deleted file mode 100644 index 819ea8c9..00000000 --- a/src/bip32_path.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _BIP32_PATH_H_ -#define _BIP32_PATH_H_ - -#include "stdbool.h" - -#define MAX_BIP32_PATH 10 -#define MAX_BIP32_PATH_LENGTH (4 * MAX_BIP32_PATH) + 1 - -typedef struct bip32_path { - unsigned char length; - unsigned int path[MAX_BIP32_PATH]; -} bip32_path_t; - -bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, unsigned char serialized_path_length); - -#endif \ No newline at end of file diff --git a/src/btchip.c b/src/btchip.c deleted file mode 100644 index 2d65d16f..00000000 --- a/src/btchip.c +++ /dev/null @@ -1,606 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#include "os.h" -#include "cx.h" - -#include "string.h" - -#include "internal.h" - -#include "bagl_extensions.h" - -#include "segwit_addr.h" -#include "cashaddr.h" - -#include "ux.h" -#include "display_variables.h" -#include "swap_lib_calls.h" - -#include "handle_swap_sign_transaction.h" -#include "handle_get_printable_amount.h" -#include "handle_check_address.h" -#include "ui.h" -#include "lib_standard_app/format.h" -#include "read.h" -#include "write.h" -#include "bip32.h" -#include "swap.h" - -unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); - } - return 0; -} - -unsigned char io_event(unsigned char channel) { - UNUSED(channel); - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { -#ifdef HAVE_NBGL - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif // HAVE_NBGL - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: -#ifdef HAVE_BAGL - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); -#endif // HAVE_BAGL - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#ifdef HAVE_BAGL - UX_DISPLAYED_EVENT({}); -#endif // HAVE_BAGL -#ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif // HAVE_NBGL - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - // TODO: found less hacky way to exit library after sending response - // this mechanism is used for Swap/Exchange functionality - // when application is in silent mode, and should return to caller, - // after responding some APDUs - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; -} - -uint8_t check_fee_swap() { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) - return 0; - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - context_D.sw = 0x9000; - context_D.outLength = 0; - G_io_apdu_buffer[context_D.outLength++] = 0x90; - G_io_apdu_buffer[context_D.outLength++] = 0x00; - - return 1; -} - -uint8_t prepare_fees(void) { - if (context_D.transactionContext.relaxed) { - memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned short textSize; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if (borrow && COIN_KIND == COIN_KIND_KOMODO) { - memmove(vars.tmp.feesAmount, "REWARD", 6); - vars.tmp.feesAmount[6] = '\0'; - } - else { - if (borrow) { - PRINTF("Error : Fees not consistent"); - goto error; - } - memmove(vars.tmp.feesAmount, COIN_COINID_SHORT, - strlen(COIN_COINID_SHORT)); - vars.tmp.feesAmount[strlen(COIN_COINID_SHORT)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - strlen(COIN_COINID_SHORT) + 1); - textSize = convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = - '\0'; - } - } - return 1; -error: - return 0; -} - -#define OMNI_ASSETID 1 -#define MAIDSAFE_ASSETID 3 -#define USDT_ASSETID 31 - -void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { - if (output_script_is_op_return(script)) { - strncpy(out, "OP_RETURN", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_create(script, script_size)) { - strncpy(out, "OP_CREATE", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_call(script, script_size)) { - strncpy(out, "OP_CALL", out_size); - return; - } - if (output_script_is_native_witness(script)) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - segwit_addr_encode( - out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, - script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, - script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); - } - return; - } - unsigned char versionSize; - unsigned char address[22]; - unsigned short textSize; - int addressOffset = 3; - unsigned short version = COIN_P2SH_VERSION; - - if (output_script_is_regular(script)) { - addressOffset = 4; - version = COIN_P2PKH_VERSION; - } - - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - memmove(address + versionSize, script + addressOffset, 20); - - // Prepare address - if (context_D.usingCashAddr) { - cashaddr_encode( - address + versionSize, 20, (uint8_t *)out, out_size, - (version == COIN_P2SH_VERSION - ? CASHADDR_P2SH - : CASHADDR_P2PKH)); - } else { - textSize = public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)out, - out_size, version, 1); - out[textSize] = '\0'; - } -} - -uint8_t prepare_single_output(void) { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - unsigned int offset = 0; - unsigned short textSize; - char tmp[80] = {0}; - - swap_bytes(amount, context_D.currentOutput + offset, 8); - offset += 8; - - get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); - strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); - - // Prepare amount - - // Handle Omni simple send - if ((context_D.currentOutput[offset + 2] == 0x14) && - (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { - uint8_t headerLength; - uint32_t omniAssetId = read_u32_be(context_D.currentOutput, offset + 3 + 4 + 4); - switch(omniAssetId) { - case OMNI_ASSETID: - strcpy(vars.tmp.fullAmount, "OMNI "); - break; - case USDT_ASSETID: - strcpy(vars.tmp.fullAmount, "USDT "); - break; - case MAIDSAFE_ASSETID: - strcpy(vars.tmp.fullAmount, "MAID "); - break; - default: - snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); - break; - } - headerLength = strlen(vars.tmp.fullAmount); - context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; - textSize = convert_hex_amount_to_displayable(context_D.currentOutput + offset + 3 + 4 + 4 + 4); - vars.tmp.fullAmount[textSize + headerLength] = '\0'; - } - else { - memmove(vars.tmp.fullAmount, COIN_COINID_SHORT, - strlen(COIN_COINID_SHORT)); - vars.tmp.fullAmount[strlen(COIN_COINID_SHORT)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - strlen(COIN_COINID_SHORT) + 1); - textSize = convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = - '\0'; - } - - return 1; -} - -uint8_t prepare_message_signature(void) { - uint8_t buffer[32]; - - if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, - (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { - return 0; - } - - format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); - - return 1; -} - - -extern bool handle_output_state(void); -extern void apdu_hash_input_finalize_full_reset(void); - -// Analog of bagl_confirm_single_output to work -// in silent mode, when called from SWAP app -unsigned int silent_confirm_single_output() { - char tmp[80] = {0}; - unsigned char amount[8]; - while (true) { - // in swap operation we can only have 1 "external" output - if (vars.swap_data.was_address_checked) { - PRINTF("Address was already checked\n"); - return 0; - } - vars.swap_data.was_address_checked = 1; - // check amount - swap_bytes(amount, context_D.currentOutput, 8); - if (memcmp(amount, vars.swap_data.amount, 8) != 0) { - PRINTF("Amount not matched\n"); - return 0; - } - get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); - if (strcmp(tmp, vars.swap_data.destination_address) != 0) { - PRINTF("Address not matched\n"); - return 0; - } - - // Check if all inputs have been confirmed - - if (context_D.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context_D.remainingOutputs--; - if (context_D.remainingOutputs == 0) - break; - } - - memmove(context_D.currentOutput, - context_D.currentOutput + - context_D.discardSize, - context_D.currentOutputOffset - - context_D.discardSize); - context_D.currentOutputOffset -= context_D.discardSize; - context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (!(context_D.io_flags & IO_ASYNCH_REPLY)) { - // Out of data to process, wait for the next call - break; - } - } - - if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context_D.remainingOutputs == 0)) { - context_D.outputParsingState = OUTPUT_FINALIZE_TX; - // check fees - unsigned char fees[8]; - - if ((transaction_amount_sub_be(fees, - context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount) != 0) || - (memcmp(fees, vars.swap_data.fees, 8) != 0)) { - PRINTF("Fees is not matched\n"); - return 0; - } - } - - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - } - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - // we've finished the processing of the input - apdu_hash_input_finalize_full_reset(); - } - - return 1; -} - -unsigned int bagl_confirm_single_output(void) { - if (G_called_from_swap) { - return silent_confirm_single_output(); - } - if (!prepare_single_output()) { - return 0; - } - - ui_confirm_single_flow(); - return 1; -} - -unsigned int bagl_finalize_tx(void) { - if (G_called_from_swap) { - return check_fee_swap(); - } - - if (!prepare_fees()) { - return 0; - } - - ui_finalize_flow(); - return 1; -} - -void bagl_confirm_message_signature(void) { - if (!prepare_message_signature()) { - return; - } - - ui_sign_message_flow(); -} - -uint8_t set_key_path_to_display(unsigned char* keyPath) { - bip32_print_path(keyPath, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); - return bip44_derivation_guard(keyPath, false); -} - -void bagl_display_public_key(uint8_t is_derivation_path_unusual) { - // append a white space at the end of the address to avoid glitch on nano S - strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); - - if (is_derivation_path_unusual) { - ui_display_public_with_warning_flow(); - } - else { - ui_display_public_flow(); - } -} - -void bagl_display_token(void) -{ - ui_display_token_flow(); -} - -void bagl_request_pubkey_approval(void) -{ - ui_request_pubkey_approval_flow(); -} - -void bagl_request_change_path_approval(unsigned char* change_path) -{ - - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_change_path_approval_flow(); -} - -void bagl_request_sign_path_approval(unsigned char* change_path) -{ - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_sign_path_approval_flow(); -} - -void bagl_request_segwit_input_approval(void) -{ - ui_request_segwit_input_approval_flow(); -} - - -#include "os.h" - -#include "internal.h" - -#include "os_io_seproxyhal.h" - -#include "apdu_constants.h" -#include "display_variables.h" - -#include "handle_swap_sign_transaction.h" - -#define TECHNICAL_NOT_IMPLEMENTED 0x99 - -#define COMMON_CLA 0xB0 - -void app_dispatch(void) { - unsigned char cla; - unsigned char ins; - unsigned char dispatched; - - // nothing to reply for now - context_D.outLength = 0; - context_D.io_flags = 0; - - cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; - ins = G_io_apdu_buffer[ISO_OFFSET_INS]; - for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && - (ins == DISPATCHER_INS[dispatched])) { - break; - } - } - if (dispatched == DISPATCHER_APDUS) { - context_D.sw = SW_INS_NOT_SUPPORTED; - goto sendSW; - } - if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - context_D.inLength - 5 == 0) { - context_D.sw = SW_INCORRECT_LENGTH; - goto sendSW; - } - // notify we need to receive data - // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); - } - // call the apdu handler - context_D.sw = ((apduProcessingFunction)PIC( - DISPATCHER_FUNCTIONS[dispatched]))(); - - // an APDU has been replied. request for power off time extension from the - // common ux -#ifdef IO_APP_ACTIVITY - IO_APP_ACTIVITY(); -#endif // IO_APP_ACTIVITY - -sendSW: - if (G_called_from_swap) { - context_D.io_flags &= ~IO_ASYNCH_REPLY; - if(context_D.sw != SW_OK) { - vars.swap_data.should_exit = 1; - } - } - // prepare SW after replied data - G_io_apdu_buffer[context_D.outLength] = - (context_D.sw >> 8); - G_io_apdu_buffer[context_D.outLength + 1] = - (context_D.sw & 0xff); - context_D.outLength += 2; - return; -} - -void app_main(void) { - context_init(); - - ui_idle_flow(); - - memset(G_io_apdu_buffer, 0, 255); // paranoia - - // Process the incoming APDUs - - // first exchange, no out length :) only wait the apdu - context_D.outLength = 0; - context_D.io_flags = 0; - for (;;) { - - // memset(G_io_apdu_buffer, 0, 255); // paranoia - - if (G_called_from_swap && vars.swap_data.should_exit) { - context_D.io_flags |= IO_RETURN_AFTER_TX; - } - - // receive the whole apdu using the 7 bytes headers (ledger transport) - context_D.inLength = - io_exchange(CHANNEL_APDU | context_D.io_flags, - // use the previous outlength as the reply - context_D.outLength); - - if (G_called_from_swap && vars.swap_data.should_exit) { - swap_finalize_exchange_sign_transaction(context_D.sw == SW_OK); - } - - PRINTF("New APDU received:\n%.*H\n", context_D.inLength, G_io_apdu_buffer); - - app_dispatch(); - - // reply during reception of next apdu - } - - PRINTF("End of main loop\n"); - - // in case reached - reset(); -} diff --git a/src/ecc.c b/src/ecc.c deleted file mode 100644 index 69092c81..00000000 --- a/src/ecc.c +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -void compress_public_key_value(unsigned char *value) { - value[0] = ((value[64] & 1) ? 0x03 : 0x02); -} diff --git a/src/helpers.c b/src/helpers.c deleted file mode 100644 index 605acb06..00000000 --- a/src/helpers.c +++ /dev/null @@ -1,407 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" -#include "lib_standard_app/crypto_helpers.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/base58.h" -#include "bip32_path.h" -#include "ledger_assert.h" - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x3D, 0xA9, - 0x14}; // script length, OP_HASH160, address length - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { - 0x87, // OP_EQUAL - 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, - 0x1C, 0x03, 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, - 0xBA, 0x97, 0xF0, 0xE3, 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, - 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xB4}; // OP_CHECKBLOCKATHEIGHT - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; - -const unsigned char ZEN_OUTPUT_SCRIPT_PRE[] = { - 0x3F, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC, // OP_EQUALVERIFY, OP_CHECKSIG - 0x20, 0x9e, 0xc9, 0x84, 0x5a, 0xcb, 0x02, 0xfa, 0xb2, 0x4e, 0x1c, 0x03, - 0x68, 0xb3, 0xb5, 0x17, 0xc1, 0xa4, 0x48, 0x8f, 0xba, 0x97, 0xf0, 0xe3, - 0x45, 0x9a, 0xc0, 0x53, 0xea, 0x01, 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xc0, 0x1f, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xb4 // OP_CHECKBLOCKATHEIGHT -}; // BIP0115 Replay Protection - -unsigned char output_script_is_regular(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, - sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, - ZEN_OUTPUT_SCRIPT_POST, - sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - } - - return 0; -} - -unsigned char output_script_is_p2sh(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - } - return 0; -} - -unsigned char output_script_is_native_witness(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - return 0; -} - -unsigned char output_script_is_op_return(unsigned char *buffer) { - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); - } - else { - return (buffer[1] == 0x6A); - } -} - -static unsigned char output_script_is_op_create_or_call(unsigned char *buffer, - size_t size, - unsigned char value) { - return (!output_script_is_regular(buffer) && - !output_script_is_p2sh(buffer) && - !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && - (buffer[0] < size) && - (buffer[buffer[0]] == value)); -} - -unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC1); -} - -unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC2); -} - -void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char *out) { - cx_ripemd160_t riprip; - unsigned char buffer[32]; - cx_hash_sha256(in, inlen, buffer, 32); - cx_ripemd160_init(&riprip); - LEDGER_ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20) == CX_OK, "hash160"); -} - -void compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { - unsigned char checksumBuffer[32]; - cx_hash_sha256(in, inlen, checksumBuffer, 32); - cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); - - PRINTF("Checksum\n%.*H\n",4,checksumBuffer); - memmove(output, checksumBuffer, 4); -} - -unsigned short public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, - unsigned char alreadyHashed) { - unsigned char tmpBuffer[34]; - - unsigned char versionSize = (version > 255 ? 2 : 1); - size_t outputLen; - - if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n",inlen,in); - public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); - if (version > 255) { - tmpBuffer[0] = (version >> 8); - tmpBuffer[1] = version; - } else { - tmpBuffer[0] = version; - } - } else { - memmove(tmpBuffer, in, 20 + versionSize); - } - - compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); - - outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); - if (outputLen < 0) { - THROW(EXCEPTION); - } - return outputLen; -} - -void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { - unsigned char i; - for (i = 0; i < size; i++) { - target[i] = source[size - 1 - i]; - } -} - -/* -Checks if the values of a derivation path are within "normal" (arbitrary) ranges: -Account < 100, change == 1 or 0, address index < 50000 -Returns 1 if the path is unusual, or not compliant with BIP44*/ -unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { - - unsigned char path_len; - bip32_path_t bip32PathInt; - - path_len = bip32Path[0]; - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning - if(path_len != BIP44_PATH_LEN || - ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { - return 1; - } - - // If the coin type doesn't match, return a warning - if ((BIP44_COIN_TYPE != 0) && - (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { - return 1; - } - - // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { - return 1; - } - - return 0; -} - -/* -Only enforce the structure or coin type for consumed UTXOs or a public address -Returns 0 if the path is non compliant, or 1 if compliant -*/ -unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) { - bip32_path_t bip32PathInt; - // No enforcement required - if (BIP44_COIN_TYPE == 0) { - return 1; - } - // Path is too short - always require a user validation if signing - if (bip32Path[0] < 2) { - return for_pubkey; - } - - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // Path is not compliant with BIP 44 or derivatives - valid if not signing - if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { - return for_pubkey; - } - - if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { - // Valid BIP 44 path - return 1; - } - // Everything else needs a user validation - return 0; -} - -// Print a BIP32 path as an ascii string to display on the device screen -// On the Ledger Blue, if the string is longer than 30 char, the string will be split in multiple lines -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len) { - - unsigned char bip32PathLength; - unsigned char i, offset; - unsigned int current_level; - bool hardened; - - bip32PathLength = bip32Path[0]; - if (bip32PathLength > MAX_BIP32_PATH) { - THROW(INVALID_PARAMETER); - } - bip32Path++; - out[0] = ' '; - offset=1; - for (i = 0; i < bip32PathLength; i++) { - current_level = read_u32_be(bip32Path, 0); - hardened = (bool)(current_level & 0x80000000); - if(hardened) { - //remove hardening flag - current_level ^= 0x80000000; - } - bip32Path += 4; - snprintf(out+offset, max_out_len-offset, "%u", current_level); - offset = strnlen(out, max_out_len); - if(offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); - if(hardened) out[offset++] = '\''; - - out[offset++] = '/'; - out[offset] = '\0'; - } - // remove last '/' - out[offset-1] = '\0'; - - return offset -1; -} - -void transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh) { - const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE - : TRANSACTION_OUTPUT_SCRIPT_PRE); - const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST - : TRANSACTION_OUTPUT_SCRIPT_POST); - unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); - unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); - if (amount != NULL) { - swap_bytes(context_D.tmp, amount, 8); - context_D.tmp += 8; - } - memmove(context_D.tmp, (void *)pre, sizePre); - context_D.tmp += sizePre; - memmove(context_D.tmp, hash160Address, 20); - context_D.tmp += 20; - memmove(context_D.tmp, (void *)post, sizePost); - context_D.tmp += sizePost; -} - - -int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen, - unsigned char rfc6979) { - - unsigned int info = 0; - - io_seproxyhal_io_heartbeat(); - - bip32_path_t bip32Path; - bip32Path.length = path[0]; - - if (!parse_serialized_path(&bip32Path, path, path_len)) { - return -1; - } - - if (bip32_derive_ecdsa_sign_hash_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, - in, - inlen, - out, - outlen, - &info) != CX_OK) { - return -1; - } - - // Store information about the parity of the 'y' coordinate - if (info & CX_ECCINFO_PARITY_ODD) { - out[0] |= 0x01; - } - - io_seproxyhal_io_heartbeat(); - return 0; -} - -int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { - - bip32_path_t bip32Path; - - if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { - return -1; - } - - if (bip32_derive_get_pubkey_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - raw_pubkey, - chainCode, - CX_SHA512) != CX_OK) - { - return -1; - } - - return 0; -} diff --git a/src/internal.h b/src/internal.h deleted file mode 100644 index 1b84471e..00000000 --- a/src/internal.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef INTERNAL_H -#define INTERNAL_H - -#include "btchip.h" -#include "public_ram_variables.h" -#include "rom_variables.h" -#include "filesystem.h" -#include "bcd.h" -#include "ecc.h" -#include "helpers.h" -#include "transaction.h" - -#endif diff --git a/src/nvram.c b/src/nvram.c deleted file mode 100644 index a956708f..00000000 --- a/src/nvram.c +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#include "public_ram_variables.h" - -storage_t const N_real; diff --git a/src/public_ram_variables.c b/src/public_ram_variables.c deleted file mode 100644 index a0acc359..00000000 --- a/src/public_ram_variables.c +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "public_ram_variables.h" - -context_t context_D; - diff --git a/src/rom_variables.c b/src/rom_variables.c deleted file mode 100644 index 375e3d86..00000000 --- a/src/rom_variables.c +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', - 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; - -unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0 }; -unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -unsigned char const DISPATCHER_CLA[] = { - CLA, // apdu_get_wallet_public_key, - CLA, // apdu_get_trusted_input, - CLA, // apdu_hash_input_start, - CLA, // apdu_hash_sign, - CLA, // apdu_hash_input_finalize_full, - CLA, // apdu_sign_message, - CLA, // apdu_get_firmware_version, - CLA, // apdu_get_coin_version -}; - -unsigned char const DISPATCHER_INS[] = { - INS_GET_WALLET_PUBLIC_KEY, // apdu_get_wallet_public_key, - INS_GET_TRUSTED_INPUT, // apdu_get_trusted_input, - INS_HASH_INPUT_START, // apdu_hash_input_start, - INS_HASH_SIGN, // apdu_hash_sign, - INS_HASH_INPUT_FINALIZE_FULL, // apdu_hash_input_finalize_full, - INS_SIGN_MESSAGE, // apdu_sign_message, - INS_GET_FIRMWARE_VERSION, // apdu_get_firmware_version, - INS_GET_COIN_VER, // apdu_get_coin_version -}; - -unsigned char const DISPATCHER_DATA_IN[] = { - 1, // apdu_get_wallet_public_key, - 1, // apdu_get_trusted_input, - 1, // apdu_hash_input_start, - 1, // apdu_hash_sign, - 1, // apdu_hash_input_finalize_full, - 1, // apdu_sign_message, - 0, // apdu_get_firmware_version, - 0, // apdu_get_coin_version -}; - -apduProcessingFunction const DISPATCHER_FUNCTIONS[] = { - apdu_get_wallet_public_key, - apdu_get_trusted_input, - apdu_hash_input_start, - apdu_hash_sign, - apdu_hash_input_finalize_full, - apdu_sign_message, - apdu_get_firmware_version, - apdu_get_coin_version, -}; diff --git a/src/rom_variables.h b/src/rom_variables.h deleted file mode 100644 index 82d5fa89..00000000 --- a/src/rom_variables.h +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef _ROM_VARIABLES_ -#define _ROM_VARIABLES_ - -#include "internal.h" - -#define SIGNMAGIC_LENGTH 17 - -extern unsigned char const SIGNMAGIC[SIGNMAGIC_LENGTH]; - -extern unsigned char const OVERWINTER_PARAM_PREVOUTS[16]; -extern unsigned char const OVERWINTER_PARAM_SEQUENCE[16]; -extern unsigned char const OVERWINTER_PARAM_OUTPUTS[16]; -extern unsigned char const OVERWINTER_PARAM_SIGHASH[16]; -extern unsigned char const OVERWINTER_NO_JOINSPLITS[32]; - -#define HDKEY_VERSION_LENGTH 4 - -#define APDU_DEBUG_LENGTH 0 - -#define APDU_NFCPAYMENT_LENGTH 0 - -#define APDU_BIP70_LENGTH 0 - -#define APDU_MOFN_LENGTH 0 - -#define APDU_KEYCARD_LENGTH 0 - -#define APDU_PORTABLE_LENGTH 5 - -#define APDU_KEYBOARD_LENGTH 0 - -#define APDU_LEGACY_SETUP_LENGTH 0 - -#define APDU_DEVELOPER_MODE_LENGTH 0 - -#define APDU_BASE_LENGTH 13 - -#define DISPATCHER_APDUS 13 - -typedef unsigned short (*apduProcessingFunction)(void); - -extern unsigned char const DISPATCHER_CLA[DISPATCHER_APDUS]; -extern unsigned char const DISPATCHER_INS[DISPATCHER_APDUS]; -extern unsigned char const DISPATCHER_DATA_IN[DISPATCHER_APDUS]; -extern apduProcessingFunction const DISPATCHER_FUNCTIONS[DISPATCHER_APDUS]; - -#endif /* _ROM_VARIABLES_ */ \ No newline at end of file diff --git a/src/swap/handle_get_printable_amount.c b/src/swap/handle_get_printable_amount.c deleted file mode 100644 index 8f9d8fd7..00000000 --- a/src/swap/handle_get_printable_amount.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "handle_get_printable_amount.h" -#include "bcd.h" -#include - -void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { - params->printable_amount[0] = 0; - if (params->amount_length > 8) { - PRINTF("Amount is too big"); - return; - } - unsigned char amount[8]; - memset(amount, 0, 8); - memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); - unsigned char coin_name_length = strlen(COIN_COINID_SHORT); - memmove(params->printable_amount, COIN_COINID_SHORT, coin_name_length); - params->printable_amount[coin_name_length] = ' '; - int res_length = convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, (uint8_t *)params->printable_amount + coin_name_length + 1); - params->printable_amount[res_length + coin_name_length + 1] = '\0'; - - return; -} \ No newline at end of file